扩展枢轴

Extending a Pivot

我有一个文档 table 和一个事件 table。

一个文档可能有零个或多个这些事件类型的事件:

 DocID  | EventType | EventDate | UserID
-----------------------------------------------
    1   |    0      | 1-2-2017  |  123  
    1   |    1      | 1-3-2017  |  456
    1   |    1      | 1-4-2017  |  489
    1   |    2      | 1-5-2017  |  357
    2   |    0      | 1-6-2017  |  951
    2   |    1      | 1-7-2017  |  654
    2   |    2      | 1-8-2017  |  654
    2   |    3      | 1-9-2017  |  357

旋转事件 table 很简单:

SELECT DocID, [0] AS CreatedDate, [1] AS ModifiedDate,
              [2] AS SubmittedDate, [3] AS ApprovedDate
FROM (SELECT DocID, EventType, EventDate FROM Events
WHERE DocID IS NOT NULL AND EventDate IS NOT NULL) AS DocEvents
PIVOT (MAX(EventDate) FOR EventType IN ([0], [1], [2], [3]))
AS DocEventsPivot

出于我的目的,需要给定类型的最新事件,因此 MAX 聚合:

DocID | CreatedDate | ModifiedDate | SubmittedDate | ApprovedDate
-----------------------------------------------------------------
  1   |   1-2-2017  |    1-4-2017  |    1-5-2017   |     NULL
  2   |   1-6-2017  |    1-7-2017  |    1-8-2017   |   1-9-2017

如何将 UserID 转换为 CreatedBy、ModifiedBy、SubmittedBy 和 ApprovedBy 以对应于相应事件类型的日期?

我不会提前知道UserID的可能取值。

期望的输出:

DocID | CreatedDate | ModifiedDate | SubmittedDate | ApprovedDate | CreatedBy | ModifiedBy | SubmittedBy | ApprovedBy
---------------------------------------------------------------------------------------------------------------------
  1   |   1-2-2017  |    1-4-2017  |    1-5-2017   |     NULL     |    123    |    489     |     357     |    NULL
  2   |   1-6-2017  |    1-7-2017  |    1-8-2017   |   1-9-2017   |    951    |    654     |     654     |    657

不是使用 PIVOT,而是使用 OUTER APPLY.

的另一种解决方案
CREATE TABLE #Documents (ID int)
CREATE TABLE #Events (DocID int, EventType int, EventDate date, UserID int)

INSERT INTO #Documents VALUES
(1),
(2)

INSERT INTO #Events VALUES
(1, 0, '1-2-2017', 123),  
(1, 1, '1-3-2017', 456),
(1, 1, '1-4-2017', 489),
(1, 2, '1-5-2017', 357),
(2, 0, '1-6-2017', 951),
(2, 1, '1-7-2017', 654),
(2, 2, '1-8-2017', 654),
(2, 3, '1-9-2017', 357)

SELECT
    DOC.ID AS 'DocID',
    CRT.EventDate AS 'CreatedDate',
    MFY.EventDate AS 'ModifiedDate',
    SUB.EventDate AS 'SubmittedDate',
    APR.EventDate AS 'ApprovedDate',
    CRT.UserID AS 'CreatedBy',
    MFY.UserID AS 'ModifiedBy',
    SUB.UserID AS 'SubmittedBy',
    APR.UserID AS 'ApprovedBy'
FROM 
    #Documents AS DOC
    OUTER APPLY (SELECT TOP 1 EventDate, UserID FROM #Events WHERE DocID = DOC.ID AND EventType = 0 ORDER BY EventDate DESC) AS CRT
    OUTER APPLY (SELECT TOP 1 EventDate, UserID FROM #Events WHERE DocID = DOC.ID AND EventType = 1 ORDER BY EventDate DESC) AS MFY
    OUTER APPLY (SELECT TOP 1 EventDate, UserID FROM #Events WHERE DocID = DOC.ID AND EventType = 2 ORDER BY EventDate DESC) AS SUB
    OUTER APPLY (SELECT TOP 1 EventDate, UserID FROM #Events WHERE DocID = DOC.ID AND EventType = 3 ORDER BY EventDate DESC) AS APR

DROP TABLE #Documents
DROP TABLE #Events

尝试以下方法

CREATE TABLE #Events (DocID int, EventType int, EventDate date, UserID int)

INSERT INTO #Events VALUES
(1, 0, '1-2-2017', 123),  
(1, 1, '1-3-2017', 456),
(1, 1, '1-4-2017', 489),
(1, 2, '1-5-2017', 357),
(1, 2, '1-4-2017', 666),
(2, 0, '1-6-2017', 951),
(2, 1, '1-7-2017', 654),
(2, 2, '1-8-2017', 654),
(2, 3, '1-9-2017', 357)

SELECT
  DocID,
  MAX(CASE WHEN EventType=0 THEN EventDate END) [CreatedDate],
  MAX(CASE WHEN EventType=1 THEN EventDate END) [ModifiedDate],
  MAX(CASE WHEN EventType=2 THEN EventDate END) [SubmittedDate],
  MAX(CASE WHEN EventType=3 THEN EventDate END) [ApprovedDate],
  MAX(CASE WHEN EventType=0 THEN LastUserID END) [CreatedBy],
  MAX(CASE WHEN EventType=1 THEN LastUserID END) [ModifiedBy],
  MAX(CASE WHEN EventType=2 THEN LastUserID END) [SubmittedBy],
  MAX(CASE WHEN EventType=3 THEN LastUserID END) [ApprovedBy]
FROM
  (
    SELECT
      DocID,
      EventDate,
      EventType,
      LAST_VALUE(UserID)OVER(
                              PARTITION BY DocID,EventType
                              ORDER BY EventDate
                              ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                            ) LastUserID
    FROM #Events
  ) q
GROUP BY DocID


DROP TABLE #Events

或者您可以使用 IFF 而不是 CASE。我更喜欢使用 CASE 因为它不是块 ELSE

SELECT
  DocID,
  MAX(IIF(EventType=0,EventDate,NULL)) [CreatedDate],
  MAX(IIF(EventType=1,EventDate,NULL)) [ModifiedDate],
  MAX(IIF(EventType=2,EventDate,NULL)) [SubmittedDate],
  MAX(IIF(EventType=3,EventDate,NULL)) [ApprovedDate],
  MAX(IIF(EventType=0,LastUserID,NULL)) [CreatedBy],
  MAX(IIF(EventType=1,LastUserID,NULL)) [ModifiedBy],
  MAX(IIF(EventType=2,LastUserID,NULL)) [SubmittedBy],
  MAX(IIF(EventType=3,LastUserID,NULL)) [ApprovedBy]
FROM
  (
    SELECT
      DocID,
      EventDate,
      EventType,
      LAST_VALUE(UserID)OVER(
                              PARTITION BY DocID,EventType
                              ORDER BY EventDate
                              ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
                            ) LastUserID
    FROM #Events
  ) q
GROUP BY DocID