【问题标题】:Create view with aggregated columns from three levels of nested tables使用来自三层嵌套表的聚合列创建视图
【发布时间】:2015-04-24 03:02:51
【问题描述】:

我使用的是 Postgres 9.4,我有 3 个表:truckcontainercontainer_metadata
一个truck 可以有很多container 和一个container 很多container_metadata

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

一辆卡车可以包含许多由 truck_id

键引用的集装箱

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

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

在最后一列中,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
;

假设架构是公开的。以上是我尝试过的查询,但它输出了错误数量的子容器,这就是我已经走了多远。

【问题讨论】:

  • 您能否将表定义提供为create table 语句,将示例数据提供为insert 语句?或者甚至为此创建一个sqlfiddle.com?屏幕截图对于示例数据非常不利,因为您无法从中复制和粘贴。
  • 我们真的很想看看你到目前为止所做的尝试。这个网站是为了解决问题而不是让其他人无偿做你的工作。因此,一个问题包含太多问题。
  • 好吧,当然……等一下。这不是真实数据。我只是用卡车和集装箱来表示类似的表结构。我只是认为包含我的解决方案已经太长了。好的,会更新的。
  • Sql fiddle here sqlfiddle.com/#!15/8c724/1 ...我不确定我是否理解正确,但是是的。顺便说一句,这不是真正的工作,如果您误解了,请见谅。但是我真的很想知道正确的sql语句来解决这种问题。即使不完全是“这个”问题。谢谢。我会更新问题
  • 我已经用我的初始查询更新了问题

标签: sql postgresql view left-join aggregate


【解决方案1】:

假设container_metadata.volumeNOT 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;

主要特点是先聚合,然后然后加入到上一层。无论如何,它不仅在处理大部分或全部表格时通常更快,而且还允许一举聚合每个级别:

您需要非常小心 NULL 值可能潜入的位置。这些可能由列值或 LEFT JOIN(缺失行)引入。因此,必须观察哪些列可以为 NULL。该查询仅在与拟合表定义结合使用时有效。

当然您需要了解logicalcomparison operators,尤其是涉及NULL 值。

聚合 FILTER 需要 Postgres 9.4:

SQL Fiddle 没有数据,因为没有提供数据。所以也没有测试。

【讨论】:

  • 谢谢,这些真的很有帮助,我开始用我的真实表格和数据集进行尝试。 :) 并更新发生的事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-04
  • 1970-01-01
相关资源
最近更新 更多