编写此SQL查询的更好方法是什么?

时间:2015-10-01 05:46:18

标签: mysql sql database

我有以下关系。

Suppliers( sid: integer, sname: string, address: string)
Parts(pid: integer, pname: string, color: string)
Catalog( sid: integer, pid: integer, cost: real)

问题要求我找到Acme Widget Suppliers提供的部件的名称而不是其他人。我写了以下SQL语句;但是我觉得这个查询由于重复而效率低下。我想知道是否有更好的方法来编写此查询而不重复选择目录部分。

Select P.pname 
FROM Parts P 
WHERE P.pid IN (
    Select C.pid 
    FROM Catalog C 
    INNER JOIN Supplier S
    ON S.sid = C.sid 
    WHERE S.sname = "Acme Widget Suppliers" 
    AND C.pid NOT IN (
            SELECT C2.pid 
            FROM Catalog C2
            INNER JOIN Supplier S
            ON S.sid = C2.sid 
            WHERE S.sname <> "Acme Widget Suppliers"
        )
);

7 个答案:

答案 0 :(得分:2)

我在第二部分使用left join,因为我希望得到nulls。在这种情况下,acme只有一行而没有其他人

<强> Sql Fiddle Demo

Select *
FROM Parts P 
INNER JOIN Catalog C1
   ON P.pid = C1.pid
INNER JOIN Suppliers S1
   ON C1.sid = S1.sid
LEFT JOIN Catalog C2
   ON P.pid = C2.pid
  AND C1.sid <> C2.sid
WHERE 
   S1.sname = 'Acme' 
AND C2.sid IS NULL

答案 1 :(得分:2)

正确的查询是:

Select P.PName from Suppliers S1 
 join Catalog C1
  on S1.sid = C1.sid
  join parts P
   on P.pid = C1.pid
where  S1.sname = 'Acme Widget Suppliers'
 and not exists 
 ( select  1 from catalog C2 where C2.sid != C1.sid 
   and C2.pid = C1.pid)

不存在是非常有效的,因为它在找到第一次出现时停止搜索。

SQL Fiddle

答案 2 :(得分:1)

我会尝试将三个表连接在一起,然后使用您已使用的WHERE子句进行限制。我在DISTINCT语句中使用SELECT来确保重复项被删除,如果它们发生的话。

SELECT DISTINCT p.pname
FROM  Parts p INNER JOIN Catalog c
ON p.pid = c.pid
INNER JOIN Suppliers s
ON c.sid = s.sid
WHERE s.sname = "Acme Widget Suppliers"

答案 3 :(得分:1)

这可行:

select p.pname from Catalog c
join Parts p on p.pid = c.pid
join Suppliers s on s.sid = c.sid
where s.sname = 'Acme Widget Suppliers'
and p.pid in (select pid as SupplierCount from Catalog c
              group by pid having count(*) = 1)

内部select旨在查找任何供应商的独家部分。如果某个零件由多个供应商销售,则不会包含该零件。

工作示例:http://sqlfiddle.com/#!6/1ccde/10

答案 4 :(得分:1)

提供另一种方法来解决这个问题,这是一种使用数据分组的变体。这是一个选择由“Acme Widget Suppliers”提供的所有 pnames 的解决方案

Select P.pname 
FROM Parts P 
INNER JOIN Catalog C on c.pid=p.pid
INNER JOIN Supplier S  ON S.sid = C.sid 
GROUP BY p.pname 
HAVING min(s.sname)=max(s.sname) 
   and max(s.name)='Acme Widget Suppliers'

按照pname选择组,并计算供应商名称的 min max 。如果有一个零件的不同供应商 min max 不相等。

据我所知,问题中的细微差别(部分由'Acme'提供或部分由'Acme'提供而且没有其他人)仍然不清楚,我会坚持以后更难选择;)。

答案 5 :(得分:0)

你是对的。您想要进行的查询可以大大简化。请尝试以下方法。

SELECT P.pname FROM Parts P, Suppliers S, Catalog C
WHERE C.pid = P.pid
AND C.sid = S.sid
AND S.sname == "Acme Widget Suppliers"

答案 6 :(得分:0)

根据您的查询,似乎不是不需要exists语句比in更好并且加入。

Select P.pname 
FROM Parts P 
WHERE EXISTS (
    Select C.pid 
    FROM Catalog C 
    INNER JOIN Supplier S
    ON S.sid = C.sid 
    WHERE P.pid = C.pid  AND  S.sname = "Acme Widget Suppliers" 
);