Reputation: 43
I have two tables:
P
and PC
(master/detail joined by the column Id)
Table P:
Id integer
Name varchar(12)
Table PC:
Id integer
Code varchar(12)
Val number
I want to get all Names from P that satisfy the following simultaneous conditions:
have a PC with PC.Code='A'
and Val>100
have another PC with PC.Code='B'
and Val>80
In summary, I'm only interested in those P.Name where the details comply with both conditions. Is there a way to select without resorting to INTERSECT?
The INTERSECT query is:
Select P.Name
from P, PC
where P.Id=PC.Id
and PC.Code='A' and Val>100
INTERSECT
Select P.Name
from P, PC
where P.Id=PC.Id
and PC.Code='B' and Val>80
(The interest is to check performance and also to allow the query to be run in Access)
Upvotes: 4
Views: 7273
Reputation: 57023
Here is an alternative approach that is relationally equivalent (i.e. eliminating duplicate rows):
SELECT P.Name
FROM P
WHERE EXISTS (
SELECT *
FROM PC
WHERE P.Id = PC.Id
AND PC.Code ='A'
AND PC.Val > 100
)
AND EXISTS (
SELECT *
FROM PC
WHERE P.Id = PC.Id
AND PC.Code ='B'
AND PC.Val > 80
);
Here are a couple of alternatives that are semantically equivalent (in that they may return duplicate rows):
SELECT P.Name
FROM P, PC
WHERE P.Id = PC.Id
AND PC.Code ='A'
AND PC.Val > 100
AND P.Name IN (
SELECT P1.Name
FROM P AS P1, PC AS PC1
WHERE P1.Id = PC1.Id
AND PC1.Code = 'B'
AND PC1.Val > 80
);
SELECT P.Name
FROM P, PC
WHERE P.Id = PC.Id
AND PC.Code ='A'
AND PC.Val > 100
AND P.Name = ANY (
SELECT P1.Name
FROM P AS P1, PC AS PC1
WHERE P1.Id = PC1.Id
AND PC1.Code = 'B'
AND PC1.Val > 80
);
Upvotes: 1
Reputation: 453298
Wouldn't actually use this but an alternative...
SELECT P.Name
FROM P
JOIN PC
ON P.Id = PC.Id
WHERE PC.Cod IN ( 'A', 'B' )
AND Val > 80
GROUP BY P.Id,
P.Name
HAVING MAX(CASE WHEN PC.Cod='A' and Val>100 THEN 1 END) = 1
AND MAX(CASE WHEN PC.Cod='B' and Val>80 THEN 1 END) = 1
Or for Microsoft Access the having clause would need to be
HAVING MAX(IIf(PC.Cod='A' and Val>100, 1, 0)) = 1
AND MAX(IIf(PC.Cod='B' and Val>80, 1, 0)) = 1
Upvotes: 0
Reputation: 66697
Select p.Name
from P p
inner join PC pc1 on p.Id = pc1.Id and pc1.Cod = 'A' and pc1.Val > 100
inner join PC pc2 on p.Id = pc2.Id and pc2.Cod = 'B' and pc2.Val > 80
Upvotes: 0
Reputation: 3996
Do not know how the performance is .. try it ..
SELECT P.Name
FROM P
INNER JOIN PC AS a ON P.Id=a.Id and a.Cod='A' and a.Val>100
INNER JOIN PC AS b ON P.Id=b.Id and a.Cod='B' and a.Val>80
Upvotes: 2
Reputation: 8709
Select P.Name
from P, PC
where P.Id=PC.Id
and PC.Cod='A' and Val>100
and exists (Select 1 From PC Where Id = P.Id and Cod = 'B' and Val > 80)
Upvotes: 0
Reputation: 753970
SELECT P.Name
FROM P
JOIN PC AS P1 ON P.Id = P1.Id AND P1.Cod = 'A' AND P1.Val > 100
JOIN PC AS P2 ON P.Id = P2.Id AND P2.Cod = 'B' AND P2.Val > 80
Using table aliases P1 and P2 allows you to do a 3-way join. It isn't quite a self-join, though; not this time.
Upvotes: 0