1

我正在尝试编写一个复杂的(至少,就我的知识水平而言)字符串,但我有一个地狱般的时间。

这就是问题所在。我有两张表,一张名为 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 表中具有e_date过去 24 小时内的所有 e_id 值。
  • 检索过去 30 天内(e_date > now - 30 天)内 T1 中过去 24 小时内( e_date 大于当前时间 - 24h )发生的所有 e_id ,仍在表 T1 内(例如:如果 e_id 的 AAAAAAA并且 BBBBBBBB 在 t1 中找到,并且 e_date 在过去 24 小时内,检索 e_id 的 AAAAAAAAA 和 BBBBBBBB 在同一个表中的所有出现,但 e_date 在过去 30 天内
  • 将在整个中找到的e_status = 'OK'每个特定的计数附加到行结果中e_idT1 table
  • 将在整个中找到的e_Status = 'OK'每个特定的计数附加到行结果中e_idC1 table

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

T1:

  1. e_id: 'A' , e_date: 2012-Nov-08 10:00:00 , e_status: 'OK'
  2. e_id: 'A' , e_date: 2012-Nov-08 10:00:00 , e_status: 'R'
  3. e_id: 'A' , e_date: 2012-Oct-15 10:00:00 , e_status: 'R'
  4. e_id: 'B', e_date: 2012-Oct-15 10:00:00 , e_status: 'OK'
  5. e_id: 'A' , e_date: 2012-Oct-15 10:00:00 , e_status: 'OK'
  6. e_id: 'A' , e_date: 2012-Oct-15 10:00:00 , e_status: 'R'
  7. e_id: 'A' , e_date: 2012-Oct-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'

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: 'OK'
  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: 'OK'
  5. e_id: 'A' , e_date: 2012-Oct-01 10:00:00 , e_status: 'OK'

运行查询将产生:

e_id, e_date, e_status, r_count, c_count
1. e_id: 'A' , e_date: 2012-Nov-08 10:00:00 , e_status: 'OK' , r_count: 6 , c_count: 2
2. e_id: 'A' , e_date: 2012-Nov-08 10:00:00 , e_status: 'R' , r_count: 6 , c_count: 2
3. e_id: 'A' , e_date: 2012-Oct-15 10:00:00 , e_status: 'R' , r_count: 6 , c_count: 2
4. e_id: 'A' , e_date: 2012-Oct-15 10:00:00 , e_status: 'OK' ,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 -Oct-15 10:00:00 ,e_status:'R',r_count:6,c_count:2

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

T1 的第 4 行未返回,因为e_id: B在过去 24 小时内未找到
T1 第 8 行和第 9 行未返回,因为它们在过去 30 天之外

4

1 回答 1

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的(次要)更新。

于 2012-11-09T02:54:34.157 回答