예
나는 테이블이있다
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
TRUE, FALSE 또는 (SQL의 삼항 논리로 인해) UNKNOWN으로 평가할 수있는 T-SQL 부울 식
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
다른 모든 레코드 를 얻으려면 간단히 표현을 부정 할 수 없습니다
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
왜 이런 일이 발생하는지 (삼항 논리) 알고 있으며이 특정 문제를 해결하는 방법을 알고 있습니다.
나는 단지 사용할 수 있고 알 myField = 'someValue' AND NOT myField IS NULL
수없는 “돌이킬 수없는”표현을 얻는다는 것을 안다 :
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
일반적인 경우
이제 일반적인 경우에 대해 이야기합시다. myField = 'someValue'
많은 필드와 조건, 아마도 하위 쿼리를 포함하는 복잡한 표현이 있다고 가정 해 봅시다 .
SELECT * FROM myTable WHERE ...some complex Boolean expression...
이 expession을 “반전”하는 일반적인 방법이 있습니까? 하위 표현식에서 작동하는 경우 보너스 포인트 :
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
SQL Server 2008-2014를 지원해야하지만 2008보다 최신 버전이 필요한 우아한 솔루션이 있다면 그것에 대해서도 관심이 있습니다.
답변
이진 결과 (예 : 1 또는 0)를 반환하는 CASE 식으로 조건을 묶을 수 있습니다.
SELECT
...
FROM
...
WHERE
CASE WHEN someColumn = someValue THEN 1 ELSE 0 END = 1
;
표현식을 무효화하면 someColumn 이 null 인 행을 포함하여 동일한 데이터 소스의 다른 모든 행이 제공됩니다 .
SELECT
...
FROM
...
WHERE
NOT CASE WHEN someColumn = someValue THEN 1 ELSE 0 END = 1
-- or: CASE WHEN someColumn = someValue THEN 1 ELSE 0 END <> 1
;
SQL Server 2012부터 IIF 함수 도 있습니다. 이는 위와 같이 이진 CASE를 감싸는 래퍼입니다. 따라서이 CASE 표현식은 다음과 같습니다.
CASE WHEN someColumn = someValue THEN 1 ELSE 0 END
IIF를 사용하여 다시 작성하면 다음과 같습니다.
IIF(someColumn = someValue, 1, 0)
그리고 CASE 표현식과 정확히 같은 방식으로 사용할 수 있습니다. 성능에는 차이가 없으며 코드 만 약간 더 간결하고 아마도 더 깔끔합니다.
답변
나에게 일어난 첫 번째 생각 :
DECLARE @T AS table (c1 integer NULL);
INSERT @T (c1)
VALUES (1), (NULL), (2);
-- Original expression c1 = 1
SELECT T.c1
FROM @T AS T
WHERE c1 = 1;
보고:
-- Negated
SELECT T.c1
FROM @T AS T
WHERE NOT EXISTS (SELECT 1 WHERE c1 = 1);
보고:
길가에이 의존 EXISTS
항상 반환 참 또는 거짓 결코 알 수없는 . 의 필요성 SELECT 1 WHERE
은 불행히도 필요하지만, 예를 들어 다음과 같은 요구 사항에 맞출 수 있습니다.
sql = "
SELECT *
FROM someTable
WHERE " + someExpression +
" AND NOT EXISTS (SELECT 1 WHERE " +
someOtherExpression + ")";
result = executeAndShow(sql);
참조가 EXISTS (Transact-SQL)를 참조하십시오
개별 술어를 뒤집는 데 하나 EXISTS
이상의 CASE/IIF
방법을 적용하는 방법을 보여주는 약간 더 복잡한 예제입니다 .
DECLARE @T AS table
(
c1 integer NULL,
c2 integer NULL,
c3 integer NULL
);
INSERT @T
(c1, c2, c3)
VALUES
(1, NULL, 2),
(2, 2, 3),
(NULL, 1, 4);
암호:
-- Original
SELECT
T.c1,
T.c2,
T.c3
FROM @T AS T
WHERE
1 = 1
-- Predicate #1
AND T.c1 = 2
-- Predicate #2
AND T.c2 =
(
SELECT MAX(T2.c2)
FROM @T AS T2
WHERE T2.c2 IS NOT NULL
)
-- Predicate #3
AND T.c3 IN (3, 4)
;
-- Invert predicates #1 and #2
SELECT
T.c1,
T.c2,
T.c3
FROM @T AS T
WHERE
1 = 1
AND NOT EXISTS (SELECT 1 WHERE 1 = 1
-- Predicate #1
AND T.c1 = 2)
AND NOT EXISTS (SELECT 1 WHERE 1 = 1
-- Predicate #2
AND T.c2 =
(
SELECT MAX(T2.c2)
FROM @T AS T2
WHERE T2.c2 IS NOT NULL
))
-- Predicate #3
AND T.c3 IN (3, 4)
;
답변
하위 표현식을 미리 작성하지 않으려면 다음을 사용할 수 있습니다 COALESCE
.
SELECT *
FROM myTable
WHERE NOT (COALESCE(myField, 'notSomeValue') = 'someValue')
당신 은 그것 'notSomeValue'
과 구별 되도록해야합니다 'someValue'
; 바람직하게는 컬럼에 대해 완전히 잘못된 값일 수 있습니다. ( NULL
물론 어느 쪽도 될 수는 없습니다 .) 긴 목록이 있어도 부정하기 쉽습니다.
SELECT *
FROM myTable
WHERE NOT (
COALESCE(myField, 'notSomeValue') = 'someValue' AND
COALESCE(myField2, 'notSomeValue') = 'someValue2' AND
COALESCE(myField3, 'notSomeValue') = 'someValue3' AND
COALESCE(myField4, 'notSomeValue') = 'someValue4'
)
내 의견으로 는 CASE
또는 보다 깨끗하고 단순하며 분명 IIF
합니다. 주된 단점은 두 번째 값이 같지 않다는 것입니다. 그러나 실제 값을 미리 모르는 경우에만 문제가됩니다. 이 경우 Hanno Binder가 제안하고 사용 하는 것처럼 COALESCE(myField, CONCAT('not', 'someValue')) = 'someValue'
( 'someValue'
실제로 매개 변수화 되는 위치) 수행 할 수 있습니다.
COALESCE
SQL Server 2005부터 사용 가능하도록 문서화되었습니다.
이와 같이 쿼리를 망치면 (여기서 권장되는 방법 중 하나를 사용하여) 데이터베이스에서 쿼리를 최적화하기가 더 어려워 질 수 있습니다. 대규모 데이터 세트의 경우 IS NULL
버전을 최적화하기가 더 쉽습니다.
답변
내장 EXCEPT 세트 연산자가있어 첫 번째 쿼리에서 두 번째 쿼리의 결과를 효과적으로 제거합니다.
select * from table
except
select * from table
where <really complex predicates>
답변
COALESCE를 사용할 수 있습니까?
SELECT * FROM myTable WHERE NOT COALESCE(myField = 'someValue', FALSE)