T-SQL 2008 中的 REPLACE 函数与 T-SQL 2005 不同

Posted

技术标签:

【中文标题】T-SQL 2008 中的 REPLACE 函数与 T-SQL 2005 不同【英文标题】:REPLACE function in T-SQL 2008 is different from T-SQL 2005 【发布时间】:2011-10-22 13:34:13 【问题描述】:

我正在进行将数据库从 SQL Server 2005 迁移到 2008 的项目。

在测试过程中,我发现了一个不一致之处。根据 BOL http://msdn.microsoft.com/en-us/library/ms186862(v=SQL.100).aspx (2008) 和 http://msdn.microsoft.com/en-us/library/ms186862(v=SQL.90).aspx (2005) 返回 varchar。到目前为止,两者都是一样的。但是,如果我们传递给REPLACE 函数列类型char,那么差异就会出现。看这段代码

declare @test table
(
  testcharstring char(25)
) 

insert into @test
  select 'Hello'
  union
  select 'World'
  union
  select 'Hello world '

select 
  '"'+testcharstring+'"' as original
  ,'"'+replace(testcharstring,'a','A')+'"' as afterreplace
  --,'"'+replace(rtrim(testcharstring),'a','A')+'"'
from @test

来自 SQL Server 2005 的结果

original                    afterreplace
--------------------------- ---------------------------
"Hello                    " "Hello"
"Hello world              " "Hello world"
"World                    " "World"

来自 SQL Server 2008 的结果

original                    afterreplace
--------------------------- ---------------------------
"Hello                    " "Hello                    "
"Hello world              " "Hello world              "
"World                    " "World                    "

SQL Server 2005 中的 T-SQL 甚至删除了合法的尾随空格,并不是说它像 varchar(25) 一样威胁 char(25)。 SQL Server 2008 中的 T-SQL 更仔细地处理类型,并根据接收到的用于转换的类型返回结果

我在不同的 T-SQL 对象中有数字位置,主要是在触发器中。主要思想只是为了在 SQL Server 2008 中进行最小的更改以保持相同的行为

可能的方法

覆盖内置 REPLACE 函数快速搜索表明不可能,但我的队友想要研究该选项 将Rtrim() 函数与REPLACE 一起使用。这将需要在多个例程中的代码中的确切位置进行替换(使用 char 列) 在 CLR 中创建自己的版本 Replace 以查看 CLR 允许我保留 SQL Server 2005 的行为,然后在确切位置再次搜索和替换功能

想问问大家有没有遇到过这个问题,你们是怎么解决的?

也欢迎任何建议,可能我只是不知道服务器实例或数据库级别的哪些设置可以改变行为。

提前感谢您!

【问题讨论】:

如果将 char(25) 更改为 nchar(25) 2005 年的结果将与 2008 年相同,我自己对原因感兴趣。 【参考方案1】:

你有不同的SET ANSI_PADDING选项,也可以通过SET ANSI_DEFAULTS控制

就目前而言,REPLACE 在两个版本中的行为相同。两者(2005,2008)都说:

如果输入参数之一是 nvarchar 数据类型,则返回 nvarchar;否则,REPLACE 返回 varchar。

编辑:有 2 个连接错误/功能

我上面的回答可能是错的

http://connect.microsoft.com/SQLServer/feedback/details/259840/trailing-spaces-are-lost-when-a-char-value-is-fed-to-replace

检查数据库兼容级别:

http://connect.microsoft.com/SQLServer/feedback/details/126092/t-sql-replace-function-seems-to-be-broken-for-char-x-variables

作为修复,抱歉,我会使用 rtrim,但它是修复吗?您不能覆盖替换,如果您计划紧急 clr,为什么不将替换/rtrim 包装在 SQL udf 中

【讨论】:

+1 :说“版本 X 的行为与版本 Y 不同”很容易,但要检查所有服务器的设置实际上是否相同则要困难得多。但是检查你应该;如果你不这样做,你可能会遇到迁移问题(尤其是字符串)。 @gbn 谢谢你的链接。我玩了所有设置,但结果相同。必须使用 RTRIM @likhtin: 是的,但是您可以使用 SQL udf 来包装它。如前所述,存在一些问题,因此您正在解决 SQL Server 中的一些已知错误【参考方案2】:

根据 MS,这是正确的行为,而 SQL2005 有错误。 在您的代码中,您不仅将 Replace() 用作校正函数 (查找一个模式并用另一个模式替换),而且还用作 Trim() 函数 (如果没有找到至少修剪传入的值)

但是当你使用 Char() 时这是错误的。使用 Char() 作为数据类型的唯一原因是不惜一切代价保留值数据长度。(恕我直言)因为您需要确保返回值长度始终相同,而不管实际存储的字符数如何。 当您需要使用字符串连接构建某种结构时,这一点很重要 与用于输出的固定长度文件一样,并且不关心数据长度检查或转换。 否则你不妨使用 varchar() 或 nvarchar()

http://msdn.microsoft.com/en-us/library/ms143359(v=sql.100).aspx

在 SQL Server 2005 中,当参数为 char 类型时,REPLACE 函数的第一个输入参数中指定的尾随空格将被修剪。例如,在语句 SELECT '' 中,值 'ABC' 被错误地评估为 'ABC'。

在 SQL Server 2008 中,始终保留尾随空格。对于依赖函数先前行为的应用程序,在指定函数的第一个输入参数时使用 RTRIM 函数。例如,以下语法将重现 SQL Server 2005 行为 SELECT ''。

【讨论】:

以上是关于T-SQL 2008 中的 REPLACE 函数与 T-SQL 2005 不同的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 与 T-SQL 中的 Cast 和 Convert 函数有啥区别? [复制]

SQL Server 2008 T-SQL UDF Split() 剪裁

在 T-SQL 中对字符范围使用通配符

等效于 Amazon Redshift 中的 T-SQL 表值构造函数?

替换 T-SQL 中的 Unicode 字符

如何将数据从一个表移动到另一个表并更新外键 (T-SQL 2008)