SQL 服务器中的三值逻辑示例

Example of three valued logic in SQL Server

我知道 SQL 使用三值逻辑,但我无法理解如何在实践中使用它,尤其是为什么 TRUE || NULL = TrueFALSE && NULL = False 而不是评估为 null.

以下是适用于 SQL 服务器的三个有值真值表:

我在网上找到了一些关于三值逻辑的解释,但我找不到任何实际使用的代码示例。谁能给我看一个使用三值逻辑的代码示例,以帮助我更好地理解这一点?

True && NULL 既不是真也不是假。只是NULL

在布尔表达式中计算结果为 True、False 还是 Error 取决于当您将 NULL 本身计算为布尔值时系统上发生的情况。 Sql 服务器会尽其所能避免选择,但如果被迫,您几乎永远不会看到肯定的 (True) 结果。

要使用可空变量,您只需在检查值之前检查 NULL 条件(使用 IS NULL)。

例如IF @a IS NOT NULL AND @a = 1

一般来说,从用户的角度来看,您不希望布尔表达式的计算结果为 NULL。

编写 SQL 通常涉及将查询编写为 明确避免 布尔表达式中的 NULL 值。 IMX,开发人员会考虑故意使用三值逻辑将被视为滥用三值逻辑。正确编写的查询应该处理 NULL 并理解它们。您不会以这样的方式编写它们,即当某些内容为 NULL 时它们恰好可以正常工作。通常这涉及 COALESCE()IS NULLIS NOT NULL 某处。

然而,理解逻辑是至关重要的,因为 NULL 存在并且对于大多数真实世界的数据来说是不可避免的。

例如,假设我正在研究 table 名学生。 table 有名字、中间名和姓氏字段。我想知道没有中间名的学生名单。现在,一些应用程序将存储一个空字符串 '',而一些应用程序将存储一个 NULL 值,而一些应用程序可能会同时执行这两种操作(一些 RDBMS,如 Oracle 将空字符串视为 NULL)。如果你不确定,你可以写成:

SELECT *
FROM Student
WHERE MiddleName = ''
    OR MiddleName IS NULL;

另一种常见情况是当您外部连接到另一个 table 时。假设您正在比较教师的薪水。您有一个 table 用于 Checks,还有一个 table 用于 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 的全部内容。

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'

user4955163 的代码示例很好地形象化了这一点,但是我只是想返回来解决问题的第一部分:

...especially why TRUE || NULL = True and FALSE && NULL = False instead of evaluating to null...

TRUE || NULL = True

这是因为如果已知一个操作数是 trueor 运算符将短路。无论第二个操作数是什么(即使未知,即 "NULL"),它都不会生成表达式 false,因为我们已经知道另一个操作数是 trueor只需要一个操作数为true,求值为true.

FALSE && NULL = False

这是因为如果已知一个操作数是 falseand 运算符将短路。无论第二个操作数是什么(即使未知,即 "NULL"),它都不会生成表达式 true,因为我们已经知道另一个操作数是 falseand 需要两个操作数都是 true 才能求得 true.