Reputation: 613
Using MS SQL Server, I'd like to count the number of entities to which each of several entities is related. Let's say my schema looks something like this:
foo (
id UNIQUEIDENTIFIER NOT NULL,
)
thing1 (
id UNIQUEIDENTIFIER NOT NULL
)
thing2 (
id UNIQUEIDENTIFIER NOT NULL
)
thingN (
id UNIQUEIDENTIFIER NOT NULL
)
with join tables
foo_thing1 (
foo_id UNIQUEIDENTIFIER NOT NULL,
thing1_id UNIQUEIDENTIFIER NOT NULL
)
etc.
there might be 2 thingNs, or 10, or some other number- I want something that works well even when there are quite a few. If there was just one Foo, a possible solution looks like this:
SELECT COUNT(DISTINCT foo_thing1.thing1_id),
COUNT(DISTINCT foo_thing2.thing2_id),
COUNT(DISTINCT foo_thing3.thing3_id),
COUNT(DISTINCT foo_thing4.thing4_id,
FROM foo
LEFT JOIN foo_thing1 ON foo_thing1.thing1_id = thing1.id
LEFT JOIN foo_thing2 ON foo_thing2.thing2_id = thing2.id
LEFT JOIN foo_thing3 ON foo_thing3.thing3_id = thing3.id
LEFT JOIN foo_thing4 ON foo_thing4.thing4_id = thing4.id
GROUP BY foo.id
HAVING foo.id = '12341234-1234-12341234-1234'
However, I'm not sure this is efficient. What if the Foo is related to a lot of thing2s and a lot of thing3s - am I getting far too many rows, and then hiding it with DISTINCT?
Further complicating things, I actually want to count the relationships of more than one foo at once. Ideally I'd like to do it by arbitrary where clause, but if necessary I can just supply a list of ids such that WHERE/HAVING foo.id IN (x, y, z). From there, though, how should I determine all the cardinalities? :(
UNION ALL is one option, since my goal in combining these queries is to save database roundtrip latency. But I suspect that the parse time of multiple SELECTs means it can't be the most efficient way...
Upvotes: 0
Views: 162
Reputation: 10703
This should work the way you expect:
SELECT foo.id,
(SELECT count(*) FROM foo_thing1 WHERE foo_thing1.foo_id = foo.id),
(SELECT count(*) FROM foo_thing2 WHERE foo_thing2.foo_id = foo.id),
(SELECT count(*) FROM foo_thing3 WHERE foo_thing3.foo_id = foo.id),
...
FROM foo
WHERE foo.id IN (1, 2, 3, 7, ...);
Upvotes: 1