兼容级别 80 和 100 之间的可变长度字符串问题

Pab*_*bra 6 sql-server-2008 sql-server varchar sql-server-2016 compatibility-level

在我当前的企业中,我遇到了大量与特定场景相关的问题。

我们有一个 SQL Server 2008,我们想迁移到 SQL Server 2016,所以我们将兼容性从 80 迁移到 100,但是我们的一些存储过程有问题,如下代码所示:

CREATE TABLE #PRUEBA (texto1 char(30), condicion char(30)) 
INSERT INTO  #PRUEBA VALUES ('PFI','1') 
INSERT INTO #PRUEBA VALUES ('CFI','2') 
SELECT 
    CASE
        WHEN condicion= '1' THEN texto1 
        ELSE 'TFI'
    END 
FROM  #PRUEBA 
DROP TABLE #PRUEBA
Run Code Online (Sandbox Code Playgroud)

兼容性 -> 80

'PFI                           ' -> char of 30 length 
'TFI                           ' -> char of 30 length
Run Code Online (Sandbox Code Playgroud)

兼容性 -> 90

'PFI                           ' -> varchar of 30 length
'TFI'                            -> varchar of 3 length
Run Code Online (Sandbox Code Playgroud)

兼容性 -> 100

'PFI                           ' -> varchar of 30 length
'TFI'                            -> varchar of 3 length
Run Code Online (Sandbox Code Playgroud)

为什么会这样?

我们可以保留空格来获得与兼容性80相同的结果,而无需更改查询,只需在服务器上进行配置即可?

是否有任何解决方案可以在兼容性 100 上获得与兼容性 80 相同的结果?

Sol*_*zky 6

我们可以保留空格来获得与兼容性80相同的结果,而无需更改查询,只需在服务器上进行配置即可?

不,不是我所知道的。这是关于表达式的数据类型优先级问题CASECASE无论选择哪个分支,表达式都需要返回一致的数据类型。由于VARCHAR具有比 更高的优先级CHAR,这里唯一的选择是返回VARCHAR。看起来您需要更新代码才能将CASE表达式的结果转换为CHAR(30). 例如:

SELECT
    CONVERT(CHAR(30), CASE
                        WHEN condicion= '1' THEN texto1
                        ELSE 'TFI'
                      END)
FROM  #PRUEBA
Run Code Online (Sandbox Code Playgroud)

或者,我想您可以简单地转换字符串文字以匹配列的数据类型:

SELECT
    CASE
      WHEN condicion= '1' THEN texto1
      ELSE CONVERT(CHAR(30), 'TFI')
    END
FROM  #PRUEBA
Run Code Online (Sandbox Code Playgroud)

另外,您为什么使用兼容级别 80?那是针对 SQL Server 2000。而您即将升级到 SQL Server 2016?默认情况下,兼容性级别为 130。幸运的是,SQL Server 2016 中提供了级别 100,尽管它是可用的最低级别。尽管如此,如果您目前依赖于 SQL Server 2000 的行为,那么如果迁移到 SQL Server 2016,您可能需要进行更多更改。