Schema and sample data
A simple one-to-many parent/child relationship:
CREATE TABLE Parent (
id VARCHAR PRIMARY KEY
);
CREATE TABLE Child (
id VARCHAR PRIMARY KEY,
type INT,
parent_id VARCHAR REFERENCES Parent(id)
);
INSERT INTO Parent VALUES ('p1'), ('p2'), ('p3'), ('p4');
INSERT INTO Child VALUES ('c1', 0, 'p2'), ('c2', 42, 'p2'), ('c3', 0, 'p3'), ('c4', 42, 'p4');
Queries
We always query for parents with their children. Whenever a particular parent is part of the result, all its children should be retrieved too, in any case.
Use case A)
No restriction on the children - just display all parent/child data, including the parents with no children (p1
).
The LEFT JOIN
query
SELECT p.*, c.* FROM parent p
LEFT JOIN child c ON c.parent_id = p.id
yields the desired output:
id|id|type|
--|--|----|
p1| | |
p2|c1| 0|
p2|c2| 42|
p3|c3| 0|
p4|c4| 42|
Use case B)
There's a restriction on the children, e.g. type = 42
. We'd like to retrieve the parents (with all their children) that have any child with type = 42
, i.e., the desired output is:
id|id|type|
--|--|----|
p2|c1| 0|
p2|c2| 42|
p4|c4| 42|
Note that c1
is retrieved because its parent p2
has a matching child c2
, even though c1
's type doesnt' match.
This query with a correlated subquery achieves this result:
SELECT p.*, c.* FROM parent p
JOIN child c ON c.parent_id = p.id
WHERE EXISTS (SELECT 1 FROM child c2 WHERE c2.parent_id = p.id AND c2.type = 42)
Questions
1) Is the second query WHERE EXISTS
the standard way to go for use case B)?
2) Since, in real life, there are multiple associations and multiple possible filter conditions, is there a way the entire construction of the query can be simplified, covering both use cases A) and B)? In the sense of a "master query" that can be "enriched" by conditions for various child associations. In case of a single parent table, there is a "master query" of
SELEECT * from Parent p
WHERE 1 = 1
Any conditions on the parent can simply be AND
'ed to the WHERE
clause of the "master query", making this query construction very easy.
Is there anything comparable for joins with various conditions on various children, retaining the "always return all children for each returned parent" semantics?