如何观察 SET CONCAT_NULL_YIELDS_NULL off 的效果?
How can I observe the effect of SET CONCAT_NULL_YIELDS_NULL off?
我们有一个旧的数据库产品;主部署始终完成 ALTER Database [databasename] SET CONCAT_NULL_YIELDS_NULL OFF
。由于此设置即将消失,我们想制定一个测试计划来摆脱它并追踪依赖它的代码。
关闭此开关后,文档说 SELECT 'abc' + NULL FROM sometable
结果是 abc 而不是 NULL。
我可以很容易地在连接级别观察到这种行为;但是应用程序 never 在连接级别设置它。这不是这里的问题。
我如何通过任何 SQL 语句观察仅在数据库级别使用 .NET System.Data.SqlClient
作为数据库访问客户端关闭 CONCAT_NULL_YIELDS_NULL
的效果?
我们审核了整个代码库并删除了除事务隔离级别之外的所有 SET 命令实例,因为这些管控非常困难。虽然我尝试 EXEC
看它是否会绕过驱动程序设置并发现它没有,但我有理由相信有一些足够奇特的 SQL 构造可以成功。
即使您的应用程序没有明确指定此选项,不同的 ODBC 和 OLEDB 驱动程序也有不同的默认连接选项。根据驱动程序的不同,此特定选项可以隐式设置,也可以从数据库/服务器设置继承。
为了查看您的应用程序建立的连接的此选项的实际状态,您可以setup a Profiler trace这将显示有效的连接设置。
关于覆盖驱动程序的行为设置此选项,在 DBA StackExchange 上有一个类似的问题 thorough answer。在那里,您可以找到几种可能的方法,看看哪一种最适合您。
在 SQL 方面,一种可能的解决方案是用更新的 concat()
函数替换旧式 +
字符串连接,该函数自 SQL Server 2012 起可用。此函数在串联期间跳过 NULL
个参数,因此结果看起来总是好像 concat_null_yields_null
设置为 off
。根据您系统中 SQL 代码模块的数量,这可能是一项艰巨的任务,尤其是因为肉眼很难区分数字加法和字符串连接。
我建议货比三家,寻找一些可能对此有所帮助的代码分析/重构工具。不确定 SSDT 是否具有此功能,但我会先从它开始,因为它是免费的(试用 2 天前发布的 Visual Studio 2019 可能有意义 - 那里可能有一些东西)。除此之外,好吧... RedGate、Idera、ApexSQL,随你便。可能有人已经这样做了。
这可以通过这个查询来实现
IF (SELECT ''+NULL) IS NULL
BEGIN
SET CONCAT_NULL_YIELDS_NULL OFF
END
ELSE
BEGIN
SET CONCAT_NULL_YIELDS_NULL ON
END
我想我终于明白你真正想要的是什么:改变连接选项而不改变它。 不,没有办法实现这个,否则我会听说过它们,而 Rutzky 会在他的回答中提到它们,我在我的原始回复中引用了它们。
在设置选项的方式上存在严格的层次结构:
- 所有数据库的实例范围设置,使用
sp_configure 'user options'
。最低级别的默认值。
- 可以通过
ALTER DATABASE
设置的特定于数据库的选项。优先于实例默认值。
- 在连接上执行的显式
SET
语句。覆盖一切。
建议?如果可以,请更改应用程序的连接字符串,以便它使用另一个未设置/触摸此选项的驱动程序。当然,假设它不会崩溃,但这是一个可以相对快速测试的东西。
此外,您可以尝试更改实例默认值,并查看驱动程序是否以某种方式偏爱它们而不是 #2。它可能太聪明了。
P.S。为了完整起见,下面列出了我所知道的相互依赖选项的唯一情况:
- 快捷方式设置,例如
ANSI_DEFAULTS
。设置它实际上会影响与 ANSI 兼容性相关的几个选项;
SET LANGUAGE
。当您更改连接语言时,它还会覆盖 DATEFIRST
和 DATEFORMAT
选项。
P.P.S。我决定原封不动地保留我之前的回答,因为它仍然包含一些信息,这些信息可能对那些会像我最初那样理解你的问题的人有用。
我们有一个旧的数据库产品;主部署始终完成 ALTER Database [databasename] SET CONCAT_NULL_YIELDS_NULL OFF
。由于此设置即将消失,我们想制定一个测试计划来摆脱它并追踪依赖它的代码。
关闭此开关后,文档说 SELECT 'abc' + NULL FROM sometable
结果是 abc 而不是 NULL。
我可以很容易地在连接级别观察到这种行为;但是应用程序 never 在连接级别设置它。这不是这里的问题。
我如何通过任何 SQL 语句观察仅在数据库级别使用 .NET System.Data.SqlClient
作为数据库访问客户端关闭 CONCAT_NULL_YIELDS_NULL
的效果?
我们审核了整个代码库并删除了除事务隔离级别之外的所有 SET 命令实例,因为这些管控非常困难。虽然我尝试 EXEC
看它是否会绕过驱动程序设置并发现它没有,但我有理由相信有一些足够奇特的 SQL 构造可以成功。
即使您的应用程序没有明确指定此选项,不同的 ODBC 和 OLEDB 驱动程序也有不同的默认连接选项。根据驱动程序的不同,此特定选项可以隐式设置,也可以从数据库/服务器设置继承。
为了查看您的应用程序建立的连接的此选项的实际状态,您可以setup a Profiler trace这将显示有效的连接设置。
关于覆盖驱动程序的行为设置此选项,在 DBA StackExchange 上有一个类似的问题 thorough answer。在那里,您可以找到几种可能的方法,看看哪一种最适合您。
在 SQL 方面,一种可能的解决方案是用更新的 concat()
函数替换旧式 +
字符串连接,该函数自 SQL Server 2012 起可用。此函数在串联期间跳过 NULL
个参数,因此结果看起来总是好像 concat_null_yields_null
设置为 off
。根据您系统中 SQL 代码模块的数量,这可能是一项艰巨的任务,尤其是因为肉眼很难区分数字加法和字符串连接。
我建议货比三家,寻找一些可能对此有所帮助的代码分析/重构工具。不确定 SSDT 是否具有此功能,但我会先从它开始,因为它是免费的(试用 2 天前发布的 Visual Studio 2019 可能有意义 - 那里可能有一些东西)。除此之外,好吧... RedGate、Idera、ApexSQL,随你便。可能有人已经这样做了。
这可以通过这个查询来实现
IF (SELECT ''+NULL) IS NULL
BEGIN
SET CONCAT_NULL_YIELDS_NULL OFF
END
ELSE
BEGIN
SET CONCAT_NULL_YIELDS_NULL ON
END
我想我终于明白你真正想要的是什么:改变连接选项而不改变它。 不,没有办法实现这个,否则我会听说过它们,而 Rutzky 会在他的回答中提到它们,我在我的原始回复中引用了它们。
在设置选项的方式上存在严格的层次结构:
- 所有数据库的实例范围设置,使用
sp_configure 'user options'
。最低级别的默认值。 - 可以通过
ALTER DATABASE
设置的特定于数据库的选项。优先于实例默认值。 - 在连接上执行的显式
SET
语句。覆盖一切。
建议?如果可以,请更改应用程序的连接字符串,以便它使用另一个未设置/触摸此选项的驱动程序。当然,假设它不会崩溃,但这是一个可以相对快速测试的东西。
此外,您可以尝试更改实例默认值,并查看驱动程序是否以某种方式偏爱它们而不是 #2。它可能太聪明了。
P.S。为了完整起见,下面列出了我所知道的相互依赖选项的唯一情况:
- 快捷方式设置,例如
ANSI_DEFAULTS
。设置它实际上会影响与 ANSI 兼容性相关的几个选项; SET LANGUAGE
。当您更改连接语言时,它还会覆盖DATEFIRST
和DATEFORMAT
选项。
P.P.S。我决定原封不动地保留我之前的回答,因为它仍然包含一些信息,这些信息可能对那些会像我最初那样理解你的问题的人有用。