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, должны быть исследованы, они могут быть включены в предложение where:
...
) as unpvt
where ColValue <> '' -- will eliminate empty strings
обсуждение
Для этого требуется идентификатор, который передается через UNPIVOT. Ключ будет лучшим. Если ничего не существует, его можно ввести с помощью ROW_NUMBER () оконной функции , хотя это может быть дорогостоящим для выполнения.
Все столбцы должны быть явно перечислены в предложении UNPIVOT. Их можно перетащить с помощью SSMS, как предложено @ db2. Это не будет динамичным, когда определение таблицы искажается, как было бы предложено Аароном Бертраном. Однако это касается почти всех SQL.
Для моего довольно ограниченного набора данных план выполнения - это сканирование кластерного индекса и агрегат потока. Это будет дороже памяти, чем прямое сканирование таблицы и множество предложений OR.