Sql server 具有最后一个_值、当前行和空值的意外结果
我有以下数据:Sql server 具有最后一个_值、当前行和空值的意外结果,sql-server,sql-server-2012,window-functions,sql-server-2014,Sql Server,Sql Server 2012,Window Functions,Sql Server 2014,我有以下数据: 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-
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
(直到该行):
如果我理解正确,应该排除null值,因为它们是窗口中的第一个值--IIF(NewDeptID为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
相反,忽略最后一个_值中的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中的一个错误,还是我在窗口函数语法中遗漏了什么
注意:如果我扩展窗口以包括整个分区,则将忽略空值:
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
不,您还没有很好地理解窗口函数是如何工作的。在IIF…对
进行排序之后,应用前一行和当前行之间无界的行
,因此首先对行进行排序(首先是具有NULL的行,然后是所有其他行),然后应用行…
限制。所以,这永远不会解决你的问题
具体地说,OVER
子句根据分区和排序依据创建这些“窗口”
因此,例如,对于带有AddedOn='2014-02-17 00:00:00.0000000'
的行,无界前一行和当前行之间的行是上面的行和它本身(用标记的两行我不明白。如果先应用ORDER BY
,则分区内第一个为空值的记录。当计算分区内直到当前行的最后一个值时,结果永远不应为空,除非分区中以前所有记录的值也为空。Bu你不是这么说的吗,“具有空值的记录首先在分区内”。如果一行有空值,那么它前面的所有行也有空值。当我编写orderby
时,我指的是orderby IIF…
,而不是外部orderby。你的IIF()
不允许这样做(所有非空行放在所有空行之后)。我编辑了我的答案,其中包含了有关windows如何工作的详细信息。因此,LAST\u VALUE
withROWS-BETWEEN-AND-CURRENT-ROW
将始终返回当前行的值?正如FIRST\u VALUE
withROWS-BETWEEN-BETWEEN-AND…
一样?是的,thnx。更正。(是的,与前面的问题完全相同)
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
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
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
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 ;
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 ;
WITH cte AS
( SELECT AddedOn, EmpID, NewDeptID,
COUNT(NewDeptID) OVER (
PARTITION BY EmpID
ORDER BY AddedOn
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cnt
FROM Transfers
)
SELECT AddedOn, EmpID, NewDeptID,
MIN(NewDeptID) OVER (PARTITION BY EmpID, cnt) AS CurrentDeptID
FROM cte
ORDER BY EmpID, AddedOn ;