How to make LAG() ignore NULLS in SQL Server?
SQL Server does not support the ignore nulls
option for window functions such as lead()
and lag()
, for which this question was a nice fit.
We can work around this with some gaps and island technique:
select
t.*,
max(past_due_col) over(partition by grp) new_past_due_col
from (
select
t.*,
sum(case when past_due_col is null then 0 else 1 end)
over(order by id) grp
from mytable t
) t
The subquery does a window sum that increments everytime a non null value is found: this defines groups of rows that contain a non-null value followed by null values.
Then, the outer uses a window max()
to retrieve the (only) non-null value in each group.
This assumes that a column can be used to order the records (I called it id
).
Demo on DB Fiddle:
ID | PAST_DUE_COL | grp | new_past_due_col
-: | :---------------------- | --: | :----------------------
1 | 91 or more days pastdue | 1 | 91 or more days pastdue
2 | null | 1 | 91 or more days pastdue
3 | null | 1 | 91 or more days pastdue
4 | 61-90 days past due | 2 | 61-90 days past due
5 | null | 2 | 61-90 days past due
6 | null | 2 | 61-90 days past due
7 | 31-60 days past due | 3 | 31-60 days past due
8 | null | 3 | 31-60 days past due
9 | 0-30 days past due | 4 | 0-30 days past due
10 | null | 4 | 0-30 days past due
11 | null | 4 | 0-30 days past due
12 | null | 4 | 0-30 days past due
Ignoring Nulls using Lag() in SQL Server 2018
If I understand your question correctly, you are getting null FLAGID
for non- null attrib_43
becuase you are using a partition by sea.ATTRIB_43
clause.
Partition by divides the query result set into partitions. The window function is applied to each partition separately and computation restarts for each partition.
That is why the null values for ATTRIB_43
are grouped into one window and the non-null ATTRIB_43
will have a separate window for each distinct value, therefore giving a NULL
for LAG()
function in the first row of each window.
you should remove the clause partition by sea.ATTRIB_43
if you want lag values for all rows.
LAG(sea.ROW_ID,1) over (order by sea.CREATED_DTTM) AS 'FLAGID'
LAG(...) IGNORE NULLS OVER (ORDER BY....)
MariaDB does not support the IGNORE NULLS
option. But, we can simulate LAG
in MariaDB or MySQL using a correlated subquery, e.g.
SELECT
id,
col1,
col2,
(SELECT t2.col1 FROM yourTable t2
WHERE t2.id < t1.id AND t2.col1 IS NOT NULL
ORDER BY t2.id DESC LIMIT 1) col1_lag
FROM yourTable t1;
Demo
Edit:
The output you are expecting in your updated question is not really a lag, but we can use similar logic to get what you want:
SELECT
claim_ts,
step,
step_no,
desired_results,
(SELECT t2.step_no FROM testTable t2
WHERE t2.claim_ts <= t1.claim_ts AND t2.step = 'MAIN'
ORDER BY t2.claim_ts DESC LIMIT 1) AS actual_results
FROM testTable t1;
Demo
LAG functions and NULLS
if it is null all the way up to the end then can take a short cut
declare @b varchar(20) = (select top 1 b from table where b is not null order by id desc);
declare @c varchar(20) = (select top 1 c from table where c is not null order by id desc);
select is, isnull(b,@b) as b, insull(c,@c) as c
from table;
SQL lag function avoid getting first row as null
An option would be to calculate the last known value from the table and use it as a default value in LAG:
DECLARE @Test TABLE (LOAD_DATE DATE, [VALUE] INT);
INSERT INTO @Test (LOAD_DATE, [VALUE])
VALUES
('2021-06-25', 25)
, ('2021-06-26', 27)
, ('2021-06-27', null)
, ('2021-06-28', 29)
;
DECLARE @LoadDate DATE = '2021-06-24';
WITH LastValue AS (
SELECT
MAX([VALUE]) AS [VALUE] /* This is to make sure, there is at least one record returned (e.g. the date is earlier than the first record in the table. */
FROM
(
SELECT TOP(1)
[VALUE]
FROM
@Test
WHERE
LOAD_DATE <= @LoadDate
ORDER BY
LOAD_DATE DESC
) X
)
SELECT
T.*
, LAG(T.VALUE, 1, LV.[VALUE]) OVER (ORDER BY T.LOAD_DATE) AS PREV_VALUE
FROM
@Test T
CROSS JOIN LastValue LV
WHERE
T.LOAD_DATE > @LoadDate
;
LAG and the first NULL
last_value
is a good idea, just add window clause:
select id, date_,
nvl(cust, last_value(cust) ignore nulls over (partition by id order by date_
rows between unbounded preceding and unbounded following)) cust
from a
order by id, date_
demo
Related Topics
Why Are Dot-Separated Prefixes Ignored in the Column List for Insert Statements
SQL Function Issue "The Last Statement Included Within a Function Must Be a Return Statement"
Using Insert into with 'Select' to Supply Some Values But Not Others (Access 2010)
How to Pass a Variable That Contains a List to a Dynamic SQL Query
Problems with Createdb in Postgres
Can SQL Server Pivot Without Knowing the Resulting Column Names
Comparing Date with Sysdate in Oracle
SQL - Update a Table Using a Field of Another Table
How to Extend the Query to Add 0 in the Cell When No Activity Is Performed
Fixing Holes/Gaps in Numbers Generated by Postgres Sequence
Returning the Value of Identity Column After Insertion in Oracle
Join/Pivot Items with Eav Table
SQL Select for All Records That May Holds Specific Value
SQL Trigger After Insert Update Another Table with Conditions
How to Create a Check Constraint on a Varchar Column in SQL Server Specifying a Minimum Data Length