我有一个关于三元布尔逻辑的问题,它影响如何在我们的LINQ提供程序中实现多态实体之间的比较。
在SQL中,如果使用Country的外键连接Region表:
SELECT * From Region r1, Region r2
WHERE r1.Country == r2.Country
(注意:无论使用JOIN还是WHERE语法,结果都是相同的)
它将返回条件为真的值,而不是条件为假或未知的值(因为有些键为空)。如果我们否定条件
SELECT * From Region r1, Region r2
WHERE r1.Country != r2.Country
我们获得条件为真(现在是不同的键)的值,我们将跳过具有相同键的值,或者具有空值的值,因为条件再次返回未知。即使我们这样写:
SELECT * From Region r1, Region r2
WHERE not(r1.Country == r2.Country)
未知将被传播,因此在这个简单的条件下,null永远不会出现。到目前为止一切顺利。
现在让我们想象一个地区可以有一个国家(对于欧洲小国)或一个州(对于美国,俄罗斯,中国…)。如果区域有一个State,它将有Country null,反之亦然。
我们如何将[Country,State]对连接起来,使其具有与以前相同的属性?:
SELECT * From Region r1, Region r2
WHERE r1.Country == r2.Country OR r1.State == r2.State
此表达式如果连接将返回true,否则返回未知。我们希望它只在所有字段为空的情况下返回未知,否则如果我们取反:
SELECT * From Region r1, Region r2
WHERE not(r1.Country == r2.Country OR r1.State == r2.State)
它不返回行!如果我们尝试一个更复杂的表达式:
SELECT * From Region r1, Region r2
WHERE (r1.Country == r2.Country AND r1.Country IS NOT NULL AND r2.Country IS NOT NULL)
OR (r1.State == r2.State AND r1.State IS NOT NULL AND r2.State IS NOT NULL)
如果匹配则返回真值,否则返回假值,永远不返回空值。然后,如果我们取负值,它将返回所有行都为空的值,这与第一个示例中的行为不同。
那么哪个表达式比较这对将表现得像SQL相等?
- 匹配 时为True
- 当不匹配 时为False
- 当某些操作数为空时未知。
创建计算列:
Location AS COALESCE(Country, State)
,将其索引并像往常一样进行比较:
SELECT *
FROM Region r1
JOIN Region r2
ON r2.Location = r1.Location
如果Country
和State
都是NULL
,则Location
为NULL
。
更新:
如果Country
和State
可以相互比较,则创建一个额外的列,显示使用哪一个:
LocationType AS CASE WHEN Country IS NOT NULL THEN 1 WHEN State IS NOT NULL THEN 2 END,
LocationId AS COALESCE(Country, State)
,索引两个并使用它们进行比较:
SELECT *
FROM Region r1
JOIN Region r2
ON r2.LocationType = r1.LocationType
AND r2.LocationID = r1.LocationID
你可以试试这个吗:
SELECT *
FROM Region r1
JOIN Region r2
ON ( r1.Country = r2.Country
AND r1.State IS NULL
AND r2.State IS NULL
)
OR ( r1.State = r2.State
AND r1.Country IS NULL
AND r2.Country IS NULL
)