use*_*760 5 postgresql join aggregate
我有一个关于如何JOIN
在多个表上工作的基本问题。我想计算link1
&中外键的出现次数link2
CREATE TABLE main (
id SERIAL PRIMARY KEY,
name text NOT NULL
);
CREATE TABLE link1 (
id SERIAL PRIMARY KEY,
main_id integer NOT NULL,
CONSTRAINT main_id_fk FOREIGN KEY (main_id) REFERENCES main (id)
);
-- link2 is similar to link1
Run Code Online (Sandbox Code Playgroud)
当两列中的计数都不为零时,为什么下面的查询会给出计数的乘积(而不是总和)。
SELECT main.id, COUNT(link1.main_id) + COUNT(link2.main_id)
FROM main
LEFT JOIN link1 ON main.id=link1.main_id
LEFT JOIN link2 ON main.id=link2.main_id
GROUP BY main.id
Run Code Online (Sandbox Code Playgroud)
您看到的是“代理交叉连接”。先聚合,然后加入:
SELECT m.id, COALESCE(l1.ct, 0) + COALESCE(l2.ct, 0) AS total_ct
FROM main m
LEFT JOIN (
SELECT main_id, count(*) AS ct
FROM link1
GROUP BY main_id
) l1 ON l1.main_id = m.id
LEFT JOIN (
SELECT main_id, count(*) AS ct
FROM link2
GROUP BY main_id
) l2 ON l2.main_id = m.id
ORDER BY m.id;
Run Code Online (Sandbox Code Playgroud)
难道不是与多个不合格的连接和乘行count(DISTINCT ...)
,以后再修改错误。它碰巧在这种情况下工作,因为计算 DISTINCT link1.id
/link2.id
与所需的结果一致,但它不必要地昂贵且容易出错。
这些相关答案中的详细解释和几个语法变体:
我会尝试自己回答这个问题。考虑&LEFT JOIN
之间。输出将是main
link1
main.id link1.main_id
1 1
1 1
2 2
3 NULL
4 NULL
Run Code Online (Sandbox Code Playgroud)
现在用 执行LEFT JOIN
上面的表格link2
,输出将是:
main.id link1.main_id link2.main_id
1 1 NULL
1 1 NULL
2 2 2
2 2 2 -- Error : double counting for link1
3 NULL 3
4 NULL
Run Code Online (Sandbox Code Playgroud)
现在计算 的出现次数main_id
并对它们求和(按 分组main.id
)
main.id Count
1 2
2 2 + 2
3 1
4 0
Run Code Online (Sandbox Code Playgroud)
因此,两个连续的事件LEFT JOIN
是顺序发生的,而不是并行发生的。获取计数的正确方法是分别进行 2 个查询,然后将结果相加
根据@a1ex07更新另一种方法是
SELECT main.id, COUNT(DISTINCT link1.id) + COUNT(DISTINCT link2.id)
FROM main
LEFT JOIN link1 ON main.id=link1.main_id
LEFT JOIN link2 ON main.id=link2.main_id
GROUP BY main.id
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
13098 次 |
最近记录: |