Find the sids of the suppliers who supply every part
This is a double nested NOT EXISTS
query (no really, that's what I've usually seen it called), and it is used specificially to answer this type of quesion, i.e., "Are there any x true for all y?"
Here's MySQL's page on EXISTS and NOT EXISTS, which mentions this technique specifically.
First, in the innermost SELECT
query, you are selecting parts that each store carries. Then, with the first NOT EXISTS
clause, you are selecting parts that are NOT carried by each store. Finally, in the outer NOT EXISTS
clause, you are selecting stores that returned an empty set for the inner NOT EXISTS
clause, meaning they carry every part.
Here is a SQLFiddle of this query in action.
A word of warning: if you are working with SQL, it is always good to think and work in sets, and thinking in linear terms like what is about to follow can get you into trouble quickly. Don't make it a habit!
However, sometimes when trying to figure out a complex query like this, it can help to think of these things as loops.
So, taking the data in the fiddle as an example, we have:
suppliers:
sid, name
9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
1,1,9
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
So with this data, AAA carries wood and stone, BBB only carries wood, and CCC carries wood, stone, and paper.
Now let's step through the query row by row. We are selecting from suppliers
, and we are deciding which rows to include in the result set, so start with the first row in suppliers
: 9,'AAA'
. We'll call this row S
temporarily. We'll only include this row if there is nothing in the inner result set, so lets take a look at that.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
This result set is selecting from parts
, and we are going to go through it row by row. S
still equals 9,'AAA'
while we do this. So start with the first row in parts
: 1,'wood'
. We'll call this row P
for now. We'll only include this row in this first inner result set if there is nothing in the next level of result set, so let's move there. Remember that S
= 9,'AAA'
and P
= 1,'wood'
.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
P => 1, 'wood'
2, 'stone'
3, 'paper'
This innermost query is selecting from 'catalog'. We're looking for any row, we'll call it C
, in catalog
where C.sid
equals S.sid
AND C.pid
equals P.pid
. This means that the current supplier carries the part. We want parts that the current supplier DOESN'T carry, that's why we invert the result set. We know that S
's sid is 9, and we know that P
's pid is 1. Are there any rows in C
that match that? The very first row in C
matches that, so we know that this result set is not empty.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
P => 1, 'wood'
2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
C => 1,1,9 --Match found! Don't include P in outer result set
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
Now jump back to the next outermost loop. The inner result set was not empty, so we know that 1,'wood
will not be part of this loop's result set. So we move to the next row in parts
, 2,'stone'
. We update the value of P
to equal this row. Should we include this row in the result set? We have to run the inner query again with our new value for P
(S
has still not changed). So we look for any rows in catalog
with sid
equal to 9 and pid
equal to 2. The second row matches, so there is a result set.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
P => 2, 'stone'
3, 'paper'
catalog:
cid, pid, sid
1,1,9
C => 2,2,9 --Match found! Don't include P in outer result set
3,1,8
4,1,7
5,2,7
6,3,7
Jump back to the next outermost loop. The inner result set was not empty, so 2,'stone'
will not be part of this loop's result set.
When we go through all this again for 3,'paper'
, we find that there are no rows in catalog
that have sid = 9
and pid = 3
. The innermost result set is empty, so we know to include this value of P
in the next outermost loop.
suppliers:
sid, name
S => 9, 'AAA'
8, 'BBB'
7, 'CCC'
parts:
pid, name
1, 'wood'
2, 'stone'
P => 3, 'paper'
catalog:
cid, pid, sid
1,1,9
2,2,9
3,1,8
4,1,7
5,2,7
6,3,7
C => --No match found, include P in outer result set
We have gone through the entire parts
table at this point, so we have our final result set for the second loop, and it is not empty, which means that we found a part that S
does not carry, so we know that we cannot include the current value of S
in our final outer loop's result set.
So we move on to the next row in suppliers
and start the whole process over:
suppliers:
sid, name
9, 'AAA'
S => 8, 'BBB'
7, 'CCC'
Once we get to S = 7,'CCC'
we will go through all of these loops, and a match will be found in the inner loop for every value of P that is supplied, which means that that second loop will have an empty set. We couldn't find any parts that supplier doesn't carry, so that value of S
is added to the result set, meaning they carry everything!
Find the sids of suppliers who supply only red parts
You do want aggregation. One method is to compare the colors using min()
and max()
:
select c.SID
from cat c JOIN
part p
ON c.PID = p.PID
group by c.SID
having min(p.color) = max(p.color) and -- all colors are the same
min(p.color) = 'red' -- and that color is 'red'
find the sids of suppliers who charge more for some part than the average cost of that part (averaged over all the suppliers who supply that part)
You could turn your subquery into a JOIN
, so that its result is available in the outer query :
SELECT c.sid, c.pid, c.cost, c1.avg_cost
FROM catalog AS c
INNER JOIN (SELECT pid, avg(cost) AS avg_cost FROM catalog GROUP BY pid) c1
ON c1.pid = c.pid
WHERE c.cost > c1.avg_cost
PS : in your original query, you did not need a GROUP BY
since, you did not use aggregate functions in the outer query. Also, based on your data it seems likely that you do not need the DISTINCT
functionality.
Find the names of the suppliers who supply all the parts in MS Access
You need a CROSS
join of Suppliers
and Parts
and a LEFT
join to SPB
.
Then you group by supplier and set the condition in the HAVING clause:
SELECT t.supplierID, t.name
FROM (
SELECT s.ID AS supplierID, s.name, p.Id AS part_ID
FROM Suppliers AS s, Parts AS p
) AS t LEFT JOIN SPB AS b ON b.Supplier = t.supplierID AND b.Part = t.part_ID
GROUP BY t.supplierID, t.name
HAVING COUNT(*) = COUNT(b.Part)
Sids of supplier who supply some particular part using Nested Queries
Just figured it out :)
select sid from Suppliers where address='221 Packer Ave' or sid IN (select sid from _Catalog where pid IN(select pid from Parts where color = 'Red'));
Find the sids of suppliers who supply a red part AND a green part
You must group by cat.sid
and put the condition in the HAVING
clause:
select
c.sid,
min(p.color) color1 ,
max(p.color) color2
from cat c inner join par p
on c.pid = p.pid
where p.color in ('green', 'red')
group by c.sid
having count(distinct p.color) = 2
After selecting only parts with the 2 colors, there will be only suppliers who supply 1 or both colors.
The condition having count(distinct p.color) = 2
returns only the suppliers who supply both colors. min()
and max()
return the 2 colors. They are not really needed in this case but I preferred to use them instead of hardcoding them.
Find the Supplier number for those suppliers who supply every part
You're close. You need to add a group by/having clause with a subquery:
group by s.sname having count(*) = (select count(*) from catalogue)
How to find the Supplier number for those suppliers who supply all parts that are supplied by another by supplier in SQL?
this is how I achieved the result:
create table MyTable (
Supplier varchar(20),
Part varchar(20),
SomeOrder int
)
insert into MyTable values
('S1', 'P1', 100),
('S1', 'P2', 200),
('S2', 'P1', 300),
('S2', 'P2', 100),
('S3', 'P1', 400),
('S4', 'P1', 100),
('S4', 'P2', 200)
---------------------------
-- temporary table to store all parts of a supplier
CREATE TABLE #tmp (Part varchar(20))
-- put your desired provider here
declare @Supplier varchar(20) = 'S2'
-- select all parts of this supplier
insert into #tmp
select Part from MyTable where Supplier = @Supplier
-- count how many parts this supplier has
declare @partCount int
select @partCount = count(*) from #tmp
-- select all suppliers that have all the parts (i.e. count = @partCount)
select innerTbl.Supplier from (
select m.Supplier, m.Part
from MyTable m
inner join #tmp t on t.Part = M.Part
) innerTbl
group by innerTbl.Supplier
having Count(innerTbl.Supplier) = @partCount
and innerTbl.Supplier <> @Supplier
DB2 SQL Find the Id of Suppliers, who supply specific color
You're doing a join already - an implicit, comma separated one.
Tip of today: Always use modern, explicit JOIN
syntax. Easier to write (without errors), easier to read and maintain, and easier to convert to outer join if needed!
select p.id, s.suppliers, s.color
from suppliers s
JOIN parts p ON s.num = p.num
where s.color IN ('blue', 'red')
Also use table aliases (s
, p
), and qualify the columns, e.g. s.num
.
JOIN-free version:
select *
from
(
select p.id,
(select s.suppliers from suppliers s where s.num = p.num) suppliers,
(select s.color from suppliers s where s.num = p.num) color
from parts p
) dt
where color in ('blue', 'red');
Related Topics
Order by Column1 If Column1 Is Not Null, Otherwise Order by Column2
How to Remove The Default Value from a Column in Oracle
Sql Two Tables and Creating a Link Table
Creating Groups of Consecutive Days Meeting a Given Criteria
Why Can't I Reorder My SQL Server Columns
Failed to Create an Assembly in Sql
How to Get Rightmost 10 Places of a String in Oracle
How to Set a Default Value for One Column in SQL Based on Another Column
How to Override SQL Sanitization in Coldfusion
How to List All Stored Procedures in Informix
How to Select The First 100 Characters in SQL Server
Insufficient Privileges When Creating Tables in Oracle SQL Developer
How to Create Trigger to Keep Track of Last Changed Data
Sql Server Stored Procedure and Execute in VB.NET
Sql Server Get The Full Month Name from a Date
Sql Server Row Date Last Modified
Data Type Equivalents: Ms Access Tables ↔ 'Create Table' Queries ↔ Odbc Sql