简体   繁体   中英

What is a better way to write this SQL query?

I have the following relations.

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

The problem asks me to find the pnames of parts supplied by Acme Widget Suppliers and no one else. I wrote the following SQL statement; however I feel like this query is inefficient because of the repetition. I would like to know if there is a better way to write this query without repeating the selecting catalog part.

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"
        )
);

I use left join on the second part because I expect get nulls . In that case only one row for acme and no one else

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

The correct query would be:

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)

The not exist is very efficient as it stops to search when it finds the first occurence.

SQL Fiddle

I would just try joining together the three tables, then restricting with the WHERE clause you already were using. I used DISTINCT in the SELECT statement to ensure that duplicates get taken out, should they occur.

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"

This can work:

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)

The inner select is meant to find exclusive parts from any supplier. If a part is sold by multiple providers, it will not be included.

Working example: http://sqlfiddle.com/#!6/1ccde/10

To provide another way to tackle this one here a variant using grouping of data. It is a solution to select all pnames that were provided by and only by 'Acme Widget Suppliers'

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'

The select groups by pname and calculates the min and max of suppliers name. If there are different suppliers of one part min and max are not equal.

As I understand the nuance within the question (Part provided by 'Acme' or Part provided by 'Acme' and no one else) is still not clear, I will stick to the later and more difficult selection ;).

You are correct. The query you want to make can be greatly simplified. Try the following.

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"

As per your query, seems to be not in not required also exists statement is much better than in and join.

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" 
);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM