【发布时间】:2016-03-15 23:44:01
【问题描述】:
我有一个非常大的表(称为 device_operation 有 5000 万行),其中包含产品在其生命周期中的所有操作(例如“开始”、“停止”、“重新填充”、...”和状态这些操作(行状态:已完成,失败),以及关联设备的 ID(行 device_id)和每个操作的时间戳(行 create_date)。
类似这样的:
/------+-----------+------------------+---------\
| ID | Device ID | Create_Date | Status |
+------+-----------+------------------+---------+
| 1 | 1 | 2012-03-04 01:43 | Success |
| 2 | 4 | 2012-04-04 02:34 | Failed |
| 3 | 9 | 2013-01-01 01:23 | Failed |
| 4 | 4 | 2013-12-12 12:34 | Success |
| 5 | 23 | 2014-02-01 03:45 | Success |
| 6 | 1 | 2014-05-03 08:34 | Failed |
\------+-----------+------------------+---------/
我还有另一个表(称为订阅),它告诉我产品的保修开始时间(行 create_date)(行 device_id)。保修期为一年。
/-----------+------------------\
| Device ID | Create_Date |
+-----------+------------------+
| 2 | 2011-04-03 05:00 |
| 4 | 2012-03-05 03:45 |
| 5 | 2012-03-05 06:07 |
| ... | ... |
\-----------+------------------/
我正在使用 PostgreSQL。
我想做以下事情:
- 列出在给定日期 (2014-07-06) 之前至少有一次成功操作的所有设备 ID
对于这些设备中的每一个,计数:
- 在该日期 + 2 天 (2014-07-08) 之后的失败操作次数,并且尝试操作时设备在保修期内
- 在该日期 + 2 天 (2014-07-08) 之后的失败操作次数,并且在尝试操作时设备不在保修范围内
- 该日期之后成功操作的次数(设备是否在保修期内)
我在以下方面取得了一些有限的成功(为了便于阅读,查询已被稍微简化 - 还涉及到其他连接以获取订阅表,以及将设备包含在列表中的其他条件):
SELECT distinct device_operation.device_id as did, subscription.create_date,
(
SELECT COUNT(*)
FROM device_operation dop
WHERE dop.device_id = device_operation.device_id and
dop.create_date > '2014-07-08' and
dop.status = 'Success'
) as success,
(
SELECT COUNT(*)
FROM device_operation dop2
WHERE
dop2.device_id = subscription.device_id and
dop2.create_date > '2014-07-08' and
dop2.status = 'Failed' and
dop2.create_date <= subscription.create_date + interval '1 year'
) as failed_during_warranty,
(
SELECT COUNT(*)
FROM device_operation dop2
WHERE
dop2.device_id = subscription.device_id and
dop2.create_date > '2014-07-08' and
dop2.status = 'Failed' and
dop2.create_date > subscription.create_date + interval '1 year'
) as failed_after_warranty,
FROM device_operation, subscription
WHERE
device_operation.status = 'Success' and -- list operations which are successful
device_operation.create_date <= '2014-07-06' and -- list operations before that date
device_operation.device_id = subscription.device_id -- get warranty start for each operation
ORDER BY success DESC, failed_during_warranty DESC, failed_after_warranty DESC
您可以猜到,它太慢了,我无法运行查询。但是,它可以让您了解结构。
我尝试使用 NULLIF 将请求合并为一个,希望它能让 PostgreSQL 只列出一次子查询而不是 3 个,但它返回“子查询必须只返回一列”:
SELECT distinct device_operation.device_id as did, subscription.create_date,
(
SELECT COUNT(NULLIF(dop2.status != 'Success', true)) as completed,
COUNT(NULLIF(dop2.status != 'Failed' or not (dop2.create_date <= subscription.create_date + interval '1 year'), true)) as failed_in_warranty,
COUNT(NULLIF(dop2.status != 'Failed' or (dop2.create_date <= subscription.create_date + interval '1 year'), true)) as failed_after_warranty
FROM device_operation dop2
WHERE
dop2.device_id = device_operation.device_id and
dop2.device_id = subscription.device_id and
dop2.create_date > '2014-07-08'
) as subq
FROM device_operation, subscription
WHERE
device_operation.status = 'Success' and -- list operations which are successful
device_operation.create_date <= '2014-07-06' and -- list operations before that date
device_operation.device_id = subscription.device_id -- get warranty start for each operation
ORDER BY success DESC, failed_in_warranty DESC, failed_outside_warranty DESC
我也尝试将子查询移动到 FROM 子句,但这不起作用,因为我需要为主查询的每一行运行子查询(或者我是否?也许有更好的方法)
我期望的是这样的:
/-----------+---------+------------------------+-----------------------\
| Device ID | Success | Failed during warranty | Failed after warranty |
+-----------+---------+------------------------+-----------------------+
| 194853 | 10 | 0 | 0 |
| 7853 | 5 | 5 | 0 |
| 5848 | 3 | 0 | 56 |
| 8546455 | 0 | 45 | 0 |
| 102 | 0 | 4 | 1 |
| 69329548 | 0 | 0 | 9 |
| 17 | 0 | 0 | 0 |
\-----------+---------+------------------------+-----------------------+
有人可以帮我找到最有效的方法吗?
编辑:极端情况:您可以认为所有设备都有订阅条目。
非常感谢!
【问题讨论】:
-
我想你可以从stackoverflow.com/questions/14048098/…得到提示
-
正如我所说:“我还有另一个表(称为订阅),它告诉我产品(行 device_id)的保修何时开始(行 create_date)。保修期为一年。”跨度>
-
关于提供的链接,它没有帮助,除非我没有看到任何东西。它准确地描述了我在第二次尝试中尝试做的事情,并且我已经描述了为什么它在我的问题中不起作用(在子查询中不能返回超过一行)。我相信,我必须从我必须获取的信息的结构中处理一个子查询。
-
我认为这个
SELECT distinct device_operation.device_id as did, subscription.create_date,应该取自不同的表,例如devices。 BTW,你检查过执行计划吗?
标签: sql postgresql