SQL 服务器:select 来自 window 的符合条件的记录

SQL Server : select a record from a window with criteria

我在 SQL 服务器中有一个审计 table,它为单个案例存储这样的数据:

示例 1

ID        CREATED                 MESSAGE               MEMO         USER
------------------------------------------------------------------------------
A-123     08/02/2022 12:00:00     Generic Message 1     NULL         System
A-123     08/02/2022 12:05:30     Generic Message 2     NULL         System
A-123     08/02/2022 12:45:01     Reassigned to XYZ     NULL         System
A-123     08/02/2022 14:59:59     NULL                  Resolved     User XYZ
A-123     08/02/2022 18:05:05     Reassigned to XYZ     NULL         System

示例 2

ID        CREATED                 MESSAGE               MEMO         USER
--------------------------------------------------------------------------------
A-987     07/02/2022 12:00:00     Generic Message 1     NULL         System
A-987     07/02/2022 12:05:30     Generic Message 2     NULL         System
A-987     07/02/2022 12:45:01     Generic Message 3     NULL         System
A-987     07/02/2022 14:59:59     NULL                  Resolved     User XYZ
A-987     07/02/2022 18:05:05     Reassigned to XYZ     NULL         System

使用 SQL 在这些情况下我只想 select ID 值:

  1. 当 MESSAGE 值为“Reassigned to XYZ”且 USER 值为“System”时

  2. 当第 1 点出现的时间早于包含 MEMO 值“Resolved”的记录时。

在上面的 2 个示例中,示例 1 会输出 ID A-123,因为满足了 2 个条件,但是示例 2 不会输出任何内容,因为“Reassigned to XYZ " MESSAGE 值在“Resolved”MEMO 条目的时间戳之后。

我想我需要 rank() 然后做一些事情,但我不知道该做什么。

我认为这里不需要 window 函数。有几种方法可以解决这个问题:这里有一些 UNTESTED 方法。

使用 Exists 来限制数据:获取所有 XYZ,查找在解析数据之前出现的任何 XYZ 创建日期。并且 return 如果存在多个“重新分配给 XYZ”的 ID,那么 ID 的多个 ID 将 return。

SELECT ID 
FROM TABLE
WHERE message = 'Reassigned to XYZ' 
  AND exists (SELECT 1 
                  FROM TABLE
                  WHERE memo = 'Resolved'
                    AND A.ID = B.ID
                    AND A.Created < B.Created)

使用 CTE's 和一个 join。类似于存在;显示任何 XYZID,其创建的数据小于相同 ID 的解析创建数据。可以有多行 returned

WITH XYZ as (SELECT ID, Created FROM TABLE WHERE message = 'Reassigned to XYZ'),
     Resolved as (SELECT ID, Created FROM TABLE WHERE memo = 'Resolved')
SELECT XYZ.ID
FROM XYZ
INNER JOIN Resolved
   on XYZ.ID = Resolve.ID
  AND XYZ.Created < Resolved.Created

我想你也可以使用 aggregatecase expression

这假设您可以将多个重新分配给 XYZ 或已解析,并且在解析之前只需要 1 个 XYZ 即可显示 ID。如果满足条件,则只会 return 编辑 1 个 ID。

SELECT ID, 
       MIN(CASE when Message = 'Reassigned to XYZ' then create end) as MinZYZ,  
       MIN(Case when memo = 'Resolved' then create end) MinMemo
FROM Table
GROUP BY ID
HAVING MINXYZ < MinMemo

我想我们可以执行 min/case 表达式,如果需要的话,必须从 select 中删除值...只需用表达式替换所使用的别名列名即可

您可以使用 cross apply 交叉应用是一个 table 值函数,它允许子查询对 运行 左侧的每个记录执行一次 table 并且像inner join 如果没有找到记录,则删除该记录。因此,只有 XYZ 记录和解析创建的数据大于 XYZ 记录的记录才会出现。

SELECT Distinct XYZ.ID
FROM Table XYZ
CROSS APPLY (SELECT TOP 1 ID, Created FROM TABLE WHERE memo = 'Resolved' ORDER BY Created ASC) Resolved
   on XYZ.ID = Resolve.ID
  AND XYZ.Created < Resolved.Created

备注:

  • 每个人都有自己的优点s/con和假设。
  • 根据数据量指标等,性能也可能会有所不同
  • 请随时提出任何问题或指出它们是否不起作用。再次未经测试,完全基于逻辑思维,可能没有正确的语法或 return 正确的结果。