Aggregate functions on multiple joined tables

后端 未结 1 877
悲哀的现实
悲哀的现实 2021-01-14 21:09

I have three tables:

CREATE TABLE foo (
    id bigint PRIMARY KEY,
    name text NOT NULL
);

CREATE TABLE foo_bar (
    id bigint PRIMARY KEY,
    foo_id bi         


        
1条回答
  •  一整个雨季
    2021-01-14 21:59

    SELECT f.id, f.name, b.fb_ct, t.tag_names
    FROM   foo f
    LEFT JOIN  (
        SELECT foo_id AS id, count(*) AS fb_ct
        FROM   foo_bar
        GROUP  BY 1
        ) b USING (id)
    LEFT JOIN  (
        SELECT target_id AS id, array_agg(name) AS tag_names
        FROM   tag
        GROUP  BY 1
        ) t USING (id)
    ORDER  BY f.id;
    

    Produces the desired result.

    • Rewrite with explicit JOIN syntax. Makes it so much easier to read and understand (and debug).

    • By joining to multiple 1:n related tables, rows would multiply each other producing a Cartesian product - which is very expensive nonsense. It's an unintended CROSS JOIN by proxy. Related:

      • Two SQL LEFT JOINS produce incorrect result
    • To avoid this, join at most one n-table to the 1-table before you aggregate (GROUP BY). You could aggregate two times, but it's cleaner and faster to aggregate n-tables separately before joining them to the 1-table.

    • As opposed to your original (with implicit INNER JOIN). I use LEFT JOIN to avoid losing rows from foo that have no matching row in foo_bar or tag.

    • Once the unintended CROSS JOIN is removed from the query, there is no need for adding DISTINCT any more - assuming that foo.id is unique.

    0 讨论(0)
提交回复
热议问题