Verifica se le colonne sono NULL


16

Sto cercando di capire una query semplice che posso fare per verificare se una tabella di grandi dimensioni ha un elenco di voci che ha almeno UN valore vuoto (NULL / vuoto) in QUALSIASI colonna.

Ho bisogno di qualcosa del genere

SELECT * FROM table AS t WHERE ANY(t.* IS NULL)

Non voglio fare

SELECT * FROM table AS t WHERE t.c1 = NULL OR t.c2 = NULL OR t.c3 = NULL

Questa sarebbe una query ENORME.

Risposte:


16

Un'estensione alla risposta di @ db2 con meno (leggi: zero) wrangling:

DECLARE @tb nvarchar(512) = N'dbo.[table]';

DECLARE @sql nvarchar(max) = N'SELECT * FROM ' + @tb
    + ' WHERE 1 = 0';

SELECT @sql += N' OR ' + QUOTENAME(name) + ' IS NULL'
    FROM sys.columns 
    WHERE [object_id] = OBJECT_ID(@tb);

EXEC sys.sp_executesql @sql;

8

Dovresti elencare tutte le colonne come da commento di JNK.

WHERE c1 IS NULL OR c2 IS NULL OR c3 IS NULL

Un approccio un po 'meno efficiente che evita questo è però sotto.

;WITH xmlnamespaces('http://www.w3.org/2001/XMLSchema-instance' AS ns) 
SELECT * 
FROM   YourTable AS T1 
WHERE (
    SELECT T1.* 
    FOR XML PATH('row'), ELEMENTS XSINIL, TYPE
  ).exist('//*/@ns:nil') = 1 

(Basato su questa risposta SO)


5

Non esiste una bella sintassi integrata, ma Management Studio ha un paio di utili funzioni per generare rapidamente la query.

In Esplora oggetti, eseguire il drill-down fino alla tabella desiderata, espanderla, quindi trascinare l'intera cartella "Colonne" in un editor di query vuoto. Ciò aggiungerà un elenco di colonne separato da virgole alla query.

Quindi, apri Trova e sostituisci. Impostare "Trova cosa" su ,e impostare "Sostituisci con" su IS NULL OR(con uno spazio iniziale), quindi premere Sostituisci tutto. Dovrai ripulire manualmente l'ultimo nella sequenza.

È ancora brutto, ma è meno brutto ad alta intensità di manodopera.


4

Soluzioni multiple per: alcuni null, tutti i null, colonne singole e multiple più rendendolo VELOCE usando Top 1

Se è necessario testare più colonne, è possibile utilizzare quanto segue:

Column_1 Column_2 Column_3
-------- -------- --------
1        2        NULL
1        NULL     NULL
5        6        NULL

Innanzitutto , verifica i NULL e contali:

select 
    sum(case when Column_1 is null then 1 else 0 end) as Column_1, 
    sum(case when Column_2 is null then 1 else 0 end) as Column_2, 
    sum(case when Column_3 is null then 1 else 0 end) as Column_3,
from TestTable 

Produce un conteggio di NULL:

Column_1  Column_2  Column_3
0         1         3

Dove il risultato è 0, non ci sono NULL.

In secondo luogo , contiamo i non-NULL:

select 
    sum(case when Column_1 is null then 0 else 1 end) as Column_1, 
    sum(case when Column_2 is null then 0 else 1 end) as Column_2, 
    sum(case when Column_3 is null then 0 else 1 end) as Column_3,
from TestTable

... Ma poiché qui stiamo contando non NULL, questo può essere semplificato per:

select 
    count(Column_1) as Column_1, 
    count(Column_2) as Column_2, 
    count(Column_3) as Column_3,
from TestTable

Uno dei due produce:

Column_1  Column_2  Column_3
3         2         0

Dove il risultato è 0, la colonna è interamente composta da NULL.

Infine , se hai solo bisogno di controllare una colonna specifica, TOP 1 è più veloce perché dovrebbe fermarsi al primo colpo. È quindi possibile utilizzare facoltativamente count (*) per ottenere un risultato in stile booleano:

select top 1 'There is at least one NULL' from TestTable where Column_3 is NULL

select count(*) from (select top 1 'There is at least one NULL' AS note from TestTable where Column_3 is NULL) a

0 = Non ci sono NULL, 1 = C'è almeno un NULL

o

select top 1 'There is at least one non-NULL' AS note from TestTable where Column_3 is not NULL

select count(*) from (select top 1 'There is at least one non-NULL' AS note from TestTable where Column_3 is not NULL) a

0 = Sono tutti NULL, 1 = C'è almeno un non NULL

Spero che questo possa essere d'aiuto.


Mentre questo sembra abbastanza utile, sento l'obbligo di notare che non è ciò che l'OP stava chiedendo: volevano il contenuto di ogni riga che includeva un valore NULL, non solo un controllo per vedere se ne esistesse.
RDFozz,

Giusto. Penso che lo stavo leggendo in modo diverso. Mi sono concentrato sul "... test se un grande tavolo ha ..." parte, quindi ... Booleano (nel mio caso booleano). Ma se, per "elenco di voci", intendeva le righe, allora hai assolutamente ragione.
lupo

Ho appena rivisto questo. Ho sicuramente frainteso la domanda - avrei dovuto dedurre che stava cercando le righe come risultato. Penso di aver letto male anche quello che intendeva con ENORME. Inizialmente pensavo che significasse computazionalmente costoso, ma ora penso solo che abbia significato largo con le colonne, quindi Arron e DB2 hanno fatto bene, sia nella lettura che nelle soluzioni (a seconda di quale è più stanco: il cervello o le dita)
jwolf

2

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.