我有以下数据:
CREATE TABLE #Transfers (
AddedOn DATETIME2 NOT NULL,
EmpID INT NOT NULL,
NewDeptID INT NULL
)
INSERT INTO #Transfers
VALUES
('2013-12-17 17:18:54.3499987', 19, 36),
('2013-12-18 13:02:34.1168087', 19, NULL),
('2014-01-28 11:41:55.8755928', 22, 100),
('2014-02-05 10:36:36.3645703', 22, NULL),
('2014-02-16 00:00:00.0000000', 22, 37),
('2014-02-17 00:00:00.0000000', 22, NULL)
对于每一行,我试图获取最新的非空NewDeptID
(直到该行):
SELECT *,
LAST_VALUE(NewDeptID) OVER (
PARTITION BY EmpID
ORDER BY IIF(NewDeptID IS NULL,0,1), AddedOn
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS CurrentDeptID
FROM #Transfers
ORDER BY EmpID, AddedOn
如果我理解正确,应排除空值,因为它们是窗口中的第一个值 - IIF(NewDeptID IS NULL,0,1)
。
我希望如下:
AddedOn EmpID NewDeptID CurrentDeptID
2013-12-17 17:18:54.3499987 19 36 36
2013-12-18 13:02:34.1168087 19 NULL 36
2014-01-28 11:41:55.8755928 22 100 100
2014-02-05 10:36:36.3645703 22 NULL 100
2014-02-16 00:00:00.0000000 22 37 37
2014-02-17 00:00:00.0000000 22 NULL 37
而是忽略LAST_VALUE中的ORDER BY子句,当前行包含NULL时返回NULL:
AddedOn EmpID NewDeptID CurrentDeptID
2013-12-17 17:18:54.3499987 19 36 36
2013-12-18 13:02:34.1168087 19 NULL NULL --
2014-01-28 11:41:55.8755928 22 100 100
2014-02-05 10:36:36.3645703 22 NULL NULL --
2014-02-16 00:00:00.0000000 22 37 37
2014-02-17 00:00:00.0000000 22 NULL NULL --
我在SQL Server 2012和2014中获得了相同的结果。
这是SQL Server中的错误,还是我在窗口函数语法中遗漏了什么?
注意:如果我展开窗口以包含整个分区,则忽略NULL:
SELECT *,
LAST_VALUE(NewDeptID) OVER (
PARTITION BY EmpID
ORDER BY IIF(NewDeptID IS NULL,0,1), AddedOn
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
) AS CurrentDeptID
FROM #Transfers
ORDER BY EmpID, AddedOn
结果:
AddedOn EmpID NewDeptID CurrentDeptID
2013-12-17 17:18:54.3499987 19 36 36
2013-12-18 13:02:34.1168087 19 NULL 36
2014-01-28 11:41:55.8755928 22 100 37
2014-02-05 10:36:36.3645703 22 NULL 37
2014-02-16 00:00:00.0000000 22 37 37
2014-02-17 00:00:00.0000000 22 NULL 37
答案 0 :(得分:3)
不,你还不太清楚,窗口功能是如何工作的。 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
在ORDER BY IIF...
后应用,因此首先排序行(首先是NULL
行,然后是所有其余行),然后是{{ 1}}限制被应用。所以,这对你的问题永远不会有用。
详细信息,ROWS ...
子句会根据OVER
和PARTITION
创建这些" windows"。
因此,例如对于ORDER BY
行,AddedOn = '2014-02-17 00:00:00.0000000'
是上面的行和它自己(标有ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
的两行):
<------
因此,AddedOn EmpID IIF() NewDeptID
-- partition EmpID = 19
2013-12-18 13:02:34.1168087 19 0 NULL
2013-12-17 17:18:54.3499987 19 1 36
-- partition EmpID = 22
2014-02-05 10:36:36.3645703 22 0 NULL <---
2014-02-17 00:00:00.0000000 22 0 NULL <--- this is the LAST_VALUE
2014-01-28 11:41:55.8755928 22 1 100
2014-02-16 00:00:00.0000000 22 1 37
列会获得以下值:
CurrentDeptID
然后根据外部AddedOn EmpID IIF() NewDeptID CurrentDeptID
-- partition EmpID = 19
2013-12-18 13:02:34.1168087 19 0 NULL NULL
2013-12-17 17:18:54.3499987 19 1 36 36
-- partition EmpID = 22
2014-02-05 10:36:36.3645703 22 0 NULL NULL
2014-02-17 00:00:00.0000000 22 0 NULL NULL
2014-01-28 11:41:55.8755928 22 1 100 100
2014-02-16 00:00:00.0000000 22 1 37 37
要解决此问题,可以使用相关子查询:
ORDER BY
进行测试
如果SELECT *,
( SELECT TOP (1) NewDeptID
FROM #Transfers AS ti
WHERE ti.EmpID = t.EmpID
AND ti.NewDeptID IS NOT NULL
AND ti.AddedOn <= t.AddedOn
ORDER BY AddedOn DESC
) AS CurrentDeptID
FROM #Transfers AS t
ORDER BY EmpID, AddedOn ;
函数可以忽略空值,那么您尝试做的事实际上是有意义的。这可以通过 LAST_VALUE()
来完成,但遗憾的是,此功能尚未在SQL-Server中实现。您可以在 Oracle (fiddle-2) :
IGNORE NULLS
使用在SQL-Server中工作的窗口函数的另一种方法是首先计算当前行之前的非空SELECT AddedOn, EmpID, NewDeptID,
LAST_VALUE(NewDeptID)
IGNORE NULLS -- check this
OVER (
PARTITION BY EmpID
ORDER BY AddedOn
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS CurrentDeptID
FROM Transfers
ORDER BY EmpID, AddedOn ;
。您可以在 fiddle-3 :
NewDeptID