来自同一个表的MySQL子查询

时间:2015-01-07 15:46:13

标签: mysql

我有一个包含表xxx_facileforms_forms,xxx_facileforms_records和xxx_facileforms_subrecords的数据库。

xxx_facileforms_subrecords的列标题:

id | record | element | title | neame | type | value

使用element =' 101'过滤记录。 ..query返回正确的记录,但是当我将子查询添加到filete aditional element =' 4871'来自同一张表 - 返回了0条记录。

SELECT
F.id AS form_id,
R.id AS record_id,
PV.value AS prim_val,
COUNT(PV.value) AS count
FROM
xxx_facileforms_forms AS F
INNER JOIN xxx_facileforms_records AS R ON F.id = R.form
INNER JOIN xxx_facileforms_subrecords AS PV ON R.id = PV.record AND PV.element = '101'
WHERE R.id IN (SELECT record FROM xxx_facileforms_records WHERE record = R.id AND element = '4871')
GROUP BY PV.value

这看起来不错吗?

谢谢!

修改

感谢您的支持和想法!是的,我留下了许多猜测。抱歉。某些输入/输出表数据可能有助于使其更清晰。

_facileforms_form:
id | formname
---+---------
1  | myform

_facileforms_records:
id  | form | submitted
----+------+--------------------
163 | 1    | 2014-06-12 14:18:00
164 | 1    | 2014-06-12 14:19:00
165 | 1    | 2014-06-12 14:20:00

_facileforms_subrecords:
id   | record | element | title  | name|type   | value
-----+--------+---------+--------+-------------+--------
5821 | 163    | 101     | ticket | radio group | flight
5822 | 163    | 4871    | status | select list | canceled
5823 | 164    | 101     | ticket | radio group | flight
5824 | 165    | 101     | ticket | radio group | flight
5825 | 165    | 4871    | status | select list | canceled

成功的查询结果:

form_id | record_id | prim_val |  count
1       | 163       | flight   | 2

所以我必须从那些存在_subrecord元素 - 4871的记录(在这种情况下为163和165)返回值数据(并对这些记录求和)。

再次谢谢你!

2 个答案:

答案 0 :(得分:0)

不,看起来不太对劲。有一个谓词“ R.id IN (subquery) ”,但该子查询本身引用了 R.id ;它是一个相关的子查询。看起来有些东西加倍了。 (我们假设 id 是每个表中的唯一或主要键。)

子查询引用标识符element ...我们看到该标识符的唯一其他引用来自_subrecords表(我们在_records中看不到对该列的任何引用} table ...如果element中没有_records列,那么这是对elementPV列的引用,并且子查询中的谓词永远不会为true同时PV.element='101'谓词为真。

使用表别名限定列引用的荣誉,这使得查询(和EXPLAIN输出)更容易阅读;读者不需要在表定义中进行挖掘,以确定哪个表包含哪些表,哪些表包含哪些列。但请将该模式用于下一步,并在查询中限定所有列引用,包括子查询中的列引用。

由于对element的引用不合格,我们只能猜测_records表是否包含名为element的列。


如果目标是仅使用Relement='4871'返回行,我们就可以...

WHERE R.element='4871'

但是,鉴于你已经厌倦了使用子查询,我怀疑这不是你想要的。

您可能尝试从R返回_form的所有行,但仅针对_form,其中至少有一个关联的_record element='4871' 即可。我们可以使用 IN (subquery) EXISTS (correlated_ subquery) 谓词或 anti-join 模式。我将举例说明这些查询模式;我可以对规范做一些猜测,但我只会猜测你真正希望返回的内容。

但我猜这不是你想要的。我怀疑_records实际上并不包含名为element的列。

该查询已经限制从PV返回的行与element='101'的行。)

这是一些示例数据和示例输出有助于解释实际规范的情况;这将是开发所需SQL的基础。

<强>后续

我只是猜测......也许你想要的东西很简单。也许你想要返回元素值为'101'或'4913'的行。

IN比较运算符可以方便地表达OR条件,即列等于列表中的值:

SELECT F.id              AS form_id
     , R.id              AS record_id
     , PV.value          AS prim_val
     , COUNT(PV.value)   AS count
  FROM xxx_facileforms_forms F
  JOIN xxx_facileforms_records R 
    ON R.form = F.id
  JOIN xxx_facileforms_subrecords PV 
    ON PV.record = R.id
   AND PV.element IN ('101','4193')
 GROUP BY PV.value

注意:此查询(如OP查询)使用GROUP BY的非标准MySQL扩展,它允许在SELECT列表中返回非聚合表达式(例如裸列)。

非聚合表达式(在本例中为F.idR.id)返回的值将是“组”中包含的行中的值。但是因为这些行可能有多行和不同的值,所以返回哪个值不确定。 (其他数据库会拒绝此语句,除非我们将这些列包装在聚合函数中,例如MIN()或MAX()。)


<强>后续

我注意到你在答案中添加了有关问题的信息......这些信息最好添加作为编辑问题,因为它不是答案问题。我冒昧地复制那个,并重新格式化。

这个例子让你更加清楚你想要完成什么。

我认为最容易理解是使用EXISTS谓词,检查符合某些条件的行是否“存在”,并排除不存在这样的行的行。这将使用_subrecords表的相关子查询,检查是否存在匹配的行:

SELECT f.id              AS form_id
     , r.id              AS record_id
     , pv.value          AS prim_val
     , COUNT(pv.value)   AS count
  FROM xxx_facileforms_forms f
  JOIN xxx_facileforms_records r 
    ON r.form = f.id
  JOIN xxx_facileforms_subrecords pv
    ON pv.record = r.id
   AND pv.element = '101'
-- only include rows where there's also a related 4193 subrecord
 WHERE EXISTS ( SELECT 1
                  FROM xxx_facileforms_subrecords sx
                  WHERE sx.element = '4193'
                    AND sx.record = r.id
              )
--
 GROUP BY pv.value

(我认为OP就是需要子查询的想法。)

鉴于查询中存在GROUP BY,我们实际上可以使用常规连接操作完成等效结果,以及对_subrecords表的第二次引用。

连接操作通常比使用EXISTS谓词更有效。

(请注意,现有的GROUP BY子句将消除JOIN操作可能引入的任何“重复”,因此这将返回相同的结果。)

SELECT f.id              AS form_id
     , r.id              AS record_id
     , pv.value          AS prim_val
     , COUNT(pv.value)   AS count
  FROM xxx_facileforms_forms f
  JOIN xxx_facileforms_records r
    ON r.form = f.id
  JOIN xxx_facileforms_subrecords pv
    ON pv.record = r.id
   AND pv.element = '101'
-- only include rows where there's also a related 4193 subrecord
  JOIN xxx_facileforms_subrecords sx
    ON sx.record = r.id
   AND sx.element = '4193'
--
 GROUP BY pv.value

答案 1 :(得分:0)

感谢您的支持和想法!是的,我留下了很多猜测..抱歉。因此,某些输入/输出表数据可能会有所帮助。

<强> _facileforms_form:

标题 - &gt; id |表格名称

1 | myForm会

<强> _facileforms_records:

标题 - &gt; id |形式|提交

163 | 1 | 2014-06-12 14:18:00

164 | 1 | 2014-06-12 14:19:00

165 | 1 | 2014-06-12 14:20:00

<强> _facileforms_subrecords

标题 - &gt; id |记录|元素|标题|名字|类型|值

5821 | 163 | 101 |票|广播组|飞行

5822 | 163 | 4871 |状态|选择列表|取消

5823 | 164 | 101 |票|广播组|飞行

5824 | 165 | 101 |票|广播组|飞行

5825 | 165 | 4871 |状态|选择列表|取消


成功查询结果:

标题 - &gt; form_id | record_id | prim_val |计数

1 | 163 |航班| 2

所以我必须从那些存在_subrecord元素 - 4871的记录(在这种情况下为163和165)返回值数据(并对这些记录求和)。

再次谢谢你!