Saturday 15 August 2015

sql server - Unexpected results with LAST_VALUE, CURRENT ROW, and NULLs -



sql server - Unexpected results with LAST_VALUE, CURRENT ROW, and NULLs -

i have next data:

create table #transfers ( addedon datetime2 not null, empid int not null, newdeptid int null ) insert #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)

for each row, trying recent non-null newdeptid (until row):

select *, last_value(newdeptid) on ( partition empid order iif(newdeptid null,0,1), addedon rows between unbounded preceding , current row ) currentdeptid #transfers order empid, addedon

if understand correctly, null values should excluded because first values in window -- iif(newdeptid null,0,1).

i expect following:

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

instead, order clause within last_value ignored, , null returned when current row contains 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 --

i getting same results in sql server 2012 , 2014.

is bug in sql server, or missing in window function syntax?

note: if expand window include entire partition, nulls ignored:

select *, last_value(newdeptid) on ( partition empid order iif(newdeptid null,0,1), addedon rows between unbounded preceding , unbounded next ) currentdeptid #transfers order empid, addedon

results:

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

no, have not understood well, how window functions work. rows between unbounded preceding , current row applied after order iif..., first rows ordered (first ones having null, rest) , rows ... restriction applied. so, never going work problem.

in detail, over clause creates these "windows", according partition , order by. so, illustration row addedon = '2014-02-17 00:00:00.0000000', rows between unbounded preceding , current row row above , (the 2 rows marked <------):

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 <--- last_value 2014-01-28 11:41:55.8755928 22 1 100 2014-02-16 00:00:00.0000000 22 1 37

so, currentdeptid column gets these values:

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

which re-ordered final result, according external order by

to work around problem, utilize correlated subquery:

select *, ( select top (1) newdeptid #transfers ti ti.empid = t.empid , ti.newdeptid not null , ti.addedon <= t.addedon order addedon desc ) currentdeptid #transfers t order empid, addedon ;

test @ sql-fiddle

what trying create sense if nulls ignored last_value() function. can done ignore nulls unfortuantely feature has not been yet implemented in sql-server. can see how work, in oracle (fiddle-2):

select addedon, empid, newdeptid, last_value(newdeptid) ignore nulls -- check on ( partition empid order addedon rows between unbounded preceding , current row ) currentdeptid transfers order empid, addedon ;

another way, window functions, works in sql-server, counting not-null newdeptid before current row first. can test @ fiddle-3:

with cte ( select addedon, empid, newdeptid, count(newdeptid) on ( partition empid order addedon rows between unbounded preceding , current row ) cnt transfers ) select addedon, empid, newdeptid, min(newdeptid) on (partition empid, cnt) currentdeptid cte order empid, addedon ;

sql-server sql-server-2012 window-functions sql-server-2014

No comments:

Post a Comment