Sql-Server

使用視窗函式繼承非空值?

  • February 13, 2020

在 SQL Server 中,我經常看到這被稱為“塗抹”,並且有關於使用“古怪更新”來做到這一點的部落格文章。但是我將如何使用視窗函式來做到這一點。例如,如果我有:

name     date   happiness
----     ----   ---------
John     1/3    20
John     1/4    NULL
John     1/5    NULL
John     1/6    NULL
John     1/7    18
Mary     1/2    35
Mary     1/3    NULL
Mary     1/4    -15
Mary     1/6    NULL
Mary     1/7    0

有沒有辦法做類似的事情:

SELECT
   [name],
   [date],
   CARRY([happiness]) OVER (PARTITION BY [name] ORDER BY [date])

這樣中間結果看起來像:

name     date   happiness
----     ----   ---------
John     1/3    20
John     1/4    20
John     1/5    20
John     1/6    20
John     1/7    18
Mary     1/2    35
Mary     1/3    35
Mary     1/4    -15
Mary     1/6    -15
Mary     1/7    0

CARRY顯然不是一個真正的功能,只是想要那個功能。

您也可以使用APPLY()運算符來獲取"last" not null happiness

SELECT *
FROM   [Data] d
      CROSS APPLY
      (
          SELECT TOP 1 happiness
          FROM   [Data] x
          WHERE  x.[name]  = d.[name]
          AND    x.[date] <= d.[date]
          AND    x.happiness IS NOT NULL
          ORDER BY x.[date] DESC
      ) h

您可以使用遞歸 CTE 和 COALESCE 來返回最新的非 NULL 值。請參閱此小提琴以獲取工作範例。

在範例中,我首先使用 CTE 創建一個偽 ID 列以用於遞歸 CTE。然後在遞歸 CTE 中,我們選擇 ID = 1 行(最早的行)作為錨點,並為每個名稱組遞歸地按 ID 選擇下一行。如果目前值為 NULL 表示幸福,則 COALESCE 函式將選擇先前的值。

詢問:

;WITH DataC AS(
 SELECT ROW_NUMBER() OVER (PARTITION BY name ORDER BY date) AS ID,
   [name],
   [date],
   [happiness]
 FROM Data
), CTE AS (
 SELECT ID,
   [name],
   [date],
   [happiness]
 FROM DataC
 WHERE ID = 1
 UNION ALL
 SELECT d.ID,
   d.[name],
   d.[date],
   COALESCE(d.[happiness], c.happiness) AS happiness
 FROM DataC d
 INNER JOIN CTE c ON c.Name = d.Name AND c.ID = d.ID - 1
)

SELECT * 
FROM CTE
ORDER BY name, date

結果:

ID  name    date                        happiness
-------------------------------------------------
1   John    2020-01-03 00:00:00.000     20
2   John    2020-01-04 00:00:00.000     20
3   John    2020-01-05 00:00:00.000     20
4   John    2020-01-06 00:00:00.000     20
5   John    2020-01-07 00:00:00.000     18
1   Mary    2020-01-01 00:00:00.000     35
2   Mary    2020-01-02 00:00:00.000     35
3   Mary    2020-01-03 00:00:00.000     -15
4   Mary    2020-01-04 00:00:00.000     -15
5   Mary    2020-01-05 00:00:00.000     0

引用自:https://dba.stackexchange.com/questions/259554