(T-SQL) 如何查询审计 table,并查找 2 个日期之间的变化

(T-SQL) How to query an audit table, and find changes between 2 dates

审计 table 看起来像这样:

Audit ID    VendorID     PaymentType     CreateDateUTC
 999        8048         2               2017-10-30-08:84:24
1000        1234         5               2017-10-31-01:17:34
1001        8048         7               2017-10-31-01:17:45
1002        1234         5               2017-10-31-01:17:53
1003        1234         7               2017-10-31-01:18:23
1004        1234         5               2017-11-01-01:18:45

在此示例中,您可以看到 - VendorID 1234 以 PaymentType 5 开始,然后有另一个条目仍然是 5(审核 table 记录了与我的查询无关的其他更改),然后它变为 7,但随后变回 5。

假设我想回答问题:'Between now and date X, these VendorIDs had a change in PaymentType'。 奖金是 - 这是以前的 PaymentType。

预期结果:

VendorID  PaymentType  Prev_PaymentType
8048      7            2

所以说如果我在现在和 10-31-01:00:00 之间查询,我希望它 return VendorID 8048 已经改变(作为奖励,它以前的 PaymentType 是2),但 VendorID 1234 不应出现,因为在 2017-10-31-01:00:00 时它是 5,现在仍然是 5,尽管有间歇性的变化。

如何查询支付类型在 2 个日期之间发生变化的 VendorID?

谢谢!

CREATE TABLE AuditTable (
    AuditID     INT,
    VendorID    INT, 
    PaymentType INT,    
    CreateDateUTC DATE
    );

INSERT INTO AuditTable VALUES
(999 ,        8048,         2,               '2017-10-30'),
(1000,        1234,         5,               '2017-10-31'),
(1001,        8048,         7,               '2017-10-31'),
(1002,        1234,         5,               '2017-10-31'),
(1003,        1234,         7,               '2017-10-31'),
(1004,        1234,         5,               '2017-11-01');

WITH CTE AS (
SELECT *,
       ROW_NUMBER () OVER (PARTITION BY CreateDateUTC ORDER BY PaymentType) AS N1

FROM AuditTable
WHERE CreateDateUTC <= '2017-11-02' AND CreateDateUTC >= '2017-10-01'
    ) ,
    MAXP AS(
            SELECT VendorID, PaymentType, CreateDateUTC  
            FROM CTE
            WHERE N1 = (SELECT MAX(N1) FROM CTE) 
        ) 
    SELECT TOP 1 MAXP.VendorID, MAXP.PaymentType AS PaymentType, CTE.PaymentType AS Prev_PaymentType
    FROM MAXP
        JOIN CTE ON CTE.VendorID = MAXP.VendorID;

结果:

+----------+-------------+------------------+
| VendorID | PaymentType | Prev_PaymentType |
+----------+-------------+------------------+
|     8048 |           7 |                2 |
+----------+-------------+------------------+

Demo

这是一个不使用 LEAD()LAG() 但使用 ROW_NUMBERCOUNT() OVER() 的变体。

查看此版本工作:SQL Fiddle

CREATE TABLE AuditTable (
      AuditID int
    , VendorID int
    , PaymentType int
    , CreateDateUTC date
);

INSERT INTO AuditTable
      VALUES (999, 8048, 2, '2017-10-30'),
      (1000, 1234, 5, '2017-10-31'),
      (1001, 8048, 7, '2017-10-31'),
      (1002, 1234, 5, '2017-10-31'),
      (1003, 1234, 7, '2017-10-31'),
      (1004, 1234, 5, '2017-11-01');

查询 1:

WITH
      rowz AS (
                  SELECT *
                        , ROW_NUMBER() OVER (PARTITION BY VendorID
                                             ORDER BY CreateDateUTC, AuditID) AS lagno
                  FROM AuditTable
            ),
      cte AS (
                  SELECT *
                        , ROW_NUMBER() OVER (PARTITION BY VendorID, CreateDateUTC
                                             ORDER BY c DESC, span_dt) rn
                  FROM (
                        SELECT  r1.AuditID, r1.VendorID, r1.CreateDateUTC
                              , r1.PaymentType AS prevpaymenttype
                              , r2.PaymentType
                              , COALESCE(r2.CreateDateUTC, CAST(GETDATE() AS date)) span_dt
                              , COUNT(*) OVER (PARTITION BY r1.VendorID, r1.CreateDateUTC, r1.PaymentType) c
                        FROM rowz r1
                        LEFT JOIN rowz r2 ON r1.VendorID = r2.VendorID
                              AND r1.lagno = r2.lagno - 1
                  ) d
            )
SELECT
      AuditID, VendorID, PrevPaymentType, PaymentType, CreateDateUTC
FROM (
      SELECT
            *
      FROM cte
      WHERE ('20171031' BETWEEN CreateDateUTC AND span_dt AND rn = 1)
      OR (CAST(GETDATE() AS date) BETWEEN CreateDateUTC AND span_dt AND rn = 1)
) d
WHERE PaymentType <> PrevPaymentType

Results:

| AuditID | VendorID | PrevPaymentType | PaymentType | CreateDateUTC |
|---------|----------|-----------------|-------------|---------------|
|     999 |     8048 |               2 |           7 |    2017-10-30 |

这是我证明有用的替代方法,使用 OUTER APPLY。请注意,AuditID 列主要用作决胜局,因为示例数据没有日期时间值。

SQL Fiddle

CREATE TABLE AuditTable (
      AuditID int
    , VendorID int
    , PaymentType int
    , CreateDateUTC date
);

INSERT INTO AuditTable
      VALUES (999, 8048, 2, '2017-10-30'),
      (1000, 1234, 5, '2017-10-31'),
      (1001, 8048, 7, '2017-10-31'),
      (1002, 1234, 5, '2017-10-31'),
      (1003, 1234, 7, '2017-10-31'),
      (1004, 1234, 5, '2017-11-01');

查询 1:

select
*
from AuditTable a
outer apply (
  select top(1) PaymentType, CreateDateUTC
  from AuditTable t
  where a.VendorID = t.VendorID
  and a.CreateDateUTC >= t.CreateDateUTC
  and a.AuditID > t.AuditID
  order by CreateDateUTC DESC, AuditID DESC
  ) oa (PrevPaymentType, PrevDate)
order by
      vendorid 
    , CreateDateUTC

Results:

| AuditID | VendorID | PaymentType | CreateDateUTC | PrevPaymentType |   PrevDate |
|---------|----------|-------------|---------------|-----------------|------------|
|    1000 |     1234 |           5 |    2017-10-31 |          (null) |     (null) |
|    1002 |     1234 |           5 |    2017-10-31 |               5 | 2017-10-31 |
|    1003 |     1234 |           7 |    2017-10-31 |               5 | 2017-10-31 |
|    1004 |     1234 |           5 |    2017-11-01 |               7 | 2017-10-31 |
|     999 |     8048 |           2 |    2017-10-30 |          (null) |     (null) |
|    1001 |     8048 |           7 |    2017-10-31 |               2 | 2017-10-30 |