使用三层嵌套表的聚合列创建视图

问题描述 投票:0回答:1

我使用的是 Postgres 9.4,我有 3 个表:

truck
container
container_metadata

一个
truck
可以有多个
container
,一个
container
可以有多个
container_metadata

稍后我将在下表中添加更多描述(我已尽力创建它们),所以这里是:

enter image description here

一辆卡车可以包含许多通过密钥truck_id

引用的集装箱

enter image description hereenter image description here

一个容器由

container_metadata
表描述,一个容器也可以有许多不同类型的记录,但在这种情况下,我将只关注“子容器”类型。

我试图解决的问题是创建一个视图以便于查询和模型创建(用于数据浏览器)。我将在下面添加更多详细信息。

enter image description here

在最后一列中,如果卡车具有以下特征,则

all good
为真:

  • 至少一个容器。
  • 一个容器在元数据中应至少有一条
    subcontainer
    类型的记录。
  • 所有子容器的体积值应为非零正值。

更多详情:

  • 如果卡车没有集装箱,那么我应该有一栏来描述是否需要为其创建集装箱。
  • 如果卡车有集装箱但没有子集装箱,那么我也应该能够告诉我需要为其创建子集装箱记录。
  • 如果一辆卡车有 10 个集装箱,但其中只有 6 个集装箱至少有一个子集装箱,那么它仍然不好,我应该能够知道我仍然需要创建一个子集装箱。
  • 如果一辆卡车的集装箱有子集装箱,但其中一个子集装箱的体积为0,同样不好,我还应该通知我们需要填充它。

我只能计算容器、子容器的数量,我一直在尝试聚合函数,但我对这个问题很陌生,我希望这些表格能有所帮助。请询问是否需要更多说明。

查询

到目前为止我的尝试:

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
;

假设模式是公开的。上面是我尝试过的查询,但它输出了错误数量的子容器,这就是我已经达到的程度。

sql postgresql view left-join aggregate
1个回答
2
投票

假设

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:

© www.soinside.com 2019 - 2024. All rights reserved.