我知道 SQL 使用三值逻辑,但我无法理解如何在实践中使用它,尤其是为什么TRUE || NULL = True
而FALSE && NULL = False
不是评估 to null
。
以下是适用于 SQL Server 的三个有值真值表:
我在网上找到了一些关于三值逻辑的解释,但我找不到任何实际使用的代码示例。有人可以向我展示一个使用三值逻辑的代码示例来帮助我更好地理解这一点吗?
我知道 SQL 使用三值逻辑,但我无法理解如何在实践中使用它,尤其是为什么TRUE || NULL = True
而FALSE && NULL = False
不是评估 to null
。
以下是适用于 SQL Server 的三个有值真值表:
我在网上找到了一些关于三值逻辑的解释,但我找不到任何实际使用的代码示例。有人可以向我展示一个使用三值逻辑的代码示例来帮助我更好地理解这一点吗?
一个例子TRUE || NULL = True
是
declare @x as int = null;
if 1=1 or @x/1=1
print 'true'
一个例子FALSE && NULL = False
是
declare @x as int = null;
if not(1=2 and @x/1=1)
print 'false'
True && NULL
既不是真也不是假。只是NULL
。
在布尔表达式中计算结果为 True、False 还是 Error 取决于当您将其NULL
自身评估为布尔值时系统上发生的情况。Sql Server 将尽其所能避免选择,但是当你被迫时,你几乎永远不会看到积极的(真)结果。
一般来说,从用户的角度来看,您不希望布尔表达式计算为 NULL。
编写 SQL 通常涉及编写查询以显式避免布尔表达式中的 NULL 值。IMX,开发人员会考虑故意使用三值逻辑将被视为滥用三值逻辑。正确编写的查询应该处理 NULL 并理解它们。您不会以这样一种方式编写它们,即当某些东西为 NULL 时它们恰好可以正常工作。通常这涉及COALESCE()
或IS NULL
或IS NOT NULL
某处。
然而,理解逻辑至关重要,因为 NULL 存在并且对于大多数真实世界的数据来说是不可避免的。
例如,假设我正在处理一张学生表。该表具有名字、中间名和姓氏字段。我想知道没有中间名的学生名单。现在,一些应用程序将存储一个空字符串,''
而一些应用程序将存储一个 NULL 值,而一些应用程序可能会同时执行这两种操作(并且某些 RDBMS,如 Oracle 将空字符串视为 NULL)。如果你不确定,你可以写成:
SELECT *
FROM Student
WHERE MiddleName = ''
OR MiddleName IS NULL;
另一种常见的情况是当您 OUTER JOINing 到另一个表时。假设您正在比较教师的薪水。您有一个 Checks 表和一个 CheckDetail 表。您想知道教师为福利支付了多少费用。您的报告需要列出所有教师,即使他们是因没有得到任何福利而不支付福利的承包商:
SELECT Check.Employee_Id,
SUM(CheckDetail.Amount) AS BenefitsDeductions
FROM Check
LEFT JOIN CheckDetail
ON Check.Id = CheckDetail.CheckId
AND CheckDetail.LineItemType = 'Benefits'
GROUP BY Check.Employee_Id;
您运行您的报告,并注意到您的承包商教师显示的 BenefitsDeductions 为 NULL。哎呀。您需要确保它显示为零:
SELECT Check.Employee_Id,
COALESCE(SUM(CheckDetail.Amount),0) AS BenefitsDeductions
FROM Check
LEFT JOIN CheckDetail
ON Check.Id = CheckDetail.CheckId
AND CheckDetail.LineItemType = 'Benefits'
GROUP BY Check.Employee_Id;
所以你尝试一下,它的工作原理。没有 NULL 值!但是……几天后,您的用户报告说,曾经是承包商的老师现在出现的情况是 0,即使他们现在正在为福利付费。您必须在 SUM 之前 COALESCE 以保留这些金额:
SELECT Check.Employee_Id,
SUM(COALESCE(CheckDetail.Amount,0)) AS BenefitsDeductions
FROM Check
LEFT JOIN CheckDetail
ON Check.Id = CheckDetail.CheckId
AND CheckDetail.LineItemType = 'Benefits'
GROUP BY Check.Employee_Id;
查找这些极端情况和异常是编写 SQL 的全部内容。
user4955163 的代码示例对此进行了很好的可视化,但是我只想退后一步来解决问题的第一部分:
...特别是为什么 TRUE || NULL = True and FALSE && NULL = False 而不是评估为 null...
TRUE || NULL = True
这是因为or
如果一个操作数已知为 ,则运算符将短路true
。无论第二个操作数是什么(即使未知,即“NULL”),它都不会生成表达式false
,因为我们已经知道另一个操作数是true
. or
只需要一个操作数是true
,评估到true
。
FALSE && NULL = False
这是因为and
如果一个操作数已知为 ,则运算符将短路false
。无论第二个操作数是什么(即使未知,即“NULL”),它都不会生成表达式true
,因为我们已经知道另一个操作数是false
. and
需要将两个操作数都true
计算为true
。
要使用可为空的变量,您只需IS NULL
在检查值之前检查 NULL 条件(使用 )。
例如IF @a IS NOT NULL AND @a = 1