-3

表“审计”具有字段 id、old_status、new_status 和 changed_at。状态包含值 Open、On Hold 和 Closed。我想确定审核被搁置了多长时间,简单计算:

SELECT Datediff(minute, (SELECT Min(changed_at) 
                         FROM   audit 
                         WHERE  id = 123 
                                AND new_status = 'On Hold'), 
       (SELECT Max(changed_at) 
        FROM   audit 
        WHERE  id = 123 
               AND old_status = 
                   'On Hold')) 

但是,现在我有一个多次被搁置的审计记录。上面的计算确实告诉我它第一次进入 On Hold 和最后一次退出 On Hold 之间的总时间,但它并没有反映它实际处于 On Hold 的时间。

是否有会返回该实际时间的查询?

4

2 回答 2

0

JOIN 表到自身 ON 条件是 JOIN 的左侧是 'On Hold',右侧是左侧之后的 TOP 1 记录,并且不是 'On Hold',ID与左边。

由此,您的查询只需获取左侧记录和右侧记录之间的 DATEDIFF,以及 DATEDIFF 的 SUM,按ID.

于 2019-03-26T19:45:20.093 回答
0

对于下面的答案,我假设记录的初始/默认状态是“打开”。我还假设您的 SQL Server 版本具有 LEAD/LAG 功能。

假设您有关于 3 条记录的信息。所有 3 条记录都以“打开”状态开始。

  • 对于记录 1,状态更改了 4 次:
    • 它在 8:00 从 Open 更改为 On Hold。
    • 它在 9:00 由 On Hold 更改为 Open。
    • 10:00 改回 On Hold
    • 改为11:00关门。
  • 对于记录 2,状态更改了两次:
    • 在 8:00,它从 Open 更改为 On Hold。
    • 9:00 改为关闭。
  • 记录 3 只是有一个变化:
    • 在 8:00,它从 Open 更改为 On Hold(表示当前状态为 On Hold)。

这是表格形式的数据:

+----+------------+------------+------------------+
| id | old_status | new_status |    changed_at    |
+----+------------+------------+------------------+
|  1 | Open       | On Hold    | 2019-03-26 08:00 |
|  1 | On Hold    | Open       | 2019-03-26 09:00 |
|  1 | Open       | On Hold    | 2019-03-26 10:00 |
|  1 | On Hold    | Closed     | 2019-03-26 11:00 |
|  2 | Open       | On Hold    | 2019-03-26 08:00 |
|  2 | On Hold    | Closed     | 2019-03-26 09:00 |
|  3 | Open       | On Hold    | 2019-03-26 08:00 |
+----+------------+------------+------------------+

根据数据,以及我对您问题的理解,您想要记录被搁置的总时间。因此,对于上面的 3 条记录:

  • 记录 1 总共暂停了 2 小时/120 分钟:从 8 点到 9 点持续了 1 小时,然后从 10 点到 11 点又持续了一个小时。
  • 记录 2 仅保留 1 小时:从 8 点到 9 点。
  • 对于记录 3,不清楚您的预期结果是什么:结果会是从 8:00(它被搁置时)到当前日期/时间吗?或者你想从你的结果中排除这个?

要开始解决问题,您可以先使用 WINDOW 函数查看相关结果。我最终使用了LAG.

首先,您可以使用LAG来确定最后一次更改(用于记录)发生的位置:

SELECT 
    [id], 
    old_status,
    new_status,
    changed_at,
    prev_changed = LAG(changed_at) OVER
    (
        PARTITION BY [id]
        ORDER BY [id], changed_at
    )
FROM audit_records

这将为您提供以下结果:

+----+------------+------------+------------------+------------------+
| id | old_status | new_status |    changed_at    |   prev_changed   |
+----+------------+------------+------------------+------------------+
|  1 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
|  1 | On Hold    | Open       | 2019-03-26 09:00 | 2019-03-26 08:00 |
|  1 | Open       | On Hold    | 2019-03-26 10:00 | 2019-03-26 09:00 |
|  1 | On Hold    | Closed     | 2019-03-26 11:00 | 2019-03-26 10:00 |
|  2 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
|  2 | On Hold    | Closed     | 2019-03-26 09:00 | 2019-03-26 08:00 |
|  3 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
+----+------------+------------+------------------+------------------+

请注意具有 NULL 值的记录:这些记录在更改之前没有更改。因此,对于记录 1,从 Open 到 On Hold 的更改为空,因为这是第一次更改。

现在您可以将其包含在 CTE 中并计算分钟数:

WITH 
    audit_records_lead_lag([id], old_status, new_status, changed_at, prev_changed) AS
    (
        SELECT 
            [id], 
            old_status,
            new_status,
            changed_at,
            prev_changed = LAG(changed_at) OVER
            (
                PARTITION BY [id]
                ORDER BY [id], changed_at
            )
        FROM audit_records
    )
SELECT 
    [id], 
    minutes_in_hold = SUM(DATEDIFF(MINUTE, prev_changed, changed_at))
FROM audit_records_lead_lag
WHERE
    old_status = 'On Hold'
    AND prev_changed IS NOT NULL
GROUP BY [id]

这会给你以下结果:

+----+-----------------+
| id | minutes_in_hold |
+----+-----------------+
|  1 |             120 |
|  2 |              60 |
+----+-----------------+
于 2019-03-26T19:55:13.603 回答