views:

156

answers:

4

I have a simple one-to-many relationship. I would like to select rows from the parent only when they have at least one child. So, if there are no children, then the parent row is not returned in the result set.

Eg.

Parent:
+--+---------+
|id|   text  |
+--+---------+
| 1|  Blah   |
| 2|  Blah2  |
| 3|  Blah3  |
+--+---------+

Children
+--+------+-------+
|id|parent| other |
+--+------+-------+
| 1|   1  | blah  |
| 2|   1  | blah2 |
| 3|   2  | blah3 |
+--+------+-------+

I want the results to be:

+----+------+
|p.id|p.text|
+----+------+
|  1 | Blah |
|  2 | Blah2|
+----+------+
+5  A: 

You can do this using an EXISTS, like this:

SELECT *
FROM Parent p
WHERE EXISTS (SELECT 1
              FROM Chilren c
              WHERE c.Parent = p.id)

Or using a IN like this:

SELECT *
FROM Parent p
WHERE p.id IN (SELECT c.Parent
               FROM Chilren c)
Nick Craver
I have not tested but I'm guessing this is slower than a join.
Hogan
@Hogan - The exists it the fastest approach. The optimizer will do the same execution plan for a null checked outer join...which will be **as** fast, but the exists is never slower.
Nick Craver
Neat. Thanks @Nick. This is true for mysql, ms sql and oracle?
Hogan
@Hogan - The exists being faster, yes that holds true...how smart the optimizer is in making an equivalent left join have the same execution plan, I'm not sure about MS SQL.
Nick Craver
+1  A: 
SELECT p.*
FROM Parent p
WHERE EXISTS (SELECT 'X' FROM Children c WHERE c.parent = p.id);
JG
+2  A: 
Select p.id, p.text
from Parent p
inner join Children c on p.id = c.parent 
group by p.id, p.text
Avitus
+4  A: 

An inner join only returns rows that match both tables:

select distinct p.*
from Parent p
inner join Children c on c.parent = p.id
Andomar