PostgreSQL 搜索条件必须输出缺失的行

Posted

技术标签:

【中文标题】PostgreSQL 搜索条件必须输出缺失的行【英文标题】:PostgreSQL search criteria must output missing row 【发布时间】:2017-04-03 07:24:53 【问题描述】:

我有两个 postgreSQL 表,即:employeesemployee_cars。 我需要输出拥有“BMW”、“MERC”和“VW”但不拥有“AUDI”的所有员工。

我尝试过以下查询:

SELECT DISTINCT a.employee_name, b.car_brand
FROM employees a
LEFT JOIN employee_cars b 
ON a.employee_id = b.employee_id
WHERE b.car_brand IN ('BMW','MERC','VW')
AND b.car_brand NOT LIKE 'AUDI';

输出如下:

employee_name,car_brand
"Mary","BMW"
"Mary","MERC"
"Mary","VW"
"Paul","BMW"
"Paul","MERC"
"Paul","VW"

问题是员工拥有的每辆车都是employee_cars 表中的一行。例如,例如;我有“玛丽”,它拥有:“宝马”、“MERC”、“大众”、“奥迪”。 我有“保罗”,它只拥有:“宝马”、“MERC”、“大众”。 我的查询将显示 Mary 和 Paul,因为他们都拥有“BMW”、“MERC”、“VW”。

我只想在结果中看到“Paul”,因为他缺少“AUDI”。

请注意,我不是数据库专家,我将不胜感激任何帮助和帮助。 提前致谢。

【问题讨论】:

哦,我明白了。 “BMW”、“MERC”AND“VW”实际上是指“BMW”、“MERC”“VW”,对吗? @Laurenz Albe,没有一点复杂:'BMW', 'MERC' AND 'VW' AND NOT 'AUDI' 【参考方案1】:

我需要输出拥有“BMW”、“MERC”和“VW”但不是“AUDI”的所有员工。如果您需要区分员工,而不是员工 + 汽车品牌对,您可以通过聚合来做到这一点:

SELECT   e.employee_name, string_agg(c.car_brand, ', ')
FROM     employees e
JOIN     employee_cars c ON e.employee_id = c.employee_id
GROUP BY e.employee_id
HAVING   COUNT(1) FILTER (WHERE c.car_brand IN ('BMW', 'MERC', 'VW')) = 3
AND      COUNT(1) FILTER (WHERE c.car_brand = 'AUDI') = 0

这还将过滤掉既没有“BMW”、“MERC”“VW”的员工(如您的问题所建议的那样)。

http://rextester.com/MQL14836

编辑:对于旧 PostgreSQL 版本,使用 CASE 表达式而不是 FILTERing:

SELECT   e.employee_name, string_agg(c.car_brand, ', ')
FROM     employees e
JOIN     employee_cars c ON e.employee_id = c.employee_id
GROUP BY e.employee_id
HAVING   COUNT(CASE WHEN c.car_brand IN ('BMW', 'MERC', 'VW') THEN 1 END) = 3
AND      COUNT(CASE WHEN c.car_brand = 'AUDI' THEN 1 END) = 0

http://rextester.com/KHMW56692

【讨论】:

我相信这个解决方案会起作用,但是我遇到了过滤计数的问题。我有 PG 版本 9.2。 @JP_CNTLM_ADMIN 你可以使用COUNT(CASE ...)。我会尽快更新我的答案。 谢谢!像魅力一样工作......您先生,是一个传奇!【参考方案2】:

将此与not exists 条件结合起来:

SELECT distinct emp.employee_name, ec.car_brand
FROM employees emp
  JOIN employee_cars ec ON emp.employee_id = ec.employee_id
WHERE ec.car_brand IN ('BMW','MERC','VW')
  and not exists (select *
                  from employee_cars ec2
                  where ec2.car_brand = 'AUDI'
                    and ec2.employee_id = emp.employee_id);

请注意,您不需要在 employees 和 employee_cars 之间进行外部连接

【讨论】:

嗨@a_horse_with_no_name,感谢您的反馈。你的建议很有效。问题在于 My 和您的 IN 语句,即使员工仅拥有一辆车,查询也会返回结果,例如“John”仅拥有“BMW”。我需要结果只输出拥有所有 3 'BMW'、'MERC'、'VW' 而不是“AUDI”的员工。

以上是关于PostgreSQL 搜索条件必须输出缺失的行的主要内容,如果未能解决你的问题,请参考以下文章

在python中删除带有条件的行

PostgreSQL删除数据

删除同一列或连续行的另一列中具有特定值和缺失值的行

更新PostgreSQL数据

在 PostgreSQL 中按多个内连接的条件计数

如何加快计算 PostgreSQL 表中的行数?