预先警告:乍一看这个问题可能没有意义,但希望任何人都可以通过在他们的本地 Sql Server 实例上尝试这个来玩。
考虑到所有这些,请考虑两个脚本:
Create.sql
:
Drop Table If Exists dbo.MyMysteryTable;
Create Table dbo.MyMysteryTable
(
A SmallInt Not Null
,B VarChar(32) Not Null
,C VarChar(128) Not Null
,D SmallDateTime Null
,E SmallInt Not Null
,F Char(1) Not Null
,G VarChar(16) Not Null
);
Insert dbo.MyMysteryTable(A, B, C, D, E, F, G)
Values (1, 'B1', 'C1', Null, 1, '1', 'G1')
,(2, 'B2', 'C2', Null, 2, '2', 'G2');
奇怪的是
WTF.sql
(我基本上重建表并将列重命名C
为Cx
然后向其添加新行的脚本。):
Drop Table If Exists #Temp;
Select A
,B
,C
,D
,E
,F
,G
Into #Temp
From dbo.MyMysteryTable;
Drop Table If Exists dbo.MyMysteryTable;
Create Table dbo.MyMysteryTable
(
A SmallInt Not Null
,B VarChar(32) Not Null
,Cx VarChar(128) Not Null
,D SmallDateTime Null
,E SmallInt Not Null
,F Char(1) Not Null
,G VarChar(16) Not Null
);
-- Insert #1
Insert dbo.MyMysteryTable(A, B, Cx, D, E, F, G)
Select *
From #Temp;
-- Insert #2
Insert dbo.MyMysteryTable(A, B, Cx, D, E, F, G)
Values (3, 'B3', 'C3', Null, 3, '3', 'G3');
我完全意识到 Sql Server 有时无法看到更新的元数据的非常烦人的偏好,这通常需要一个人实现一个Go
强制它“刷新”它是编译器的底层模式的视图。
然而,让我陷入绝对循环的是解析器接受Insert #1成功,但拒绝Insert #2:
Msg 207, Level 16, State 1, Line 30
Invalid column name 'Cx'.
两者都使用完全相同的列列表,但只有一个在编译时被认为是可以接受的。我会冒险猜测并说 Sql 看到的是第一个Insert
正在使用临时表,因此它可能正在不同级别查看元数据必须执行 aTable Scan
并将其提供给Table Insert
运算符,而不是被能够为Insert #2使用直接插入。
现在好消息是我有一个非常简单的解决方法:
Workaround.sql
:
Drop Table If Exists #Temp;
Select A
,B
,C
,D
,E
,F
,G
Into #Temp
From dbo.MyMysteryTable;
Drop Table If Exists dbo.MyMysteryTable;
Create Table dbo.MyMysteryTable
(
A SmallInt Not Null
,B VarChar(32) Not Null
,Cx VarChar(128) Not Null
,D SmallDateTime Null
,E SmallInt Not Null
,F Char(1) Not Null
,G VarChar(16) Not Null
);
-- Insert #2
Insert #Temp
Values (3, 'B3', 'C3', Null, 3, '3', 'G3');
-- Insert #1
Insert dbo.MyMysteryTable(A, B, Cx, D, E, F, G)
Select *
From #Temp;
哪个工作正常。我不确定为什么,因为如果关于同一批次的表更改和用法的规则肯定仍然会被发现,但我离题了……
然而......已经工作了,Sql Server 变得更加困惑,如果一个然后尝试重新运行原始的Create.Sql
并且WTF.sql
在与用于执行的会话相同的会话中Workaround.sql
,那么它无法解析插入#1(这是更令人期待的) .
Msg 207, Level 16, State 1, Line 25
Invalid column name 'Cx'.
如果重新运行Create.sql
然后选择一个新会话来运行WTF.sql
,那么它将返回到第 30 行失败。
这让我完全不解。就像我说的,我有一个变通办法,所以我不会被耽搁,但我完全着迷于为什么我会观察到这种行为。
有人有任何想法吗?
这已经针对 Sql Server 2019 和 Sql Server 2022 进行了测试——同时使用SSMS和Azure Data Studio。
对于它的价值,我确实有一个Sql Fiddle,但它不是很有用,因为它显然不喜欢#Temp 表。
注意:我要重建表格还有一个更大的原因——我只是在今晚的后端遇到这个问题之后简化了我的代码步骤。