Jas*_*aty 49 sql t-sql sql-server ansi-sql sql-server-2008-r2
如何重写包含SQL实现中的标准IS DISTINCT FROM和IS NOT DISTINCT FROM运算符的表达式,例如不支持它们的Microsoft SQL Server 2008R2?
Chr*_*ndy 45
该IS DISTINCT FROM谓词是作为SQL:1999的特征T151引入的,其可读的否定IS NOT DISTINCT FROM被添加为SQL:2003的特征T152.这些谓词的目的是保证比较两个值的结果是True还是False,而不是Unknown.
这些谓词适用于任何类似的类型(包括行,数组和多集),使得完全模拟它们相当复杂.但是,SQL Server不支持大多数这些类型,因此我们可以通过检查空参数/操作数来获得相当远的结果:
a IS DISTINCT FROM b 可以改写为:
((a <> b OR a IS NULL OR b IS NULL) AND NOT (a IS NULL AND b IS NULL))
Run Code Online (Sandbox Code Playgroud)a IS NOT DISTINCT FROM b 可以改写为:
(NOT (a <> b OR a IS NULL OR b IS NULL) OR (a IS NULL AND b IS NULL))
Run Code Online (Sandbox Code Playgroud)您自己的答案是不正确的,因为它没有考虑FALSE OR NULL评估为未知.例如,NULL IS DISTINCT FROM NULL应评估为False.同样,1 IS NOT DISTINCT FROM NULL应评估为False.在这两种情况下,您的表达式都会产生未知.
小智 28
我喜欢的另一个解决方案是利用EXISTS与INTERSECT结合的真正的双值布尔结果.此解决方案应适用于SQL Server 2005+.
a IS NOT DISTINCT FROM b 可以写成:
EXISTS(SELECT a INTERSECT SELECT b)
如记录,INTERSECT对待两个空值如相等,所以如果两者都为NULL,则在单排INTERSECT结果,从而EXISTS产生true.
a IS DISTINCT FROM b 可以写成:
NOT EXISTS(SELECT a INTERSECT SELECT b)
如果您需要在两个表中比较多个可空列,则此方法更简洁.例如,要返回TableB中具有与TableA不同的Col1,Col2或Col3值的行,可以使用以下内容:
SELECT *
FROM TableA A
INNER JOIN TableB B ON A.PK = B.PK
WHERE NOT EXISTS(
SELECT A.Col1, A.Col2, A.Col3
INTERSECT
SELECT B.Col1, B.Col2, B.Col3);
Run Code Online (Sandbox Code Playgroud)
Paul White更详细地解释了这种解决方法:http://web.archive.org/web/20180422151947/http : //sqlblog.com :80/blogs/paul_white/archive/2011/06/22/undocumented-query- plans -equality-comparisons.aspx
Jas*_*aty 11
如果您的SQL实现没有实现SQL标准IS DISTINCT FROM和IS NOT DISTINCT FROM运算符,您可以使用以下等效项重写包含它们的表达式:
一般来说:
a IS DISTINCT FROM b <==>
(
((a) IS NULL AND (b) IS NOT NULL)
OR
((a) IS NOT NULL AND (b) IS NULL)
OR
((a) <> (b))
)
a IS NOT DISTINCT FROM b <==>
(
((a) IS NULL AND (b) IS NULL)
OR
((a) = (b))
)
Run Code Online (Sandbox Code Playgroud)
当在UNKNOWN和FALSE之间的差异很重要的环境中使用时,这个答案是不正确的.不过,我认为这种情况并不常见.请参阅@ChrisBandy接受的答案.
如果可以识别出实际上未在数据中出现的占位符值,则COALESCE可以选择:
a IS DISTINCT FROM b <==> COALESCE(a, placeholder) <> COALESCE(b, placeholder)
a IS NOT DISTINCT FROM b <==> COALESCE(a, placeholder) = COALESCE(b, placeholder)
Run Code Online (Sandbox Code Playgroud)
Just to extend John Keller's answer. I prefer to use EXISTS and EXCEPT pattern:
a IS DISTINCT FROM b
<=>
EXISTS (SELECT a EXCEPT SELECT b)
-- NOT EXISTS (SELECT a INTERSECT SELECT b)
Run Code Online (Sandbox Code Playgroud)
and
a IS NOT DISTINCT FROM b
<=>
NOT EXISTS (SELECT a EXCEPT SELECT b)
-- EXISTS (SELECT a INTERSECT SELECT b)
Run Code Online (Sandbox Code Playgroud)
for one particular reason. NOT is aligned whereas with INTERSECT it is inverted.
SELECT 1 AS PK, 21 AS c, NULL AS b
INTO tab1;
SELECT 1 AS PK, 21 AS c, 2 AS b
INTO tab2;
SELECT *
FROM tab1 A
JOIN tab2 B ON A.PK = B.PK
WHERE EXISTS(SELECT A.c, A.B
EXCEPT
SELECT B.c, B.b);
Run Code Online (Sandbox Code Playgroud)
小智 5
重写IS DISTINCT FROM和IS NOT DISTINCT FROM的一个警告是不干扰使用索引,至少在使用SQL Server时.换句话说,使用以下内容时:
WHERE COALESCE(@input, x) = COALESCE(column, x)
Run Code Online (Sandbox Code Playgroud)
SQL Server将无法使用包含列的任何索引.所以在WHERE子句中,最好使用表单
WHERE @input = column OR (@input IS NULL AND column IS NULL)
Run Code Online (Sandbox Code Playgroud)
利用列的任何索引.(仅用于清晰的Parens)
| 归档时间: |
|
| 查看次数: |
13731 次 |
| 最近记录: |