我使用的是 Postgres 9.4,我有 3 个表:
truck
、 container
和 container_metadata
。truck
可以有多个 container
,一个 container
可以有多个 container_metadata
。
稍后我将在下表中添加更多描述(我已尽力创建它们),所以这里是:
一辆卡车可以包含许多通过密钥truck_id
引用的集装箱一个容器由
container_metadata
表描述,一个容器也可以有许多不同类型的记录,但在这种情况下,我将只关注“子容器”类型。
我试图解决的问题是创建一个视图以便于查询和模型创建(用于数据浏览器)。我将在下面添加更多详细信息。
在最后一列中,如果卡车具有以下特征,则
all good
为真:
subcontainer
类型的记录。更多详情:
我只能计算容器、子容器的数量,我一直在尝试聚合函数,但我对这个问题很陌生,我希望这些表格能有所帮助。请询问是否需要更多说明。
到目前为止我的尝试:
select
t.id,t.name, count(c.id) as container_count, count(cm.id) as subcontainer_count
from
public.truck t
left join
public.container c
on
c.truck_id = t.id
left join
public.container_metadata cm
on
cm.container_id = c.id and type = 'subcontainer'
group by t.id
;
假设模式是公开的。上面是我尝试过的查询,但它输出了错误数量的子容器,这就是我已经达到的程度。
假设
container_metadata.volume
为 NOT NULL DEFAULT 0
,这应该完成完整的工作:
SELECT t.id, t.name
, COALESCE(c.cont_ct, 0) AS cont_ct
, COALESCE(c.sub_ct, 0) AS sub_ct
, COALESCE(c.empty_ct, 0) AS empty_ct
, c.truck_id IS NULL AS cont_missing
, c.sub_missing IS NOT FALSE AS sub_missing
,(c.empty_ct = 0) IS NOT TRUE AS sub_needfill
, c.empty_ct = 0 AND NOT c.sub_missing AS all_good
FROM truck t
LEFT JOIN (
SELECT truck_id
, count(*) AS cont_ct
, sum(cm.ct_sub) AS sub_ct
, sum(cm.ct_empty) AS empty_ct
, bool_or(cm.container_id IS NULL) AS sub_missing
FROM container c
LEFT JOIN (
SELECT container_id
, count(*) AS ct_sub
, count(*) FILTER (WHERE volume = 0) AS ct_empty
FROM container_metadata
WHERE type = 'subcontainer' -- only those seem relevant
GROUP BY 1
) cm ON cm.container_id = c.id
GROUP BY 1
) c ON c.truck_id = t.id;
主要特点是先聚合,然后然后加入到下一个上层。无论如何,它不仅在处理大部分或全部表时通常更快,而且还允许一次性聚合每个级别:
警惕空值。这些可以通过列值或通过
LEFT JOIN
(缺失行)引入。观察哪些列可以为空非常重要。该查询仅对匹配表定义有效。
聚合
FILTER
子句需要 Postgres 9.4: