如何为间隙和孤岛问题编写查询?

How to write a query for a gaps and islands problem?

这是一个缺口和孤岛问题。

Meter_id |Realtimeclock      |I_Y|I_B|I_X|
201010   |27-09-2018 00:00:00|1.0|2.0|3.0|
201010   |27-09-2018 00:30:00|1.0|2.0|3.0|
201010   |27-09-2018 01:00:00|1.0|2.0|3.0|
201010   |27-09-2018 01:30:00|1.0|2.0|3.0|
201010   |27-09-2018 02:00:00|1.0| 0 |3.0|
201010   |27-09-2018 02:30:00|1.0| 0 |0  |
201010   |27-09-2018 03:00:00|1.0|2.0|3.0|
201010   |27-09-2018 03:30:00|1.0|2.0|3.0|
201011   |27-09-2018 00:00:00|1.0|2.0|3.0|
201011   |27-09-2018 00:30:00|1.0|2.0|3.0|
201010   |28-09-2018 03:00:00|1.0|2.0|3.0|
201010   |28-09-2018 03:30:00|1.0|2.0|3.0|
201011   |28-09-2018 04:00:00|1.0| 0 |0  |
201011   |28-09-2018 00:00:00|1.0|2.0|3.0|
201011   |28-09-2018 00:30:00|1.0|2.0|3.0|

一种方法使用行号差异法:

select * from (
WITH cte1 AS (
        SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Meter_id ORDER BY Realtimeclock) rn
        FROM yourTable t
    ),
    cte2 AS (
        SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Meter_id ORDER BY Realtimeclock) rn
        FROM yourTable t
        WHERE I_B <> 0
    ),
    cte3 AS (
        SELECT t1.*,
            t1.rn - t2.rn AS diff
        FROM cte1 t1
        INNER JOIN cte2 t2
            ON t1.Meter_id = t2.Meter_id AND t1.Realtimeclock = t2.Realtimeclock
    )        
    SELECT
        Meter_id,
        MIN(Realtimeclock) AS start_time,
        MAX(Realtimeclock) AS end_time,
        COUNT(I_Y) AS I_Y,
        COUNT(I_B) AS I_B,
        COUNT(I_X) AS I_X,ROW_NUMBER() OVER (PARTITION BY meter_id ORDER BY meter_id ) AS Spell
    FROM cte3
    GROUP BY
        Meter_id,
        diff);

输出应该打印成 ,请让我知道代码中需要的任何更改。

根据上面的 table 我需要日间咒语作为开始时间和结束时间,基于条件 I_Y、I_B、I_X,它是非零值计数table。 在这里我们看到 201010 meter_id 的开始时间有两个法术,因为它们之间存在时间间隔。同样,它必须显示所有法术以及日期和时间戳。

Meter_id |start_time         |End_time           |I_Y|I_B|I_X|spell
201010   |27-09-2018 00:00:00|27-09-2018 01:30:00|4  |4  |4  |1
201010   |27-09-2018 03:00:00|27-09-2018 03:30:00|4  |4  |4  |2
201011   |27-09-2018 00:00:00|27-09-2018 00:30:00|2  |2  |2  |1
201010   |28-09-2018 03:00:00|27-09-2018 03:30:00|2  |2  |2  |1
201011   |28-09-2018 00:00:00|28-09-2018 00:30:00|2  |2  |2  |1

抛出运行时间错误如下,

[错误] 执行 (35:22):ORA-01830:日期格式图片在转换整个输入字符串之前结束

嗨蒂姆,

请看一下it.It对我会有很大的帮助。

在给出 t运行c(realtimeclock) 而不是 TO_DATE(realtimeclock) ..

后清除以上内容

感谢蒂姆的帮助。

您只需对当前方法稍作修改,即可在日期上添加一个分区(除了 meter_id)。然后,在最后的查询中,添加一个 COUNT 来计算给定仪表和日期的法术数量。

WITH cte1 AS (
    SELECT t.*,
        ROW_NUMBER() OVER (PARTITION BY Meter_id, TO_DATE(Realtimeclock)
            ORDER BY Realtimeclock) rn
    FROM yourTable t
),
cte2 AS (
    SELECT t.*,
        ROW_NUMBER() OVER (PARTITION BY Meter_id, TO_DATE(Realtimeclock)
            ORDER BY Realtimeclock) rn
    FROM yourTable t
    WHERE I_B <> 0
),
cte3 AS (
    SELECT t1.*,
        t1.rn - t2.rn AS diff
    FROM cte1 t1
    INNER JOIN cte2 t2
        ON t1.Meter_id = t2.Meter_id AND t1.Realtimeclock = t2.Realtimeclock
)

SELECT
    Meter_id,
    MIN(Realtimeclock) AS start_time,
    MAX(Realtimeclock) AS end_time,
    COUNT(I_Y) AS I_Y,
    COUNT(I_B) AS I_B,
    COUNT(I_X) AS I_X,
    COUNT(*) OVER (PARTITION BY TO_DATE(Realtimeclock), Meter_id
        ORDER BY MIN(Realtimeclock)) AS spell
FROM cte3
GROUP BY
    Meter_id,
    TO_DATE(Realtimeclock),
    diff;

Demo

请注意,此答案假定永远不会 运行 从一个日历日转移到下一个日历日。如果这可能发生,并且您需要考虑到这一点,那么您应该告诉我们计算此类事件的逻辑是什么。

在 SQL 服务器中再次演示,虽然上面的查询是 Oracle 代码并且应该 运行 没有任何问题。