我试图让以下内容返回 PostgreSQL 中使用左连接的每个组织的计数,但我无法弄清楚为什么它不起作用:
select o.name as organisation_name,
coalesce(COUNT(exam_items.id)) as total_used
from organisations o
left join exam_items e on o.id = e.organisation_id
where e.item_template_id = #{sanitize(item_template_id)}
and e.used = true
group by o.name
order by o.name
使用
coalesce
似乎不起作用。我已经无计可施了!任何帮助都将不胜感激!
为了澄清什么不起作用,目前查询仅返回计数大于 0 的组织的值。我希望它为 every 组织返回一行,无论计数如何。
表格定义:
TABLE exam_items
id serial NOT NULL
exam_id integer
item_version_id integer
used boolean DEFAULT false
question_identifier character varying(255)
organisation_id integer
created_at timestamp without time zone NOT NULL
updated_at timestamp without time zone NOT NULL
item_template_id integer
stem_id integer
CONSTRAINT exam_items_pkey PRIMARY KEY (id)
TABLE organisations
id serial NOT NULL
slug character varying(255)
name character varying(255)
code character varying(255)
address text
organisation_type integer
created_at timestamp without time zone NOT NULL
updated_at timestamp without time zone NOT NULL
super boolean DEFAULT false
CONSTRAINT organisations_pkey PRIMARY KEY (id)
LEFT JOIN
这应该有效:
SELECT o.name AS organisation_name, count(e.id) AS total_used
FROM organisations o
LEFT JOIN exam_items e ON e.organisation_id = o.id
AND e.item_template_id = #{sanitize(item_template_id)}
AND e.used
GROUP BY o.name
ORDER BY o.name;
您有一个
LEFT [OUTER] JOIN
,但后来的 WHERE
条件使其表现得像一个普通的 [INNER] JOIN
。JOIN
子句以使其按预期工作。这样,只有满足所有这些条件的行才会首先连接(或者 right 表中的列会填充 NULL)。就像您所拥有的那样,连接的行实际上会在LEFT JOIN
之后测试附加条件,如果不通过则将其删除,就像普通的
JOIN
一样。
count()
从一开始就不会返回 NULL。在这方面,这是聚合函数中的一个例外。因此,即使有额外的参数,
COALESCE(COUNT(col))
需要注意的是,我的粗体强调。参见:除了
之外,这些函数在没有选择行时返回空值。count
count()
必须位于定义为
NOT NULL
的列上(如
e.id
),或者示例中联接条件保证
NOT NULL
(
e.organisation_id
、
e.item_template_id
或
e.used
)的位置。由于
used
是类型
boolean
,因此表达式
e.used = true
是燃烧至仅
e.used
的噪音。由于
o.name
未定义
UNIQUE NOT NULL
,您可能需要改为
GROUP BY o.id
(
id
是 PK) - 除非您打算折叠具有相同名称(包括 NULL)的行。 先聚合,后加入
exam_items
的大部分或全部行,则此等效查询通常会更快/更便宜:
SELECT o.id, o.name AS organisation_name, e.total_used
FROM organisations o
LEFT JOIN (
SELECT organisation_id AS id -- alias to simplify join syntax
, count(*) AS total_used -- count(*) = fastest to count all
FROM exam_items
WHERE item_template_id = #{sanitize(item_template_id)}
AND used
GROUP BY 1
) e USING (id)
ORDER BY o.name, o.id;
(这是假设您不想像上面提到的那样折叠具有相同名称的行 - 典型情况。)现在我们可以在子查询中使用更快/更简单的
count(*)
,并且外部
GROUP BY
中不需要
SELECT
。参见:
重要的一行是
GROUP BY MAIN_TABLE
,它将处理来自
SOME_TABLE
的 NULL 值
SELECT COUNT(ST.ID)
FROM MAIN_TABLE MT
LEFT JOIN SOME_TABLE ST ON MT.ID = ST.MT_ID
GROUP BY MT.ID -- this line is a must