UNPIVOT traduce le colonne in righe. Nel processo elimina i valori NULL ( riferimento ).
Dato l'input
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);
la query 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;
produrrà l'output
| ID | ColName | ColValue |
|----|---------|----------|
| 1 | c1 | 12 |
| 1 | c2 | 13 |
| 2 | c2 | 14 |
| 3 | c1 | 15 |
Purtroppo la riga 4 è stata completamente eliminata poiché contiene solo NULL! Può essere comodamente reintrodotto iniettando un valore fittizio nella query di origine:
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;
Aggregando le righe su ID possiamo contare i valori non nulli. Un confronto con il numero totale di colonne nella tabella di origine identificherà le righe contenenti uno o più 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;
Calcolo 3 come
numero di colonne nella tabella di origine #t
+ 1 per la colonna fittizia iniettata
- 1 per ID, che non è UNPIVOTED
Questo valore può essere ottenuto in fase di esecuzione esaminando le tabelle del catalogo.
Le righe originali possono essere recuperate unendo i risultati.
Se si devono esaminare valori diversi da NULL, questi possono essere inclusi in una clausola where:
...
) as unpvt
where ColValue <> '' -- will eliminate empty strings
Discussione
Ciò richiede un identificatore che viene portato attraverso UNPIVOT. Una chiave sarebbe la migliore. Se non esiste nessuno, può essere iniettato dalla funzione della finestra ROW_NUMBER () , sebbene questo possa essere costoso da eseguire.
Tutte le colonne devono essere esplicitamente elencate all'interno della clausola UNPIVOT. Possono essere trascinati utilizzando SSMS, come suggerito da @ db2. Non sarà dinamico quando la definizione della tabella si incerta, come sarebbe il suggerimento di Aaron Bertrand. Questo è il caso di quasi tutti gli SQL, tuttavia.
Per il mio set di dati piuttosto limitato, il piano di esecuzione è una scansione dell'indice cluster e un aggregato di flussi. Questo sarà più costoso della memoria di una semplice scansione della tabella e di molte clausole OR.