内容提要
本文探讨PostgreSQL中NULL的语义及其对查询的影响。NULL代表未知值,在比较、算术、逻辑运算中会传播,导致WHERE过滤、NOT IN、聚合、窗口函数及字符串拼接等出现意外结果。通过示例展示常见陷阱,并提出使用COALESCE、IS NULL、IS NOT DISTINCT FROM、NOT EXISTS等解决方案,强调合理设计NOT NULL约束的重要性。
延伸解读
NULL的传播性:从比较到聚合
NULL在SQL中代表未知,而非值。比较、算术、逻辑运算中,NULL会传播,导致结果也是NULL。例如,NULL = NULL返回NULL,而非TRUE。这种传播性在WHERE过滤、NOT IN、聚合和窗口函数中尤为明显,容易造成数据意外丢失或计算错误。理解NULL的传播是避免这些陷阱的第一步。
NOT IN的陷阱与NOT EXISTS的可靠性
当子查询或列表中包含NULL时,NOT IN会因NULL的传播而返回空集,因为x <> NULL的结果是NULL,而非TRUE。相比之下,NOT EXISTS使用等值比较,不会因NULL而误判,因此更可靠。若必须使用NOT IN,需先过滤掉NULL值,但NOT EXISTS能更清晰地表达意图。
聚合函数与NULL:默认行为与业务规则
聚合函数如COUNT、SUM、AVG会忽略NULL值,但COUNT(*)会计数所有行。这可能导致AVG与SUM/COUNT(*)不一致。若业务上需将NULL视为0,应使用COALESCE在聚合前转换。理解默认行为,并根据业务规则显式处理NULL,是避免统计偏差的关键。
排序与NULL:默认位置与显式控制
Postgres默认将NULL视为大于任何非NULL值,因此升序时NULL排在最后,降序时排在最前。若需特定排序,应使用NULLS FIRST或NULLS LAST。注意,排序规则与聚合函数(如MAX)对NULL的处理不同,需根据需求显式指定。