Reputation: 2787
I have tables A
, B
, and a A_B_MEMBERS
table that links A
and B
. A
can have multiple B
, and B
can have multiple A
. Consider the following concrete table schemas:
CREATE TABLE A (
a_id INT PRIMARY KEY,
data TEXT
)
CREATE TABLE B (
b_id INT PRIMARY KEY,
data TEXT
)
CREATE TABLE A_B_MEMBERS (
a_id NOT NULL REFERENCES A(a_id),
b_id NOT NULL REFERENCES B(b_id),
PRIMARY KEY (a_id, b_id)
)
Given a b_id
, I want to query for all A
s that have this b_id
but also return all other b_id
s this A
contains. So consider the following example:
a_id | data
-----+-----
1 | "hi"
2 | "hello"
3 | "cao"
b_id | data
-----+-----
1 | "people"
2 | "world"
3 | "foo"
a_id | b_id
-----+-----
1 | 1
1 | 2
1 | 3
2 | 1
2 | 2
3 | 3
So a_id=1
has b_id={1,2,3}
, a_id=2
has b_id={1,2}
, a_id=3
has b_id={3}
.
Given, say b_id=2
, the return should be:
a_id | data | b_id_arr
-----+----------+---------
1 | "hi" | {1,2,3}
2 | "hello" | {1,2}
I'm unable to do this through table joins and is forced to do two separate queries. I've tried the following:
SELECT
a.*,
ARRAY_AGG(abm.b_id) b_id_arr
FROM A a
RIGHT JOIN A_B_MEMBERS abm
ON a.a_id = abm.a_id
AND abm.b_id = 2
GROUP by a.a_id;
But this doesn't seem to give me what I'd want.
Upvotes: 0
Views: 37
Reputation: 1270573
Use left join
-- the logic is just easier to follow: keep all rows in the first table you see in the from
clause.
That said, you don't seem to need an outer join. You simply want to groups that have a "2". That suggests a HAVING
clause:
SELECT a.*, ARRAY_AGG(abm.b_id)
FROM A a JOIN
A_B_MEMBERS abm
ON a.a_id = abm.a_id
GROUP by a.a_id
HAVING COUNT(*) FILTER (WHERE abm.b_id = 2) > 0
Upvotes: 2