-1

在最近的一次代码审查中,我被要求更改

Amount > 0

ISNULL(Amount,0) > 0

这些是否有可能产生不同的结果?据我所知,如果 Amount 为 null 或 0,它们都将返回 false,在任何其他情况下返回 true

为了提供更多详细信息,我想获取一个表中的所有行,只要它们在第二个表中没有对应的行且数量 > 0

-- Get members that do not have unpaid fees
Select m.Name from Members m
left join Fees f on m.Id = F.memberId and F.AmountDue > 0
where F.memberId is null
4

2 回答 2

2

amount > 0检查是否amount严格大于0。如果值为NULL,则条件返回unknown(不是true,但实际上不是false)..

ISNULL(amount, 0) > 0做同样的事情。NULL值被转换为0,这也使检查失败 - 但是在这种情况下false返回而不是unknown.

根据您要对条件结果执行的操作,这两个条件的行为可能相同,也可能不同。例如,如果您在where子句中使用它,则没有显着差异。然而,第二个条件效率较低,因为它需要额外的计算,并且可能无法利用 上的现有索引amount(如果有)。

于 2020-04-17T14:18:24.500 回答
0

将任何内容与 NULL 进行比较会导致 UNKNOWN 而不是 FALSE。

这实际上与返回 false 具有相同的效果,因为查询将仅返回数量不为空且大于 0 的行,但您应注意不要假设数量为空时比较的结果为假

例如,这也将无法返回空行:

WHERE NOT(amount > 0) 

amount > 0是 UNKNOWN 不是 FALSE。如果它是假的,那么 NOT 会变成真的

您可以认为 NULL 是一种污染物,它会在它所接触的每个布尔条件和操作中一直上升,将它们全部变为未知,然后在最后一刻“变为假”,因为布尔谓词的最终评估者需要一个真的

总的来说,您可以将 UNKNOWN 视为 NULL 的同义词;UNKNOWN 相对局限于布尔逻辑。在其他上下文中,例如涉及 NULL 的数学运算会导致 null (0+NULL = NULL)。唯一可以对 null 起作用并产生布尔值的操作是amount IS [NOT] NULL


根据您的代码审查,如果他们坚持“必须合并任何可能为空的值”,那么业务规则似乎是系统不能容忍空值——在这种情况下,应该是列不为空,仅填充实际值。通过可能会或可能不会更改它的函数传递任何值会削弱索引的使用并给查询计划带来问题。人们可能希望智能优化器可以在简化之前扩展/重写ISNULL(amount, 0) > 0amount > 0 or (amount is null and 0>0)完全删除括号中的条件,但这并不一定总是那么简单。最好不要一开始就胡说八道,而不是耸耸肩然后说“好吧,在我的简单测试用例中,它似乎并没有让事情变慢”

没有任何考虑或理由而应用一揽子规则可能会导致系统性能非常差。你将如何将此反馈给制定规则的人可能很难处理办公室政治,因为他们的方法是错误的,但他们不太可能承认或希望被告知


顺便说一句,您可能会觉得等效查询更好地捕捉了您正在尝试做的事情的概念:

SELECT m.Name 
FROM Members m
WHERE NOT EXISTS(
  SELECT 1 
  FROM Fees f 
  WHERE m.Id = F.memberId and F.AmountDue > 0
)

左反连接模式是我最喜欢的各种模式,但我觉得这更不言自明 - “所有成员都没有相关的欠款记录”。NOT IN 也使这变得非常易读,但应谨慎使用,因为某些数据库实现可能非常幼稚:

SELECT m.Name 
FROM Members m
WHERE NOT IN (
  SELECT F.MemberId 
  FROM Fees f 
  WHERE F.AmountDue > 0
)

SQL Server 很可能会重写 LEFT JOIN WHERE NULL/WHERE NOT EXISTS/WHERE NOT IN,因此它们的计划和执行方式相同,但您可能会发现在接下来的 IN 方法的这个/dim view 中没有太多欣赏代码审查:)

于 2020-04-17T14:19:53.987 回答