UNPIVOT tłumaczy kolumny na wiersze. W procesie eliminuje wartości NULL ( odniesienie ).
Biorąc pod uwagę wkład
create table #t
(
ID int primary key,
c1 int null,
c2 int null
);
insert #t(id, c1, c2)
values
(1, 12, 13),
(2, null, 14),
(3, 15, null),
(4, null, null);
zapytanie UNPIVOT
select
ID, ColName, ColValue
from
(
select *
from #t
) as p
unpivot
(
ColValue for ColName in
(c1, c2) -- explicit source column names required
) as unpvt;
wytworzy wynik
| ID | ColName | ColValue |
|----|---------|----------|
| 1 | c1 | 12 |
| 1 | c2 | 13 |
| 2 | c2 | 14 |
| 3 | c1 | 15 |
Niestety rząd 4 został całkowicie wyeliminowany, ponieważ ma tylko NULL! Można go wygodnie ponownie wprowadzić, wprowadzając wartość fikcyjną do zapytania źródłowego:
select
ID, ColName, ColValue
from
(
select
-5 as dummy, -- injected here, -5 is arbitrary
*
from #t
) as p
unpivot
(
ColValue for ColName in
(dummy, c1, c2) -- referenced here
) as unpvt;
Agregując wiersze według identyfikatora, możemy policzyć wartości inne niż null. Porównanie całkowitej liczby kolumn w tabeli źródłowej pozwoli zidentyfikować wiersze zawierające co najmniej jedną wartość NULL.
select
ID
from
(
select -5 as dummy, *
from #t
) as p
unpivot
(
ColValue for ColName in
(dummy, c1, c2)
) as unpvt
group by ID
having COUNT(*) <> 3;
Obliczam 3 jako liczbę kolumn w tabeli źródłowej #t
+ 1 dla wstrzykiwanej kolumny obojętnej
- 1 dla identyfikatora, który nie jest UNPIVOTED
Wartość tę można uzyskać w czasie wykonywania, sprawdzając tabele katalogu.
Oryginalne wiersze można odzyskać, łącząc się z wynikami.
Jeżeli mają być badane wartości inne niż NULL, można je włączyć do klauzuli where:
...
) as unpvt
where ColValue <> '' -- will eliminate empty strings
Dyskusja
Wymaga to identyfikatora przenoszonego przez UNPIVOT. Klucz byłby najlepszy. Jeśli nie istnieje, można wprowadzić ROW_NUMBER () funkcji okna , choć jego wykonanie może być kosztowne.
Wszystkie kolumny muszą być wyraźnie wymienione w klauzuli UNPIVOT. Można je przeciągać za pomocą SSMS, jak sugeruje @ db2. Nie będzie dynamiczny, gdy zmieni się definicja tabeli, jak sugerowałaby Aaron Bertrand. Jest tak jednak w przypadku prawie wszystkich SQL.
W przypadku mojego raczej ograniczonego zestawu danych plan wykonania to skanowanie indeksu klastrowego i agregacja strumienia. Będzie to droższe w pamięci niż zwykły skan tabeli i wiele klauzul OR.