左联接三个MySQL表而不是

时间:2019-06-10 15:28:56

标签: mysql

在MySQL数据库中,我具有三个连接的表:文本链接到版本,该链接链接到中间表 editor_attestations (我认为第四表编辑器与此处无关)。通常每个文本都有多个版本,而每个版本又通常具有几个editor_attestations(通过联合出版)。

如果我想使用特定的编辑器获取所有文本和版本,则可以正常工作:

SELECT texts.text_id FROM texts
LEFT JOIN editions ON texts.text_id = editions.text_id
LEFT JOIN editor_attestations ON editions.edition_id = editor_attestations.edition_id
WHERE editor_attestations.editor_id = 102

现在,我尝试了几种方法,以使所有文本均未由editor_id = 102编辑,但似乎没有任何作用。

SELECT texts.text_id FROM texts
LEFT JOIN editions ON texts.text_id = editions.text_id
LEFT JOIN editor_attestations ON editions.edition_id = editor_attestations.edition_id
WHERE (editor_attestations.editor_id != 102 or editor_attestations.editor_id is null)

在结果中有许多记录,其中editor_id 102与其他人合作,因此editor_attestations.editor_id!= 102成立。但是我想排除那些。

我只想在表1(文本)中包含与表3(editor_attestations)中的特定值没有任何联系的值。

我尝试对子查询使用NOT IN或NOT EXISTS,但这不起作用。

我觉得它不应该那么复杂...

3 个答案:

答案 0 :(得分:1)

由于只需要texts.text_id,因此可以按texts.text_id分组并在HAVING子句中设置条件。

SELECT texts.text_id 
FROM texts
LEFT JOIN editions ON texts.text_id = editions.text_id
LEFT JOIN editor_attestations ON editions.edition_id = editor_attestations.edition_id
GROUP BY texts.text_id 
HAVING SUM(editor_attestations.editor_id = 102) = 0

答案 1 :(得分:1)

forpas和xavier的答案证明了可行的方法。

作为使用NOT EXISTS

的方法的演示
SELECT t.text_id 
  FROM texts t
 WHERE NOT EXISTS ( SELECT 1 
                      FROM editions e
                      JOIN editor_attestations a 
                        ON a.edition_id = e.edition_id
                     WHERE a.editor_id = 102 
                       AND e.text_id = t.text_id
                  )

请注意子查询e.text_id = t.text_id中的谓词,该谓词将子查询与外部查询相关联。

此方法允许返回texts中的其他列,而不会重复使用JOIN操作可能会发生的行。

对于大型集合,需要合适的索引以实现最佳性能。


另一种替代方法是使用反联接模式:

 SELECT t.text_id 
   FROM texts t
     -- match to editor_id=102
   LEFT
   JOIN ( SELECT e.text_id 
            FROM editions e
            JOIN editor_attestations a
              ON a.edition_id = e.edition_id
           WHERE a.editor_id = 102
           GROUP BY e.text_id
        ) s
     ON s.text_id = t.text_id
     -- exclude rows that had a match
  WHERE s.text_id IS NULL

内联视图查询s为我们提供了与text_id相关的editor_id=102的独特列表。反联接是此查询的返回的左外部联接,因此它将返回所有行文本以及来自s的匹配行。诀窍是WHERE子句中的一个条件,该条件排除具有匹配项的行(如果s中有匹配的行,我们保证s.text_id将为非空,因为只有非空值可以满足联接条件(ON s.text_id =中的相等比较。如果排除那些行,则剩下texts中的行,它们 not 中没有匹配的行s

答案 2 :(得分:0)

一个非常简单的解决方案是:我寻找由某个编辑器修改过的所有文本,然后选择互补的文本集。可能效率不高,但是对于小型数据库而言,它会起作用:

SELECT texts.text_id FROM texts where texts.text_id NOT IN
  (SELECT editions.text_id FROM editions
    JOIN editor_attestations ON editions.edition_id = editor_attestations.edition_id
    WHERE editor_attestations.editor_id = 102
  )