使用无子查询重写具有两个子查询的查询

时间:2016-10-19 18:44:37

标签: mysql sql

给定数据库架构:

Part( PID, PName, Producer, Year, Price)
Customer( CID, CName, Province)
Supply(SID, PID, CID, Quantity, Amount, Date)

查询:

Select cname, Province
From Customer c
Where exists (
    Select * 
    from Supply s
    join Part p on p.pId = s.pId 
    Where CId = c.CId 
    and p.Producer = 'Apple'
)
and Not exists (
    Select * 
    from Supply n
    join Part nap on nap.pId = n.pId 
    Where CId = c.CId 
    and nap.Producer != 'Apple'
)

如果没有两个子查询,我将如何重写此查询?

2 个答案:

答案 0 :(得分:0)

您想要只购买Apple产品的客户吗?

一种可能的解决方案是基于条件聚合:

Select c.cname, c.Province
From Customer c
join
 ( -- this is not a Subquery, it's a Derived Table
   Select s.CId -- assuming there's a CId in Supply
   from Supply s
   join Part p
     on p.pId = s.pId
   group by s.CId 
   -- when there's any other supplier this will return 1
   having max(case when p.Producer = 'Apple' then 0 else 1 end) = 0
 ) as p
on p.CId = c.CId 

答案 1 :(得分:0)

您可以使用LEFT JOIN/NULL模式查找尚未购买任何非Apple产品的客户。然后你可以通过连接完成所有这些操作。您必须两次加入SupplyParts,一次用于查找Apple产品,然后再次排除非Apple产品。

SELECT distinct c.name, c.province
FROM Customer AS c
JOIN Supply AS s1 ON s1.cid = c.cid
JOIN Parts AS p1 ON p1.pid = s1.pid
LEFT JOIN Supply AS s2 ON s2.cid = c.cid
LEFT JOIN Parts AS p2 ON p2.pid = s2.pid AND p2.producer != 'Apple'
WHERE p1.producer = 'Apple' AND p2.pid IS NULL

请注意,在LEFT JOIN中,您在ON子句中放置了第二个表的限制,而不是WHERE子句。有关此部分查询的详情,请参阅Return row only if value doesn't exist