从一个名为#table的临时表中选择数据,该表中有一列名为sp_renamed,但在SQL Server 2019及更高版本中此操作不再生效

编程语言 2026-07-11

在一个存储过程(版本2019)中,将 #table 的列重命名为 @value,在后续执行中就失效。#table 会保留第一次执行时的 @value 名称。

这是疏忽吗,还是有意为之(也许有文档记载)?

create procedure testSP 
    @resultsetcolumn sysname
    --with recompile --not an option
as
    set @resultsetcolumn = parsename(@resultsetcolumn, 1)
    declare @data table
                  (
                      col1 int default(1), 
                      col2 int default(2), 
                      col3 int default(3), 
                      col4 int default(4)
                  )

    insert into @data default values

    create table #headerX (a int, b int, c int, d int)

    execute tempdb.sys.sp_rename '#headerX.b', @resultsetcolumn, 'column'

    select * from #headerX
    union all
    select * from @data

    create table #headerY (a int)

    set @resultsetcolumn = quotename(@resultsetcolumn)
    exec('alter table #headerY add '+@resultsetcolumn+' int, c int, d int')

    select * from #headerY
    union all
    select * from @data

举例来说,请切换以下dbfiddle.uk链接所对应的SQL Server版本:https://dbfiddle.uk/WS7zT95W

解决方案

如果在 EXEC sp_rename ... 之后立即插入语句 SELECT * FROM TempDB.sys.columns WHERE object_id = OBJECT_ID('tempdb..#headerX') ORDER BY column_id,你将看到该列实际上已经被重命名。问题似乎在于,SQL Server最初意识到需要对紧随 sp_rename 的查询进行延迟编译,但随后在后续执行中复用已编译的代码,假设参数值的变化并不显著。

是的,这确实似乎是从2017版本到2019版本的一个破坏性变更,并未在 breaking change documentation 中列出,但 WITH RECOMPILE 选项似乎是显而易见的修复办法。

我认为你有以下选项:

  1. 在存储过程定义中添加 WITH RECOMPILE
  2. 在执行存储过程的 EXEC ... 中添加 WITH RECOMPILE
  3. 在出现问题的具体查询中添加 OPTION(RECOMPILE)(感谢OP发现并实现了这个选项——很可能是最佳选择。)
  4. 将你的代码重写,正如你在 #headerY 情况中所做的那样。

请参阅 this db<>fiddle。通过取消注释标记为 "option #1" - "option #4" 的相应行,和/或更改所选的SQL Server版本来比较结果。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章