MySQL问题与组合的SELECT语句

时间:2014-09-11 02:32:29

标签: php mysql sql

我有两个主要的SELECT语句,它们在单独运行时返回所需的结果,但在组合时,不会返回所需的结果。

查询1

这样可以正常工作,返回预期结果。

SELECT feed_mode_id FROM user WHERE id=2;
+--------------+
| feed_mode_id |
+--------------+
|            1 |
+--------------+

查询2

这也没关系。有时结果会是空的,有时不会。

SELECT
        answer.id AS answer_id
    FROM
        answer
    WHERE
        answer.question_id = (
            SELECT
                question.id
            FROM
                question
            ORDER BY
                datetime_added_utc DESC
            LIMIT 1
        )
        AND answer.user_id = 2;

Empty set (0.00 sec)

查询1和2合并

当将这些语句组合成两个子SELECT语句时,feed_mode_idNULL,但x.feed_mode_id的结果应如查询1所示。这是我缺乏的了解这些合并的陈述是如何运作的。

SELECT
    x.feed_mode_id,
    IF (COUNT(y.answer_id) < 1, 0, 1) AS answered_question
FROM
    (SELECT
        user.feed_mode_id
    FROM
        user
    WHERE
        user.id = 2) AS x,
    (SELECT
        answer.id AS answer_id
    FROM
        answer
    WHERE
        answer.question_id = (
            SELECT
                question.id
            FROM
                question
            ORDER BY
                datetime_added_utc DESC
            LIMIT 1
        )
        AND answer.user_id = 2) AS y

+--------------+-------------------+
| feed_mode_id | answered_question |
+--------------+-------------------+
|         NULL |                 0 |
+--------------+-------------------+

为什么feed_mode_id生成NULL而非1?我也愿意采用不同的方法重新编写查询。期望的结果是:

+--------------+-------------------+
| feed_mode_id | answered_question |
+--------------+-------------------+
|            1 |                 0 |
+--------------+-------------------+

这与某种情况有关,即查询2的结果在这种情况下为空。对于查询2返回值(非空)的情况,组合查询将按预期工作。

3 个答案:

答案 0 :(得分:1)

您在xy之间有笛卡尔积。只要每个行源只返回一行,查询就会返回一行。

我建议您放弃连接操作的旧式逗号语法,而是使用JOIN关键字。

此外,还不清楚为什么你需要内联视图和子查询,除了返回&#34;最近添加&#34;的子查询。问题

我并不完全清楚你实际上想要返回什么结果集,但看起来你正在确定一个特定的用户(由&#34; id&#34;列唯一标识&#34; ; user&#34; table),提供了一个&#34;答案&#34;到了最近添加的问题&#34;。

如果这是您尝试返回的结果,我相信此查询将返回该结果:

SELECT u.feed_mode_id
     , IF( COUNT(a.id) < 1, 0, 1) AS answered_question
  FROM ( SELECT q.id
           FROM question q
          ORDER BY q.datetime_added_utc DESC, q.id DESC
          LIMIT 1
       ) r
  JOIN user u
    ON u.id = 2
  LEFT
  JOIN answer a
    ON a.user_id = u.id
   AND a.question_id = r.id
 GROUP BY u.id

注意:内嵌视图别名为r会返回&#34; {34}最近添加的&#34;} id。 (在原始查询中,如果两个或多个问题具有相同的question,则不确定将返回哪一行。此查询通过向ORDER BY子句添加另一个表达式来确定它。(内联查看查询可以被拉出并单独运行,以验证它是否返回了预期的结果。)

然后将从datetime_added_utc返回的行(如果有的话)连接到从&#34;用户&#34;中检索到的行。表格1}}。我们在此假设&#34;用户&#34;中的r列。 table是唯一标识符,可能是&#34; user&#34;的主键。表

如果我们有一个&#34;最近添加的&#34;问题(即来自u的一行),并且来自&#34;用户&#34;与id子句中的r谓词匹配,到目前为止,我们保证查询将返回单行。

接下来,我们执行&#34;外部联接&#34;操作,从&#34;回答&#34;找到匹配的行表。 u.id=2子句中的谓词将返回的行限制为仅ONON user_id匹配的行(在此示例中,相当于指定id },u与&#34的a.user_id=2匹配;最近添加的&#34;问题question_id

id关键字将此标识为&#34;外部联接&#34 ;;如果&#34;答案&#34;没有匹配的行表,然后查询仍将返回rLEFT的行。 (如果这是一个内部联接,也就是说,如果我们删除了r关键字,那么如果&#34; answer&#34;表中没有匹配的行,那么查询将不会返回一行。 )

我们添加u子句,以防我们从LEFT获得多个匹配行; GROUP BY u.id会将具有相同u.id值的所有行折叠为一行。

answer汇总从&#34;答案&#34;计算GROUP BY的非空出现次数。表。如果找不到匹配的行,则a.id将为NULL,因此COUNT(a.id)将返回0.


如果我们要查找多用户,如果我们为user.id指定了多个值来匹配,那么同样的查询也会有效。

COUNT()

或者如果我们完全离开该谓词,那么我们为每个用户排了一行。此查询仍然有效。

但是在其中任何一种情况下,我们还想将id添加到查询的SELECT列表中,这样我们就知道哪一行是针对哪个用户的。

如果我们想要返回两个最近添加的问题,我们可以更改 ON u.id IN (2,3,5,7) 中的LIMIT子句,然后将u.id AS user_id添加到r条款。同样,我们可能还想在SELECT列表中返回r.id,因此我们知道哪一行是针对哪个问题。

答案 1 :(得分:0)

完全查询

SELECT
    x.feed_mode_id,
    IF (COUNT(y.answer_id) < 1, 0, 1) AS answered_question
FROM
    (SELECT
        user.feed_mode_id
    FROM
        user
    WHERE
        user.id = 2) AS x,
    (SELECT
        answer.id AS answer_id
    FROM
        answer
    WHERE
        answer.question_id IN (
            SELECT
                question.id
            FROM
                question
            ORDER BY
                datetime_added_utc DESC
            LIMIT 1
        )
        AND answer.user_id = 2) AS y
  

answer.question_id =回答.question_id IN

答案 2 :(得分:0)

我不想回答我自己的问题,但我找到了一个有效的解决方案。我已将IF语句移动到子SELECT而不是主SELECT。我不知道为什么这样做,以前的尝试没有,但它现在产生了预期的结果。

SELECT
    x.feed_mode_id,
    y.question_answered 
FROM
    (SELECT
        user.feed_mode_id
    FROM
        user
    WHERE
        user.id = 2) AS x,
    (SELECT
        IF (COUNT(answer.id < 1), 1, 0) AS question_answered 
    FROM
        answer
    WHERE
        answer.question_id = (
            SELECT
                question.id
            FROM
                question
            ORDER BY
                datetime_added_utc DESC
            LIMIT 1
        )
        AND answer.user_id = 2) AS y;

+--------------+-------------------+
| feed_mode_id | question_answered |
+--------------+-------------------+
|            1 |                 0 |
+--------------+-------------------+