Hei*_*nzi 11 sql-server condition
我有一张桌子
ID myField
------------
1 someValue
2 NULL
3 someOtherValue
Run Code Online (Sandbox Code Playgroud)
和一个 T-SQL 布尔表达式,它可以计算为 TRUE、FALSE 或(由于 SQL 的三元逻辑)UNKNOWN:
SELECT * FROM myTable WHERE myField = 'someValue'
-- yields record 1
Run Code Online (Sandbox Code Playgroud)
如果我想获得所有其他记录,我不能简单地否定表达式
SELECT * FROM myTable WHERE NOT (myField = 'someValue')
-- yields only record 3
Run Code Online (Sandbox Code Playgroud)
我知道为什么会发生这种情况(三元逻辑),并且我知道如何解决这个特定问题。
我知道我可以使用myField = 'someValue' AND NOT myField IS NULL并且我得到一个永远不会产生 UNKNOWN 的“可逆”表达式:
SELECT * FROM myTable WHERE NOT (myField = 'someValue' AND myField IS NOT NULL)
-- yields records 2 and 3, hooray!
Run Code Online (Sandbox Code Playgroud)
现在,让我们谈谈一般情况。假设myField = 'someValue'我有一些涉及许多字段和条件的复杂表达式,也许是子查询:
SELECT * FROM myTable WHERE ...some complex Boolean expression...
Run Code Online (Sandbox Code Playgroud)
有没有一种通用的方法来“反转”这个expession?如果它适用于子表达式,则加分:
SELECT * FROM myTable
WHERE ...some expression which stays...
AND ...some expression which I might want to invert...
Run Code Online (Sandbox Code Playgroud)
我需要支持 SQL Server 2008-2014,但如果有一个优雅的解决方案需要比 2008 年更新的版本,我也有兴趣了解它。
And*_*y M 16
您可以将条件包含在返回二进制结果的 CASE 表达式中,例如 1 或 0:
SELECT
...
FROM
...
WHERE
CASE WHEN someColumn = someValue THEN 1 ELSE 0 END = 1
;
Run Code Online (Sandbox Code Playgroud)
否定表达式将为您提供来自同一数据源的所有其他行,包括someColumn为空的行:
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
;
Run Code Online (Sandbox Code Playgroud)
从 SQL Server 2012 开始,您还拥有IIF 函数,它只是像上面这样的二进制 CASE 的包装器。所以,这个 CASE 表达式:
CASE WHEN someColumn = someValue THEN 1 ELSE 0 END
Run Code Online (Sandbox Code Playgroud)
如果使用 IIF 重写,将如下所示:
IIF(someColumn = someValue, 1, 0)
Run Code Online (Sandbox Code Playgroud)
您可以使用与 CASE 表达式完全相同的方式来使用它。性能上没有区别,只是代码会稍微简洁一些,也可能更简洁。
Pau*_*ite 10
我想到的第一个想法是:
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;
Run Code Online (Sandbox Code Playgroud)
返回:
-- Negated
SELECT T.c1
FROM @T AS T
WHERE NOT EXISTS (SELECT 1 WHERE c1 = 1);
Run Code Online (Sandbox Code Playgroud)
返回:
这依赖的方式EXISTS总是返回true或false,从不未知。需要的SELECT 1 WHERE是不幸的是必要的,但它可能是可行的为你的要求,例如:
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;
Run Code Online (Sandbox Code Playgroud)
一个稍微复杂一些的工作示例,展示了如何应用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);
Run Code Online (Sandbox Code Playgroud)
代码:
-- 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)
;
Run Code Online (Sandbox Code Playgroud)