Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 具有最后一个_值、当前行和空值的意外结果_Sql Server_Sql Server 2012_Window Functions_Sql Server 2014 - Fatal编程技术网

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
with
ROWS-BETWEEN-AND-CURRENT-ROW
将始终返回当前行的值?正如
FIRST\u VALUE
with
ROWS-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 ;