Jak wiesz, funkcje analityczne LAG() & LEAD() uzyskują dostęp do danych z poprzedniego i następnego wiersza w tym samym zbiorze wyników bez użycia samołączenia. Ale czy możliwe jest zignorowanie wartości NULL przed uzyskaniem dostępu do wartości NOT NULL?Czy można zignorować wartości NULL podczas korzystania z funkcji LAG() i LEAD() w SQL Server?
Odpowiedz
Oracle 11 obsługuje opcję ignore nulls
, która wykonuje dokładnie to, co chcesz. Oczywiście, twoje pytanie dotyczy serwera SQL Server, ale czasami jest niezmiernie miło wiedzieć, że funkcjonalność istnieje gdzieś.
Możliwe jest zasymulowanie tej funkcji. Chodzi o to, aby przypisać wartości zerowe do grupy, w oparciu o poprzednią wartość. W gruncie rzeczy liczy się liczba wartości innych niż null przed nim. Możesz to zrobić ze skorelowanym podzapytaniem. Lub, co ciekawsze, z różnicą dwóch numerów wierszy. Następnie w grupie możesz po prostu użyć max()
.
Myślę, że następujące rzeczy robią to, co chcesz. Zakładamy, że col
zawiera NULL
wartości i ordering
ma zamawianie wierszy:
select t.*,
max(col) over (partition by grp) as LagOnNull
from (select t.*,
(row_number() over (order by ordering) -
row_number() over (partition by col order by ordering)
) as grp
from table t
) t;
lead()
jest podobny, ale kolejność jest odwrotna. Będzie to działać z dodatkowymi kluczami do partycjonowania, ale musisz dodać je do wszystkich wyrażeń okna.
Możliwość korzystania z funkcji okna. Czytanie tego article przez Itzik Ben-Gan po więcej szczegółów.
W poniższym kodzie wartość cte pobiera ostatnią wartość NOT NOT NULL, następnie następny wybiera wartość rzeczywistą kolumny. W tym przykładzie użyto LAG. np.
-- DDL for T1
SET NOCOUNT ON;
USE tempdb;
IF OBJECT_ID(N'dbo.T1', N'U') IS NOT NULL DROP TABLE dbo.T1;
GO
CREATE TABLE dbo.T1
(
id INT NOT NULL CONSTRAINT PK_T1 PRIMARY KEY,
col1 INT NULL
);
-- Small set of sample data
TRUNCATE TABLE dbo.T1;
INSERT INTO dbo.T1(id, col1) VALUES
(2, NULL),
(3, 10),
(5, -1),
(7, NULL),
(11, NULL),
(13, -12),
(17, NULL),
(19, NULL),
(23, 1759);
;WITH C AS
(
SELECT
id,
col1,
MAX(CASE WHEN col1 IS NOT NULL THEN id END) OVER(ORDER BY id ROWS UNBOUNDED PRECEDING) AS grp
FROM dbo.T1
)
SELECT
id,
col1,
(SELECT col1 FROM dbo.T1 WHERE id = grp) lastval
FROM C;
Dzięki za odpowiedź Gordon. Ale nie mogę zrozumieć whats "col2" w tym przykładzie? – Mostapha777
'col2' powinno być' col', argumentem funkcji 'lag()'/'lead()'. –
Kreatywne rozwiązanie Gordon. Ale niestety nie zadziałało to dla mnie :( – Mostapha777