Sybase与SQL Server中DISTINCT CONVERT(CHAR(32), field)行为差异咨询
这个现象其实是Sybase对ANSI SQL字符串比较规则的特定实现,算不上"异常",咱们拆解一下背后的逻辑:
单独使用CONVERT(CHAR(32), field):这时候Sybase只是执行类型转换,按照CHAR(32)的定义,自动给长度不足32的字段值填充尾部空格,目的是满足固定长度CHAR类型的存储要求,这一步没有触发任何去重逻辑,所以空格会被保留。
添加DISTINCT子句后:Sybase的DISTINCT去重逻辑是基于字符串的实际语义内容而非物理存储内容的。根据早期ANSI SQL标准,CHAR类型的尾部空格属于"填充空格",在字符串比较时会被忽略——也就是说,Sybase认为
"abc"和"abc "(带多个尾部空格)是完全相同的字符串。当执行DISTINCT时,它会把这些被判定为重复的行合并,并且为了返回"语义唯一"的结果,自动修剪掉所有尾部填充空格。
对比SQL Server的差异:SQL Server在字符串比较(包括DISTINCT去重)时,会严格区分CHAR类型的尾部空格,把它们视为有效字符。所以"abc"和"abc "在SQL Server中会被判定为不同的值,DISTINCT后会保留各自的尾部空格。
举个实际验证的例子:
如果你的mytable里有两行数据,field值分别是"test"和"test "(手动添加4个空格):
- 执行
SELECT CONVERT(CHAR(32), field) FROM mytable,Sybase会返回两个32位的字符串,都带尾部空格; - 执行
SELECT DISTINCT CONVERT(CHAR(32), field) FROM mytable,Sybase只会返回一行,值为"test"(无尾部空格),因为它判定这两行是重复的。
如果需要在Sybase中保留DISTINCT后的尾部空格,可以考虑将转换后的结果转为VARCHAR类型,比如:
SELECT DISTINCT CONVERT(VARCHAR(32), field) FROM mytable
因为VARCHAR类型的尾部空格在Sybase中会被视为有效内容,DISTINCT时不会修剪。
内容的提问来源于stack exchange,提问作者Sanjiv Jivan

