繁体   English   中英

联接:三个表和一个或条件

[英]Join: three tables and a or condition

我想我应该以某种方式知道这一点,尤其是在阅读了许多有关“条件必须进入ON子句,而不是WHERE子句”的问题和答案之后。 但是,我仍然迷路。

我有三个表,我通常通过LEFT(OUTER)联接将它们联接。 联接的表如下所示(非常标准):

task_id task_questions_taskId   taskQuestions_questionId    question_id
1         1                     5                           5
1         1                     8                           8
2         2                     8                           8
SELECT `t`.`id` AS `task_id` , 
       `task_questions`.`taskId` AS `task_questions_taskId` ,
       `task_questions`.`questionId` AS `task_questions_questionId` , 
       questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions` 
    ON ( `task_questions`.`taskId` = `t`.`id` )
LEFT OUTER JOIN `question` `questions` 
    ON ( `task_questions`.`questionId` = `questions`.`id` )

这是获取所有记录的标准查询。 (它取自Yii;我实际上想通过Active Record做到这一点,但是甚至无法正确使用普通SQL)。

现在,我只想获取那些具有question_id 2和8的任务(例如),因此,如果一个任务没有两个question_id,那么我就不希望它出现在结果集中。 在这种情况下,任务也可以具有其他question_id。 尽管如果查询仅返回恰好具有这2个(或任何其他集合)的查询,将会看到查询的外观,这很有趣。 使用WHEREquestion.id = 2可以很容易地获得所有具有一个问题的任务,但是WHERE子句中的AND导致结果为空。

WHERE子句一次只能将条件应用于一行。 但是,不同ID的问题出现在不同的行上。 如何解决呢? 使用self-join将两行连接为一行。

这是一个例子:

SELECT t.`id` AS `task_id`, ...
FROM `task` AS t
INNER JOIN `task_questions` AS tq2 ON ( tq2.`taskId` = t.`id` )
INNER JOIN `questions` AS q2 ON ( tq2.`questionId` = q2.`id` )
INNER JOIN `task_questions` AS tq8 ON ( tq8.`taskId` = t.`id` )
INNER JOIN `questions` AS q8 ON ( tq8.`questionId` = q8.`id` )
WHERE q2.`id` = 2 AND q8.`id` = 8

另一个解决方案是找到具有问题2 8的任务,然后使用GROUP BY和HAVING按正好具有两个问题的组进行筛选。

SELECT t.`id` AS `task_id`, ...
FROM `task` AS t
INNER JOIN `task_questions` AS tq ON ( tq.`taskId` = t.`id` )
INNER JOIN `questions` AS q ON ( tq.`questionId` = q.`id` )
WHERE tq.`questionId` IN (2, 8)
GROUP BY t.`id`
HAVING COUNT(DISTINCT q.`id`) = 2

您甚至可以在不使用和的情况下执行此操作... where question.id IN(2,8)

使用IN

SELECT `t`.`id` AS `task_id` , 
       `task_questions`.`taskId` AS `task_questions_taskId` ,
       `task_questions`.`questionId` AS `task_questions_questionId` , 
       questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions` 
    ON ( `task_questions`.`taskId` = `t`.`id`)
LEFT OUTER JOIN `question` `questions` 
    ON ( `task_questions`.`questionId` = `questions`.`id` )
WHERE  `task_questions`.`questionId` IN (2, 8)

这应该做

SELECT `t`.`id` AS `task_id` , 
       `task_questions`.`taskId` AS `task_questions_taskId` ,
       `task_questions`.`questionId` AS `task_questions_questionId` , 
       questions.id AS question_id
FROM `task` `t`
LEFT OUTER JOIN `task_questions` `task_questions` 
    ON ( `task_questions`.`taskId` = `t`.`id` )
LEFT OUTER JOIN `question` `questions` 
    ON ( `task_questions`.`questionId` = `questions`.`id` )
WHERE  questions.id in (2,8)

您不是在寻找AND,而是在寻找OR,或者是IN:

WHERE `questions`.`id` IN (2,8) -- grab everything in the parens.

要么

WHERE `questions`.`id` = 2 OR -- grab each item individually
      `questions`.`id` = 8

如果使用AND ,则ID必须同时为8和2。 不好

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM