2

Each company, has products and each product has entries in detail1, detail2, detail3 table.

**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

I am looking for a query that would return data as follows:

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

I might further restrict the result based on datetime constraint.

4

1 回答 1

2
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行。然后将它们一次加入到相应的产品中就没有问题了。

此相关答案中的更多解释:
两个 SQL LEFT JOINS 产生不正确的结果

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

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

以下是关于部分计数如何count(state = 'A' OR NULL)工作的解释:
Compute percents from SUM() in the same SELECT sql query

进一步限制datetime列很简单。我添加了一个注释WHERE子句。请注意使用>=and<以避免与range一起出现常见错误timestamp

于 2013-06-03T17:32:51.120 回答