SQL 如何获取和使用以前的数据并在以后计算

Posted

技术标签:

【中文标题】SQL 如何获取和使用以前的数据并在以后计算【英文标题】:SQL How to get and use previous data and calculate later 【发布时间】:2020-05-12 23:38:30 【问题描述】:

这是我拥有的数据:

+-----+-------------+----------+-----------+
| id  |    date     |  status  |  health   |
+-----+-------------+----------+-----------+
| 270 | 4/5/20 3:00 | STARTING | UNHEALTHY |
| 270 | 4/5/20 3:03 | ACTIVE   | UNHEALTHY |
| 270 | 4/5/20 3:05 | ACTIVE   | UNHEALTHY |
| 270 | 4/5/20 3:08 | ACTIVE   | HEALTHY   |
| 270 | 4/5/20 3:14 | ACTIVE   | UNHEALTHY |
+-----+-------------+----------+-----------+

我想计算由 STARTING 引起的停机时间(在本例中,从 4/5/20 3:03 ~ 4/5/20 3:08 开始)。

这是我希望的结果:

+-----+-------------+----------+-----------+-------------------------------------+
| id  |    date     |  status  |  health   | STARTING_CAUSED_DOWNTIME_IN_SECONDS |
+-----+-------------+----------+-----------+-------------------------------------+
| 270 | 4/5/20 3:00 | STARTING | UNHEALTHY |                                     |
| 270 | 4/5/20 3:03 | ACTIVE   | UNHEALTHY |                                     |
| 270 | 4/5/20 3:05 | ACTIVE   | UNHEALTHY |                                     |
| 270 | 4/5/20 3:08 | ACTIVE   | HEALTHY   |                                 480 |
| 270 | 4/5/20 3:14 | ACTIVE   | UNHEALTHY |                                     |
+-----+-------------+----------+-----------+-------------------------------------+

如果你看到这个,我没有考虑最后一行,ACTIVE / UNHEALTHY (3:14),因为它不是 STARTING 导致停机(这意味着开始后不健康)

我尝试过的:

SELECT 
id,date,status,prev_status,health,prev_health,LAST_START_TIME,HEALTHY_AFTER_STARTING_TIME
FROM
    (
        SELECT 
        id,date,status,health,
        LAG(status) OVER(partition BY id ORDER BY DATE) AS prev_status,
        LAG(health) OVER (partition BY id ORDER BY DATE) AS prev_health,
        (case when status = 'ACTIVE' AND prev_status = 'STARTING' then date end) AS LAST_START_TIME,
        (case when status = 'ACTIVE' AND prev_status = 'ACTIVE' AND prev_health = 'UNAVAILABLE' AND health_state <> 'UNAVAILABLE' THEN date END) AS HEALTHY_AFTER_STARTING_TIME
        FROM  
        DB_TABLE_04
    ) t1 ORDER BY DATE

我尝试使用此查询查找 2 次(STARTING 停机时间开始时/STARTING 停机时间结束时)。

我发现了 2 个问题。

    当我找到第二次,当 STARTING 停机时间结束时 (HEALTHY_AFTER_STARTING_TIME),我无法弄清楚如何找到停机时间。

我认为它需要类似于:

(extract(epoch from (starting_downtime_end - most_recent_starting_downtime_start)))

但是我该如何实现呢?

    这是更大的问题。如果我采用这种方法,我最终会考虑所有活动/不健康的情况,即使它不是由开始引起的

例如,它将创建如下内容:

+-----+-------------+----------+-------------+-----------+-------------+-----------------+-----------------------------+
| id  |    date     |  status  | prev_status |  health   | prev_health | LAST_START_TIME | HEALTHY_AFTER_STARTING_TIME |
+-----+-------------+----------+-------------+-----------+-------------+-----------------+-----------------------------+
| 270 | 4/5/20 3:00 | STARTING |             | UNHEALTHY |             |                 |                             |
| 270 | 4/5/20 3:03 | ACTIVE   | STARTING    | UNHEALTHY | UNHEALTHY   | 4/5/20 3:00     |                             |
| 270 | 4/5/20 3:05 | ACTIVE   | ACTIVE      | UNHEALTHY | UNHEALTHY   |                 |                             |
| 270 | 4/5/20 3:08 | ACTIVE   | ACTIVE      | HEALTHY   | UNHEALTHY   |                 | 4/5/20 3:08                 |
| 270 | 4/5/20 3:14 | ACTIVE   | ACTIVE      | UNHEALTHY | HEALTHY     |                 |                             |
| 270 | 4/5/20 3:18 | ACTIVE   | ACTIVE      | HEALTHY   | UNHEALTHY   |                 | 4/5/20 3:18                 |
+-----+-------------+----------+-------------+-----------+-------------+-----------------+-----------------------------+

我不想考虑 4/5/20 3:18 的情况,但它会。

如何从数据中获得我想要的结果?

我也可以在这个问题中使用窗口函数吗?

【问题讨论】:

我删除了不一致的数据库标签。请仅使用您真正使用的数据库进行标记。 @GordonLinoff 谢谢,我开始学习 sql 作为 sql-server,但目前正在研究 redshift。这就是我添加两者的原因。从现在开始,我会将它保留到我目前正在处理的那个。 【参考方案1】:

嗯。 . .这似乎得到了你想要的日期:

select t.*,
       (case when health = 'HEALTHY'
             then max(case when status = 'STARTING' then date end) over
                      (partition by id
                       order by date
                       rows between unbounded preceding and current row
                      )
        end) as starting_date
from DB_TABLE_04 t;

以及以秒为单位的差异:

datediff(second,
         (case when health = 'HEALTHY'
               then max(case when status = 'STARTING' then date end) over
                        (partition by id
                         order by date
                         rows between unbounded preceding and current row
                        )
          end),
         date
        ) as seconds_diff

此外,窗口框架子句 (rows between) 在 SQL Server 中是不必要的,但在 Redshift 中是必需的。

【讨论】:

谢谢,我也快到这里了,但是通过这种方法,我关心的第二个问题仍然出现在结果中。我只想在它变为 ACTIVE 时显示一次结果编号 |不健康到活跃 |健康的每个开始状态。使用这种方法,我的上一个示例中的 4/5/20 3:08 和 4/5/20 3:18 案例都会显示数字,我不想显示 4/5/20 3:18向上。有什么技巧可以将您现在拥有的内容修改为我想要的内容吗?感觉快到了,但我被困在这里 使用这种方法,starting_date 将继续显示,并且仅在新的开始事件发生时更改它的日期,并且每次健康状况良好时都会尝试 datediff,我想要的是停机时间导致 STARTING。有点不同

以上是关于SQL 如何获取和使用以前的数据并在以后计算的主要内容,如果未能解决你的问题,请参考以下文章

如何在计算机中训练神经网络或随机森林算法并在以后的Android设备中进行测试?

如何在 SQL Server 中使用存储过程提高和加快获取数据的速度?

SQL,如何从以前的INSERT中获取自动ID?

在SQL语言中,输入的是出生年月,如何获取年龄。

怎样从sql数据库中一次随机读取一条数据,而且以后随机读取出的数据不能和以前每次随机读取出的数据重复?

SQL 问题:根据操作代码获取以前的数据