Uji apakah ada kolom NULL

16

Saya mencoba mencari tahu kueri mudah yang bisa saya lakukan untuk menguji apakah tabel besar memiliki daftar entri yang memiliki setidaknya SATU nilai kosong (NULL / kosong) di kolom APA PUN.

Saya butuh sesuatu seperti

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

Saya tidak mau harus melakukan

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

Ini akan menjadi permintaan BESAR.

Dexter
sumber

Jawaban:

16

Ekstensi ke jawaban @ db2 dengan sedikit (baca: nol) perselisihan dengan tangan:

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;
Aaron Bertrand
sumber
8

Anda harus mencantumkan semua kolom sesuai komentar JNK.

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

Pendekatan yang agak kurang efisien yang menghindari ini ada di bawah ini.

;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 

(Berdasarkan jawaban SO ini)

Martin Smith
sumber
5

Tidak ada sintaks bawaan yang bagus, tetapi Management Studio memiliki beberapa fitur mudah untuk menghasilkan kueri dengan cepat.

Di Object Explorer, telusuri tabel yang Anda inginkan, perluas, lalu seret seluruh folder "Kolom" ke dalam editor kueri kosong. Ini akan menambahkan daftar kolom yang dipisahkan koma ke kueri.

Selanjutnya, buka Temukan Dan Ganti. Setel "Temukan Apa" ,dan setel "Ganti Dengan" ke IS NULL OR(dengan spasi terkemuka) lalu tekan Ganti Semua. Anda harus membersihkan yang terakhir secara berurutan dengan tangan.

Ini masih jelek, tapi kurang padat karya.

db2
sumber
4

Beberapa Solusi untuk: beberapa nol, semua nol, satu & beberapa kolom ditambah menjadikannya CEPAT menggunakan Top 1

Jika Anda perlu menguji beberapa kolom, Anda dapat menggunakan yang berikut:

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

Pertama , uji NULL dan hitung:

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 

Menghasilkan hitungan NULLs:

Column_1  Column_2  Column_3
0         1         3

Di mana hasilnya adalah 0, tidak ada NULL.

Kedua , mari kita hitung 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

... Tetapi karena kami menghitung non-NULL di sini, ini dapat disederhanakan menjadi:

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

Salah satu hasil:

Column_1  Column_2  Column_3
3         2         0

Di mana hasilnya adalah 0, kolom seluruhnya terdiri dari NULL.

Terakhir , jika Anda hanya perlu memeriksa kolom tertentu, maka TOP 1 lebih cepat karena harus berhenti pada klik pertama. Anda kemudian dapat secara opsional menggunakan count (*) untuk memberikan hasil gaya boolean:

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 = Tidak ada NULL, 1 = Setidaknya ada satu NULL

atau

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 = Semuanya NULL, 1 = Setidaknya ada satu NULL

Saya harap ini membantu.

jwolf
sumber
Meskipun ini tampaknya cukup berguna, saya merasa berkewajiban untuk mencatat bahwa itu bukan apa yang diminta OP - mereka menginginkan isi dari setiap baris yang termasuk nilai NULL, bukan hanya pemeriksaan untuk melihat apakah ada.
RDFozz
Cukup adil. Saya pikir saya hanya membacanya secara berbeda. Saya fokus pada bagian "... tes jika meja besar memiliki ...", jadi ... Boolean (dalam kasus saya Boolean-ish). Tetapi jika, dengan "daftar entri", maksudnya adalah baris, maka Anda benar sekali.
jwolf
Tinjau kembali ini. Saya pasti salah menafsirkan pertanyaan - seharusnya menyimpulkan bahwa ia sedang mencari baris sebagai hasilnya. Saya pikir saya juga salah membaca apa yang dia maksud dengan BESAR. Awalnya saya pikir dia berarti komputasi mahal tapi sekarang saya hanya berpikir dia berarti lebar dengan kolom sehingga Arron dan DB2 melakukannya dengan benar, baik dalam bacaan dan solusi (tergantung mana yang lebih lelah: otak atau jari Anda)
jwolf
2

UNPIVOT menerjemahkan kolom menjadi baris. Dalam prosesnya menghilangkan nilai NULL ( referensi ).

Diberikan 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);

permintaan 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;

akan menghasilkan output

| ID | ColName | ColValue |
|----|---------|----------|
| 1  | c1      | 12       |
| 1  | c2      | 13       |
| 2  | c2      | 14       |
| 3  | c1      | 15       |

Sayangnya baris 4 telah dihilangkan seluruhnya karena hanya memiliki NULL! Itu dapat dengan mudah diperkenalkan kembali dengan menyuntikkan nilai dummy ke dalam kueri sumber:

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;

Dengan menjumlahkan baris pada ID kita dapat menghitung nilai-nilai yang bukan nol. Perbandingan dengan jumlah total kolom dalam tabel sumber akan mengidentifikasi baris yang berisi satu atau lebih 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;

Saya menghitung 3 sebagai
jumlah kolom dalam tabel sumber #t
+ 1 untuk kolom dummy yang disuntikkan
- 1 untuk ID, yang tidak UNPIVOTED

Nilai ini dapat diperoleh saat runtime dengan memeriksa tabel katalog.

Baris asli dapat diambil dengan bergabung ke hasilnya.

Jika nilai selain NULL ingin diselidiki, nilai itu dapat dimasukkan dalam klausa where:

...
) as unpvt
where ColValue <> ''      -- will eliminate empty strings

Diskusi

Ini membutuhkan pengenal yang dilakukan melalui UNPIVOT. Kunci akan menjadi yang terbaik. Jika tidak ada, dapat disuntikkan oleh ROW_NUMBER () fungsi jendela , meskipun ini mungkin mahal untuk dieksekusi.

Semua kolom harus dicantumkan secara eksplisit di dalam klausa UNPIVOT. Mereka dapat diseret menggunakan SSMS, seperti yang disarankan @ db2. Itu tidak akan dinamis ketika definisi tabel chagnes, seperti saran Aaron Bertrand. Ini adalah kasus untuk hampir semua SQL.

Untuk set data saya yang agak terbatas, rencana eksekusi adalah scan indeks berkerumun dan agregat aliran. Memori ini akan lebih mahal daripada pemindaian langsung tabel dan banyak klausa ATAU.

Michael Green
sumber