【问题标题】:Join across multiple tables with partial counts跨多个表加入部分计数
【发布时间】:2013-05-29 22:11:51
【问题描述】:

每个company 都有产品,每个productdetail1detail2detail3 表中都有条目。

**Table Company**
cid |   cname   
-----+-----------
100 | Company 1
101 | Company 2

**Table Product**
pid  | cid |   dname   
------+-----+-----------
1000 | 100 | Product A
2000 | 101 | Product B

**Table detail1**
pid  | state |          datetime          
------+-------+----------------------------
1000 | A     | 2013-06-03 11:49:49.224992
1000 | B     | 2013-06-03 11:49:49.226124
1000 | B     | 2013-06-03 11:49:49.228573
1000 | B     | 2013-06-03 11:49:49.23136
1000 | A     | 2013-06-03 11:49:49.233897
2000 | A     | 2013-06-03 11:49:49.243572
2000 | B     | 2013-06-03 11:49:49.245899

**Table detail2**
pid  | type |          datetime          
------+------+----------------------------
1000 | T1   | 2013-06-03 11:49:49.257978
1000 | T1   | 2013-06-03 11:49:49.258865
1000 | T1   | 2013-06-03 11:49:49.261212
1000 | T1   | 2013-06-03 11:49:49.263515
2000 | T1   | 2013-06-03 11:49:49.270654

**Table detail3**
pid  | quality |          datetime          
------+---------+----------------------------
1000 | Q1      | 2013-06-03 11:49:49.280894
1000 | Q1      | 2013-06-03 11:49:49.281786
1000 | Q1      | 2013-06-03 11:49:49.284011
2000 | Q1      | 2013-06-03 11:49:49.287797
2000 | Q1      | 2013-06-03 11:49:49.288629
2000 | Q1      | 2013-06-03 11:49:49.289587

我正在寻找一个返回数据如下的查询:

CompanyID  CompanyName  detail1.StateA  detail1.stateB  count(detail2) count(detail3)
---------- ------------ --------------- --------------- -------------- ---------------
100        Company 1         2               3                4             3
101        Company 2         1               1                1             2 

我可能会根据datetime 约束进一步限制结果。

【问题讨论】:

    标签: sql postgresql join aggregate-functions


    【解决方案1】:
    SELECT c.cid
          ,c.cname
          ,sum(d1.d1_a_ct) AS d1_a_ct
          ,sum(d1.d1_b_ct) AS d1_b_ct
          ,sum(d2.d2_ct)   AS d2_ct
          ,sum(d3.d3_ct)   AS d3_ct
    FROM   company c
    LEFT   JOIN product p USING (cid)
    LEFT   JOIN (
       SELECT pid, count(state = 'A' OR NULL) AS d1_a_ct
                  ,count(state = 'B' OR NULL) AS d1_b_ct
       FROM   detail1
       -- WHERE datetime >= '2013-06-03 11:45:00'
       -- AND   datetime <  '2013-06-05 15:00:00'
       GROUP  BY pid
       ) d1   USING (pid)
    LEFT   JOIN (
       SELECT pid, count(*) AS d2_ct
       FROM   detail2
       GROUP  BY pid
       ) d2   USING (pid)
    LEFT   JOIN (
       SELECT pid, count(*) AS d3_ct
       FROM   detail3
       GROUP  BY pid
       ) d3   USING (pid);
    GROUP BY  c.cid, c.cname;
    

    在这种情况下避免“代理交叉连接”很重要。 如果您连接到多个 n 表(detail1、detail2、...)并且每个表都可以有多个相关行,则这些行将相互相乘。
    为避免此问题,请先聚合详细信息表,以便每个产品只有 1 行。然后将它们一次全部加入到相应的产品中是没有问题的。

    在这个相关答案中有更多解释:
    Two SQL LEFT JOINS produce incorrect result

    我也使用LEFT JOIN,尽管您写道“each 产品在.. 中有条目”。伤不起。否则,如果其中一个明细表中没有相关行,您将失去整个公司的结果。

    我对产品做了同样的事情,所以你甚至可以找到根本没有任何产品的公司。

    这里解释了count(state = 'A' OR NULL) 的部分计数如何工作:
    Compute percents from SUM() in the same SELECT sql query

    进一步限制datetime 列很简单。我添加了注释 WHERE 子句。注意使用&gt;=&lt; 以避免a common mistake with timestamp ranges

    【讨论】:

    • 感谢您的回复和解释。这真的很有帮助。是的,在我的示例中,详细信息表有条目,但实际上这些条目可能存在也可能不存在。我一直在寻找可以合作的东西。我会试试你的查询。再次感谢。
    • @aquitted-mind:我还为datetime 限制添加了一点。
    猜你喜欢
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-25
    相关资源
    最近更新 更多