加入并统计几个表

时间:2012-11-08 22:49:02

标签: mysql sql count sum self-join

我正在尝试写一个复杂的(至少,对于我的知识水平)字符串,但我有一段时间。

这是问题所在。我有两个表,一个名为t1,另一个名为c1。

表格定义如下:

table T1:

e_id, char(8),  
e_date, datetime,  
e_status, varchar(2)

table C1:

e_id, char(8),  
e_date, datetime,  
e_status, varchar(2)

每个表都包含两个表中可能找到或未找到的标识符列表(它们在每个表中可能是唯一的,也可能不是唯一的),以及相关的状态(T1表中可以是“OK”或“R”) ,可以是C1表中的'OK'或'C'),以及与e_id的每次出现相关联的日期时间e_date

我正在尝试编写一个查询:

  • 检索T1表格中过去24小时内e_date的所有e_id值。
  • 检索过去30天内在过去24小时内发生的e_id的所有发生( e_date大于当前时间--24h )(e_date> now - 30天) ,仍然在表T1中(例如:如果e1id的AAAAAAAA和BBBBBBBB在t1中找到,e_date在过去24小时内,则在同一个表中检索e_id的AAAAAAAA和BBBBBBBB的所有出现,但是e_date具有e_date是在过去30天内
  • 将整个e_status = 'OK'中找到的每个特定e_id的{​​{1}}计数添加到行结果中
  • 将整个T1 table中找到的每个特定e_Status = 'OK'的{​​{1}}计数添加到行结果中

我会尽力在这里写一些示例数据/结果。为清楚起见,我将忽略表数据类型。假设当前日期和时间是2012年11月8日19:00:00

T1:

  1. e_id:'A',e_date: 2012年11月8日10:00:00 ,e_status:'确定'
  2. e_id:'A',e_date: 2012年11月8日10:00:00 ,e_status:'R'
  3. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'R'
  4. e_id:'B',e_date: 2012年10月15日10:00:00 ,e_status:'确定'
  5. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'确定'
  6. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'R'
  7. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'R'
  8. e_id:'A',e_date: 2010-Jan-01 10:00:00 ,e_status:'R'
  9. e_id:'A',e_date: 2010-Jan-01 10:00:00 ,e_status:'R'
  10. C1:

    1. e_id:'A',e_date: 2012-Oct-01 10:00:00 ,e_status:'C
    2. e_id:'B',e_date: 2012-Oct-01 10:00:00 ,e_status:'确定'
    3. e_id:'A',e_date: 2012-Oct-01 10:00:00 ,e_status:'C
    4. e_id:'B',e_date: 2012-Oct-01 10:00:00 ,e_status:'确定'
    5. e_id:'A',e_date: 2012-Oct-01 10:00:00 ,e_status:'确定'
    6. 运行查询将产生:

      e_id,e_date,e_status,r_count,c_count
      1. e_id:'A',e_date: 2012年11月8日10:00:00 ,e_status:'确定',r_count: 6 ,c_count: 2
      2. e_id:'A',e_date: 2012年11月8日10:00:00 ,e_status:'R',r_count: 6 ,c_count: 2
      3. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'R',r_count: 6 ,c_count: 2
      4. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'确定',r_count: 6 ,c_count: 2
      5. e_id:'A',e_date: 2012-Oct-15 10:00:00 ,e_status:'R',r_count: 6 ,c_count: 2
      6. e_id:'A',e_date: 2012年10月15日10:00:00 ,e_status:'R',r_count: 6 ,c_count: 2

      我真的很抱歉,我不得不更改T1行3到7(结果的行3 4 5 6)的日期,因为值是错误的。

      由于在过去24小时内未找到e_id,因此未返回T1的第4行 T1第8和第9行未归还,因为它们超出了过去30天

1 个答案:

答案 0 :(得分:2)

时间做一些TDQD - 测试驱动的查询设计。

过去24小时内的T1行

SELECT DISTINCT e_id
  FROM T1
 WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)

这将是查询其他部分中普遍存在的子查询。

过去30天内T1的行......

...过去24小时内T1中有一个条目。

SELECT a.e_id
  FROM t1 AS a
  JOIN (SELECT DISTINCT e_id
          FROM T1
         WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
       ) AS b ON b.e_id = a.e_id
 WHERE a.e_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)

我们可以根据需要添加其他列。

T1中的行数,状态为' R' ...

...过去24小时内T1中有一个条目

SELECT a.e_id, COUNT(*) AS r_count  -- Per question; why not t_count?
  FROM t1 AS a
  JOIN (SELECT DISTINCT e_id
          FROM T1
         WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
       ) AS b ON b.e_id = a.e_id
 WHERE a.e_status = 'R'
 GROUP BY a.e_id

C1中的行数,状态为' C' ...

...过去24小时内T1中有一个条目

SELECT a.e_id, COUNT(*) AS c_count
  FROM c1 AS a
  JOIN (SELECT DISTINCT e_id
          FROM T1
         WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
       ) AS b ON b.e_id = a.e_id
 WHERE a.e_status = 'C'
 GROUP BY a.e_id

汇编查询集以生成结果

SELECT a.e_id, a.e_date, a.e_status, c.r_count, d.c_count
  FROM t1 AS a
  JOIN (SELECT DISTINCT e_id
          FROM T1
         WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
       ) AS b ON b.e_id = a.e_id
  LEFT JOIN -- Because there might be no OK rows in T1
       (SELECT a.e_id, COUNT(*) AS r_count
          FROM t1 AS a
          JOIN (SELECT DISTINCT e_id
                  FROM T1
                 WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
               ) AS b ON b.e_id = a.e_id
         WHERE a.e_status = 'OK'
         GROUP BY a.e_id
       ) AS c ON c.e_id = a.e_id
  LEFT JOIN -- Because there might be no OK rows in C1
       (SELECT a.e_id, COUNT(*) AS c_count
          FROM c1 AS a
          JOIN (SELECT DISTINCT e_id
                  FROM T1
                 WHERE e_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
               ) AS b ON b.e_id = a.e_id
         WHERE a.e_status = 'OK'
         GROUP BY a.e_id
       ) AS d ON d.e_id = a.e_id
 WHERE a.e_date >= DATE_SUB(NOW(), INTERVAL 30 DAY)

您可能可以在没有24小时子查询的情况下编写子查询,但是尽快消除尽可能多的行可能是有效的。


TDQD背后的概念的一个优点是您可以检查中期结果。有一些基本上是微不足道的语法问题(部分原因是因为MySQL不是我的主要DBMS),但是对于两个COUNT子查询,从JOIN到LEFT JOIN的更改是您在组装时易于发现的事情查询。试图让第一时间的一切正确 - 很难,即使不是徒劳的。但逐步建立可以让您对自己所做的事情充满信心。在没有测试组件子查询的情况下,我从不构建像这样复杂的查询。

感谢(次要)更新FatalMojo