SQL Server pad右脚本中的原因不明的运算符优先级

时间:2011-10-19 01:42:16

标签: sql-server sql-server-2005 tsql sql-server-2008

作为生成零填充唯一标识符的请求的一部分,我创建了我认为简单的语句

right('00000000' + convert(char(6),ID),6)

但是,这根本不是零填充字符。 进一步的调查显示,一切都不像我预期的那样。 参见:

drop table #test 
go
select --top 30
    right('00000000' + convert(varchar(6),ID),6) varcharPadRight, --results in varchar(6) in tempdb
    right('00000000' + convert(char(6),ID),6) charPadRight, --results in varchar(6) in tempdb
    right('00000000' + convert(char(6),ID),20) charPadRight20, --results in varchar(14) in tempdb
    right('00000000' + convert(varchar(6),ID),20) vcharPadRight20 --results in varchar(14) in tempdb
into #test
from requestidentifier aTableWithAnIntIdentityColumn
where aTableWithAnIntIdentityColumn.ID in (1,100,1000)
go
select * from #test

select left(so.name, 5) name,sc.name, sc.xtype, sc.length from tempdb..sysobjects so inner join tempdb..syscolumns sc on so.id = sc.id where so.name like '%test%'

结果如下:

varcharPadRight charPadRight charPadRight20 vcharPadRight20
--------------- ------------ -------------- ---------------
000100          100          00000000100    00000000100
001000          1000         000000001000   000000001000
000001          1            000000001      000000001

tableName colName        xtype length
--------- -------------- ----- ------
#test     varcharPadRigh 167   6
#test     charPadRight   167   6
#test     charPadRight20 167   14
#test     vcharPadRight2 167   14

其中xtype为167是varchar。

有没有人可以解释导致这些(对我而言)意外结果的操作顺序?

(此行为在SQL Server 2005和2008中是一致的)

2 个答案:

答案 0 :(得分:2)

简单的解释是char数据类型在右边有空格,使其成为变量的长度。因此,如果你有一个char(6)并将其设置为'3',那么变量中的值实际上将是3空间空间空间空间。这是一个3后跟5个空格,使总长度= 6个字符。

当你在字符串的左边添加6个零时,SQL正在进行一些数据类型转换。对字符串进行硬编码将产生varchar,因此'000000'将具有数据类型varchar(6)。附加char和varchar时,结果是一个长度合并的varchar。

'000000' + Convert(Char(6), int)
VarChar(6) + Char(6)
varchar(12)

Char(6)部分仍然会在数据的右侧填充空格,因此当您选取6个最右边的字符时,您将获得空格。

varchar不会在末尾填充空格,因此它的工作方式与您期望的完全相同。

PROOF:

Declare @ID Int
Set @Id = 3

-- Data type after converting to char (results in char(6))
SELECT SQL_VARIANT_PROPERTY(Convert(Char(6), @id), 'BaseType') As DatType, 
       SQL_VARIANT_PROPERTY(Convert(Char(6), @id), 'MaxLength') As Length,
       Convert(Char(6), @id)

-- data type of hard coded string (Results in varchar(6))
SELECT SQL_VARIANT_PROPERTY('000000', 'BaseType') As DatType, 
       SQL_VARIANT_PROPERTY('000000', 'MaxLength') As Length,
       '000000'

-- data type of varchar concatenate char (Results in varchar(12))
SELECT SQL_VARIANT_PROPERTY('000000' + Convert(Char(6), @id), 'BaseType') As DataType,
       SQL_VARIANT_PROPERTY('000000' + Convert(Char(6), @id), 'MaxLength') As Length,
       '000000' + Convert(Char(6), @id)

-- data type of the result (results in varchar(6))
SELECT SQL_VARIANT_PROPERTY(Right('000000' + Convert(Char(6), @id), 6), 'BaseType') As DataType,
       SQL_VARIANT_PROPERTY(Right('000000' + Convert(Char(6), @id), 6), 'MaxLength') As Length,
       Right('000000' + Convert(Char(6), @id), 6)

答案 1 :(得分:1)

将int转换为char(6)左对齐,所以

   int -> char(6) -> '000' + char(6) -> right('000' + char(6))
    1  -> 1______ -> '0001_____'     -> '1_____'
    10 -> 10_____ -> '00010____'     -> '10____'
    etc

因此,代码中的rtrim将给出预期的结果 e.g。

right('00000000' + rtrim(convert(char(6),ID)),6)