SQL 服务器:NULL 或空字符串?
SQL Server: NULL or empty string?
我有一个数据库列,其值以编程方式确定并且不受用户输入的影响。该值永远不是空字符串;它是 NULL 或非 0 长度的字符串。该列当前可以为空。
通常,我想在两个不同的行之间比较此列。因为该列可以为空,所以我必须执行以下操作:
SELECT *
FROM
myTable A
INNER JOIN myTable B ON ISNULL(B.someColumn, '') = ISNULL(A.someColumn, '')
WHERE B.Id > A.Id
如果空字符串没有意义,我是否更明智地创建列 NOT NULL
并使用空字符串来指示该列没有值?
然后我可以使用以下方法比较列:
SELECT *
FROM
foo A
INNER JOIN foo B ON B.someColumn = A.someColumn
WHERE B.Id > A.Id
我觉得这种方法更好地利用了列 someColumn
?
上的索引
是的,我知道我可以做到:
(B.someColumn = A.someColumn) or (B.someColumn is NULL and A.someColumn is NULL)
不过好像有点啰嗦
您自己陈述的和您提供的代码是正确的。
值得注意的是,您的第一个示例中的代码
`INNER JOIN myTable B ON ISNULL(B.someColumn, '') = ISNULL(A.someColumn, '')`
强制 SQL 服务器扫描整个 table 并计算 ISNULL(...)
,然后才能进行连接。这意味着它不能使用任何索引来加速连接,这将大大降低性能。下次执行该查询时将重复相同的过程,因此您不能期望随后 运行 再次查询会更快。
[ 作为记录,您当然可以使 ISNULL(...)
成为一个计算列,对其进行索引并在连接中使用它,但考虑到其他可能的解决方案,这似乎有点夸张。 ]
您是应该使用 ''
而不是 NULL
还是采用另一种方法取决于前者需要付出的努力:
如果您的应用程序 仅 如果它想在那里写一个有意义的(读取:非空)值,那么您可以通过三个简单的步骤解决问题(更新列并将所有 NULL
值转换为 ''
;使列不可为空;将列的默认值从 NULL
更改为 ''
).
但是,如果您的应用程序在每种情况下都触及该列并在适当的情况下主动向其写入 NULL
,则您将不得不更改应用程序本身以采用该路线。是否可以更改应用程序只有您自己知道...
如果您无法更改应用程序,那么您的第三种方法很好并且工作可靠:
(B.someColumn = A.someColumn) or (B.someColumn is NULL and A.someColumn is NULL)
我不会因为它“冗长”而感到不安。一般来说,代码的长度对性能没有任何意义,在这种情况下,冗长的代码使您能够在应用程序中保持原样(除了这个查询),同时使 SQL 服务器能够使用索引以加快连接速度。
总结:
使用 ''
而不是 NULL
如果您的应用程序允许这样做很容易,或者可以很容易地更改以允许它。否则,请使用第三种方法。
关于 ANSI_NULLS
的最后说明:
Walter Vehoeven 在您的问题下方的评论是正确的,但在您的情况下,ANSI_NULLS
不会改变任何内容。来自 the documentation([=63= 下面的第一段],格式化我的):
SET ANSI_NULLS ON affects a comparison only if one of the operands of the comparison is either a variable that is NULL or a literal NULL. If both sides of the comparison are columns or compound expressions, the setting does not affect the comparison.
第二句意味着它对你的情况没有任何影响,因为你正在比较/连接两列(即使它实际上是比较两边的同一列)。
我有一个数据库列,其值以编程方式确定并且不受用户输入的影响。该值永远不是空字符串;它是 NULL 或非 0 长度的字符串。该列当前可以为空。
通常,我想在两个不同的行之间比较此列。因为该列可以为空,所以我必须执行以下操作:
SELECT *
FROM
myTable A
INNER JOIN myTable B ON ISNULL(B.someColumn, '') = ISNULL(A.someColumn, '')
WHERE B.Id > A.Id
如果空字符串没有意义,我是否更明智地创建列 NOT NULL
并使用空字符串来指示该列没有值?
然后我可以使用以下方法比较列:
SELECT *
FROM
foo A
INNER JOIN foo B ON B.someColumn = A.someColumn
WHERE B.Id > A.Id
我觉得这种方法更好地利用了列 someColumn
?
是的,我知道我可以做到:
(B.someColumn = A.someColumn) or (B.someColumn is NULL and A.someColumn is NULL)
不过好像有点啰嗦
您自己陈述的和您提供的代码是正确的。
值得注意的是,您的第一个示例中的代码
`INNER JOIN myTable B ON ISNULL(B.someColumn, '') = ISNULL(A.someColumn, '')`
强制 SQL 服务器扫描整个 table 并计算 ISNULL(...)
,然后才能进行连接。这意味着它不能使用任何索引来加速连接,这将大大降低性能。下次执行该查询时将重复相同的过程,因此您不能期望随后 运行 再次查询会更快。
[ 作为记录,您当然可以使 ISNULL(...)
成为一个计算列,对其进行索引并在连接中使用它,但考虑到其他可能的解决方案,这似乎有点夸张。 ]
您是应该使用 ''
而不是 NULL
还是采用另一种方法取决于前者需要付出的努力:
如果您的应用程序 仅 如果它想在那里写一个有意义的(读取:非空)值,那么您可以通过三个简单的步骤解决问题(更新列并将所有 NULL
值转换为 ''
;使列不可为空;将列的默认值从 NULL
更改为 ''
).
但是,如果您的应用程序在每种情况下都触及该列并在适当的情况下主动向其写入 NULL
,则您将不得不更改应用程序本身以采用该路线。是否可以更改应用程序只有您自己知道...
如果您无法更改应用程序,那么您的第三种方法很好并且工作可靠:
(B.someColumn = A.someColumn) or (B.someColumn is NULL and A.someColumn is NULL)
我不会因为它“冗长”而感到不安。一般来说,代码的长度对性能没有任何意义,在这种情况下,冗长的代码使您能够在应用程序中保持原样(除了这个查询),同时使 SQL 服务器能够使用索引以加快连接速度。
总结:
使用 ''
而不是 NULL
如果您的应用程序允许这样做很容易,或者可以很容易地更改以允许它。否则,请使用第三种方法。
关于 ANSI_NULLS
的最后说明:
Walter Vehoeven 在您的问题下方的评论是正确的,但在您的情况下,ANSI_NULLS
不会改变任何内容。来自 the documentation([=63= 下面的第一段],格式化我的):
SET ANSI_NULLS ON affects a comparison only if one of the operands of the comparison is either a variable that is NULL or a literal NULL. If both sides of the comparison are columns or compound expressions, the setting does not affect the comparison.
第二句意味着它对你的情况没有任何影响,因为你正在比较/连接两列(即使它实际上是比较两边的同一列)。