열이 NULL인지 테스트


16

큰 테이블에 모든 열에 하나 이상의 빈 값 (NULL / empty)이있는 항목 목록이 있는지 테스트하기 위해 쉬운 쿼리를 찾으려고합니다.

나는 같은 것이 필요하다

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 

(이 SO 답변을 바탕으로)


5

기본 제공 구문은 없지만 Management Studio에는 쿼리를 빠르게 생성 할 수있는 편리한 기능이 있습니다.

개체 탐색기에서 원하는 테이블로 드릴 다운하고 확장 한 다음 전체 "Columns"폴더를 빈 쿼리 편집기로 끕니다. 이렇게하면 쉼표로 구분 된 열 목록이 쿼리에 추가됩니다.

그런 다음 찾기 및 바꾸기를 엽니 다. "Find What"을 ,설정하고 "Replace With"를 IS NULL OR(앞 공백으로) 설정 한 다음 Replace All을 누르십시오. 순서대로 마지막 하나를 손으로 정리해야합니다.

여전히 추악하지만 노동 집약도 덜 추합니다.


4

여러 솔루션 : 일부 null, 모든 null, 단일 및 다중 열 및 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

...하지만 여기서는 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이 아닌 하나 이상이 있습니다.

이게 도움이 되길 바란다.


이것은 매우 유용한 것처럼 보이지만 OP가 요구하는 것이 아니라는 점에 유의해야 할 의무가 있습니다. 그들은 존재 여부를 확인하는 것뿐만 아니라 NULL 값을 포함하는 각 행 의 내용 을 원했습니다 .
RDFozz

그럴 수 있지. 나는 그것을 다르게 읽고 있다고 생각합니다. 나는 "... 큰 테이블에 ...이 있는지 테스트합니다."부분에 집중했습니다. 그러나 "항목 목록"에 의해 행을 의미한다면, 당신은 절대적으로 옳습니다.
jwolf

방금 이것을 다시 방문했습니다. 나는 분명히 그 질문을 잘못 해석했다-그가 결과로 행을 찾고 있다고 추론해야했다. 나는 또한 그가 거대한 의미를 잘못 읽은 것 같아요. 나는 원래 그가 계산 비용을 의미 생각하지만 지금은 애런과 DB2는 독서, 바로 모두 그것을 가지고, 그래서 그가 열이 넓은 의미 생각과 솔루션 (에 따라 것이 더 피곤하다 : 당신의 두뇌 또는 손가락)
jwolf

2

UNPIVOT은 열을 행으로 변환합니다. 이 과정에서 NULL 값을 제거합니다 ( reference ).

주어진 입력

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;

주입 된 더미 열의 경우
소스 테이블 #t
+ 1 의 열 수로 3을 계산
합니다 .ID의 경우 1이며 UNPIVOTED가 아닙니다.

카탈로그 테이블을 검사하여 런타임시이 값을 얻을 수 있습니다.

결과에 결합하여 원래 행을 검색 할 수 있습니다.

NULL 이외의 값을 조사하려면 where 절에 포함시킬 수 있습니다.

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

토론

UNPIVOT을 통해 전달되는 식별자가 필요합니다. 열쇠가 가장 좋습니다. 존재하지 않는 경우 ROW_NUMBER () 창 함수 로 삽입 할 수 있지만 실행 비용이 많이들 수 있습니다.

모든 열은 UNPIVOT 절 안에 명시 적으로 나열되어야합니다. @ db2가 제안한 것처럼 SSMS를 사용하여 끌 수 있습니다. Aaron Bertrand의 제안과 같이 테이블 정의가 샴페인 일 때는 역동적이지 않습니다. 그러나 이것은 거의 모든 SQL의 경우입니다.

다소 제한된 데이터 세트의 경우 실행 계획은 클러스터형 인덱스 스캔 및 스트림 집계입니다. 이는 테이블 및 많은 OR 절을 연속 스캔하는 것보다 메모리 비용이 더 비쌉니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.