从一个名为#table的临时表中选择数据,该表中有一列名为sp_renamed,但在SQL Server 2019及更高版本中此操作不再生效
在一个存储过程(版本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 选项似乎是显而易见的修复办法。
我认为你有以下选项:
- 在存储过程定义中添加
WITH RECOMPILE。 - 在执行存储过程的
EXEC ...中添加WITH RECOMPILE。 - 在出现问题的具体查询中添加
OPTION(RECOMPILE)。(感谢OP发现并实现了这个选项——很可能是最佳选择。) - 将你的代码重写,正如你在
#headerY情况中所做的那样。
请参阅 this db<>fiddle。通过取消注释标记为 "option #1" - "option #4" 的相应行,和/或更改所选的SQL Server版本来比较结果。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。