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
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.
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.