Sql 如果右侧包含特定的内容,如何从多到多不返回任何内容?

Sql 如果右侧包含特定的内容,如何从多到多不返回任何内容?,sql,postgresql,Sql,Postgresql,我有一个通过ORM映射的多对多。我从左表中选择,并使用2个左外部联接拉入右表 一切正常,但我有一个例子,如果正确的表包含一个特定的值,那么查询应该什么也不返回 下面是一个精心设计的简化示例: people people_fruits fruits id | name people_id | fruit_id id | name --------------------------------------------------- 1 | T

我有一个通过ORM映射的多对多。我从左表中选择,并使用2个左外部联接拉入右表

一切正常,但我有一个例子,如果正确的表包含一个特定的值,那么查询应该什么也不返回

下面是一个精心设计的简化示例:

 people          people_fruits          fruits
id | name     people_id | fruit_id     id | name
---------------------------------------------------
 1 | Tom              1 | 1             1 | apple
 2 | Paul             1 | 2             2 | banana
 3 | Kim              2 | 1             3 | orange
                      2 | 3

给定的查询可能如下所示:

SELECT p.*, f.*
FROM people AS p
         LEFT OUTER JOIN people_fruits AS pf ON pf.people_id = p.id
         LEFT OUTER JOIN fruits AS f ON pf.fruits_id=f.id
WHERE p.id = 1;

相当标准。但假设我想假装与橘子有关的人根本不存在,对不起,橘子迷。我希望以下查询返回一个空集:

SELECT p.*, f.*
FROM people AS p
         LEFT OUTER JOIN people_fruits AS pf ON pf.people_id = p.id
         LEFT OUTER JOIN fruits AS f ON pf.fruits_id=f.id
WHERE p.id = 2; 

此查询应返回一个空集

对Tom和Kim的查询应返回结果,但对Paul的查询不应返回结果


如何编写这样的查询?

一种选择是按个人进行聚合,并声明他从未与橙子关联:

WITH cte AS (
    SELECT p.id
    FROM people AS p
    LEFT JOIN people_fruits AS pf ON pf.people_id = p.id
    LEFT JOIN fruits AS f ON pf.fruits_id = f.id
    GROUP BY p.id
    HAVING COUNT(*) FILTER (WHERE f.name = 'orange') = 0
)

SELECT p.*, f.*
FROM people AS p
LEFT JOIN people_fruits AS pf ON pf.people_id = p.id
LEFT JOIN fruits AS f ON pf.fruits_id = f.id
WHERE p.id IN (SELECT id FROM cte);
您可以使用“不存在”或“不存在”,如下所示。NOT IN必须小心使用,因为它需要同时处理null条件

-- NOT EXISTS --
SELECT p.*, f.*
FROM people AS p
LEFT JOIN people_fruits AS pf ON pf.people_id = p.id
LEFT JOIN fruits AS f ON pf.fruits_id = f.id

-- added this where condition with not exists
WHERE NOT EXISTS (SELECT 1
FROM people_fruits PFIN JOIN fruits FIN
ON PFIN.fruits_id = FIN.id
AND FIN.NAME = 'orange'
and PFIN.people_id = p.id);



-- NOT IN --
SELECT p.*, f.*
FROM people AS p
LEFT JOIN people_fruits AS pf ON pf.people_id = p.id
LEFT JOIN fruits AS f ON pf.fruits_id = f.id

-- added this where condition with not IN
WHERE p.id not in (SELECT PFIN.people_id
FROM people_fruits PFIN JOIN fruits FIN
ON PFIN.fruits_id = FIN.id
AND FIN.NAME = 'orange');

干杯

谢谢你的回答,很有效!我检查另一个答案是否正确,只是因为它比您提供的代码更适合ORM片段。干杯