Перевірте, чи немає стовпців NULL


16

Я намагаюся розібрати простий запит, який я можу зробити, щоб перевірити, чи є у великій таблиці список записів, у якому В будь-якому стовпці є принаймні ОДНЕ пусте (NULL / порожнє) значення.

Мені потрібно щось на кшталт

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

Я не хочу цього робити

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

Це був би ВЕЛИЧИЙ запит.

Відповіді:


16

Розширення до відповіді @ db2 з меншим (читати: нуль) рукостисканням:

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

Ви повинні перелічити всі стовпці згідно з коментарем JNK.

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

Дещо менш ефективний підхід, який уникає цього, є нижче.

;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 

(На основі цієї відповіді ТА)


5

Немає приємного вбудованого синтаксису, але Management Studio має пару зручних функцій для швидкого генерування запиту.

У «Об’єкті» виберіть потрібну таблицю, розгорніть її, а потім перетягніть всю папку «Стовпці» в порожній редактор запитів. Це додасть до запиту розділений комою список стовпців.

Далі відкрийте «Знайти та замінити». Встановіть "Знайти що" ,і встановіть "Замінити на" на IS NULL OR(з провідним простором), а потім натисніть Замінити всіх. Вам доведеться очистити останній у послідовності вручну.

Це все ще потворно, але менш трудомістко потворно.


4

Кілька рішень для: декількох нулів, усіх нулів, одинарних та декількох стовпців, а також зробити це Швидко за допомогою Top 1

Якщо вам потрібно протестувати кілька стовпців, ви можете використовувати наступне:

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

Спочатку протестуйте на NULL і підраховуйте їх:

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 

Виходить кількість NULL:

Column_1  Column_2  Column_3
0         1         3

Де результат 0, немає NULL.

По-друге , давайте порахуємо не-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

... Але оскільки ми тут рахуємо non-NULL, це може бути спрощено до:

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

Або одна врожайність:

Column_1  Column_2  Column_3
3         2         0

Якщо результат дорівнює 0, стовпець повністю складається з NULL.

Нарешті , якщо вам потрібно лише перевірити конкретний стовпець, то TOP 1 швидше, оскільки він повинен зупинитися при першому зверненні. Потім можна необов’язково використовувати count (*) для отримання результату булевого стилю:

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 = NULL немає, 1 = Є принаймні один NULL

або

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 = Усі вони NULL, 1 = Є принаймні один не-NULL

Я сподіваюся, що це допомагає.


Хоча це здається цілком корисним, я відчуваю обов'язок зазначити, що це не те, про що просила ОП - вони хотіли, щоб вміст кожного ряду, що містив значення NULL, а не просто перевірка, щоб перевірити, чи існує така.
RDFozz

Справедливо. Я думаю, що я просто читав це по-іншому. Я був зосереджений на "... тесті, якщо у великої таблиці є ..." частина, тому ... булева (в моєму випадку булева). Але якщо під "списком записів" він мав на увазі рядки, то ви абсолютно праві.
jwolf

Щойно переглянув це. Я, безумовно, неправильно трактував питання - мав би зробити висновок, що він шукає рядки як результат. Я думаю, що я також неправильно прочитав, що він мав на увазі ВЕЛИЧЕЗНО. Спочатку я вважав, що він мав на увазі дорого обчислювальну техніку, але тепер я просто думаю, що він мав на увазі широкі колонки, тому Аррон і DB2 зрозуміли це як при читанні, так і в рішеннях (залежно від того, хто втомився: ваш мозок або ваші пальці)
jwolf

2

UNPIVOT перекладає стовпці в рядки. У процесі він виключає значення NULL ( посилання ).

З огляду на вхід

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

запит 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;

буде давати вихід

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

На жаль, рядок 4 видалено повністю, оскільки він містить лише NULL! Це можна зручно повторно ввести, вводячи фіктивне значення у вихідний запит:

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;

Агрегуючи рядки на ID, ми можемо порахувати ненульові значення. Порівняння із загальною кількістю стовпців у вихідній таблиці дозволить визначити рядки, що містять один або більше 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;

Я обчислюю 3 як
кількість стовпців у вихідній таблиці #t
+ 1 для введеного манекена
- 1 для ідентифікатора, який не є НЕЗАДАЧОМ

Це значення можна отримати під час виконання, вивчивши таблиці каталогів.

Оригінальні рядки можна отримати, приєднавшись до результатів.

Якщо слід досліджувати значення, відмінні від NULL, вони можуть бути включені до пункту де:

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

Обговорення

Для цього потрібен ідентифікатор, який передається через UNPIVOT. Ключ був би найкращим. Якщо такої немає, її можна ввести ROW_NUMBER () , хоча це може бути дорого виконати.

Усі стовпці повинні бути чітко вказані всередині пункту UNPIVOT. Їх можна перетягнути за допомогою SSMS, як запропонував @ db2. Це не буде динамічним, коли визначення таблиці зміниться, як це було б пропозицією Аарона Бертранда. Однак це стосується майже всіх SQL.

Для мого досить обмеженого набору даних план виконання - це кластерне сканування індексу та сукупність потоків. Це буде дорожче пам'яті, ніж пряме сканування таблиці та велика кількість пропозицій АБО.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.