SQL Server事务中出现“无效列名”错误

5
我有一个脚本,我正在向表中添加一列,并立即从另一个表中填充该列的数据。但是,我在添加的列上得到了“无效列名”的错误。
具体地说,错误是“无效列名'tagID'”。
在“BEGIN TRANSACTION”和“COMMIT”之间的代码实际上是一个更大脚本的摘录,但这是相关的摘录(我需要所有内容成功或简单地回滚)。
BEGIN TRY
BEGIN TRANSACTION
  ALTER TABLE [Items] ADD tagID [uniqueidentifier] NULL

  MERGE INTO
    Items AS target
  USING
    Tags AS t ON t.tag = target.tag
  WHEN MATCHED THEN
    UPDATE SET target.tagID = t.id;
COMMIT
END TRY
BEGIN CATCH
  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION
END CATCH
GO

你有仔细检查 Items.tagID 是否存在吗?在上面的代码片段中之前,你是否在脚本中添加了 Items.tagID 并且处于同一批处理之中?如果是这样的话,合并语句的解析会在列创建之前发生,并且会在任何运行之前失败。 - Shannon Severance
你能单独执行ALTER TABLE命令而不出现问题吗? - gmiley
我认为这将为您提供有关您问题的一些信息。 https://dev59.com/WlvUa4cB1Zd3GeqPsEo-#7452280 - DVT
@gmiley 是的,ALTER TABLE 命令可以单独运行而不会出现问题。 @Shannon 是否有办法解决这个解析问题,还是我必须使用两个单独的事务? - charmeleon
1
这与事务无关,而是编译问题。 - Martin Smith
2个回答

5
SQL Server尝试编译批处理中的所有语句。如果表不存在,则该语句的编译被推迟,但是对于缺失列没有延迟编译。
您可以使用:
BEGIN TRY
BEGIN TRANSACTION
  ALTER TABLE [Items] ADD tagID [uniqueidentifier] NULL
  EXEC('
  MERGE INTO
    Items AS target
  USING
    Tags AS t ON t.tag = target.tag
  WHEN MATCHED THEN
    UPDATE SET target.tagID = t.id;
 ')
COMMIT
END TRY
BEGIN CATCH
  IF @@TRANCOUNT > 0
    ROLLBACK TRANSACTION
END CATCH
GO

把列使用推入在创建列后编译的子批处理中。它仍然属于在父范围内打开的同一事务。


0

事务范围适用于 DML 操作,而不适用于 DDL 操作。因此,我不确定为什么您在同一事务块中使用 ALTER 语句。如果没有错的话,您应该将该 ALTER 语句放在事务块之外。

  ALTER TABLE [Items] ADD tagID [uniqueidentifier] NULL
BEGIN TRANSACTION
  MERGE INTO
  .....

此外,我建议您从ALTER语句中删除列数据类型中的[]
ALTER TABLE [Items] ADD tagID UniqueIdentifier;

我有些困惑,根据https://dev59.com/jW445IYBdhLWcg3wytMU#4736346的说法,SQL Server中存在事务性DDL。您是在说我不能将DML和DDL组合在同一个事务中,还是DDL不能在SQL Server中进行事务处理?(请原谅我的无知,到目前为止我只使用过MySQL) - charmeleon
@charmeleon,看起来在SQL Server中DDL命令也是事务的一部分,但通常DML都会被包含在事务块中。所以你可以将其放在事务中...但在你的情况下,请检查ALTER语句并尝试将其放在事务块之外。也许可以将其放在一个单独的事务块中。 - Rahul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接