无法插入新创建的列

Tom*_*ter 8 sql-server t-sql sql-server-2008-r2

我有一个简单的测试表,如下所示:

CREATE TABLE MyTable (x INT);
Run Code Online (Sandbox Code Playgroud)

在事务中,我尝试添加一列,然后插入到新创建的列中:

BEGIN TRANSACTION;
    PRINT 'Adding column, ''SupplementalDividends'', to MyTable table.';

    ALTER TABLE MyTable
        ADD SupplementalDividends DECIMAL(18,6);

    PRINT 'Column added successfully....';

    PRINT 'Ready to INSERT into MyTable ...';

    INSERT INTO MyTable (x, SupplementalDividends)
        VALUES (1, 3.2);

    PRINT '**** CHANGES COMPLETE -- COMMITTING.';
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

当我运行上面的代码时,问题是一条错误消息:

Invalid column name 'SupplementalDividends'.
Run Code Online (Sandbox Code Playgroud)

为什么这会导致错误?如果我在交易之外的不同批次中添加该列,它将起作用。我的问题是我在事务中添加列。为什么会出错?

spa*_*dba 10

这是一个有约束力的问题。代码在编译时绑定到表的元数据,而不是后期绑定。尝试使用 EXEC 和动态 SQL 来克服此限制:

BEGIN TRANSACTION;
    PRINT 'Adding column, ''SupplementalDividends'', to MyTable table.';

    ALTER TABLE MyTable
        ADD SupplementalDividends DECIMAL(18,6);

    PRINT 'Column added successfully....';

    PRINT 'Ready to INSERT into MyTable ...';
    EXEC('
    INSERT INTO MyTable (x, SupplementalDividends)
        VALUES (1, 3.2);
    ')

    PRINT '**** CHANGES COMPLETE -- COMMITTING.';
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用存储过程插入数据:后期绑定适用于存储过程,但不适用于即席查询。同样,您必须使用动态 SQL 来创建过程,但它可以让您更轻松地传递参数:

BEGIN TRANSACTION;
    PRINT 'Adding column, ''SupplementalDividends'', to MyTable table.';

    ALTER TABLE MyTable
        ADD SupplementalDividends DECIMAL(18,6);

    PRINT 'Column added successfully....';

    PRINT 'Ready to INSERT into MyTable ...';

    EXEC('
    CREATE PROCEDURE insData @p1 int, @p2 DECIMAL(18,6)
    AS
    BEGIN 
        INSERT INTO MyTable (x, SupplementalDividends)
        VALUES (@p1, @p2);
    END')

    EXEC InsData 1, 3.2;

    PRINT '**** CHANGES COMPLETE -- COMMITTING.';
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

临时存储过程也可以:

BEGIN TRANSACTION;
    PRINT 'Adding column, ''SupplementalDividends'', to MyTable table.';

    ALTER TABLE MyTable
        ADD SupplementalDividends DECIMAL(18,6);

    PRINT 'Column added successfully....';

    PRINT 'Ready to INSERT into MyTable ...';

    EXEC('
    CREATE PROCEDURE #insData @p1 int, @p2 DECIMAL(18,6)
    AS
    BEGIN 
        INSERT INTO MyTable (x, SupplementalDividends)
        VALUES (@p1, @p2);
    END')

    EXEC #InsData 1, 3.2;

    PRINT '**** CHANGES COMPLETE -- COMMITTING.';
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)


Aar*_*and 6

只是想澄清一下,这是运行时的问题,而不是编译时的问题,与它们在同一个事务中的事实无关。例如,假设我们有这张表:

CREATE TABLE dbo.floob(a int);
Run Code Online (Sandbox Code Playgroud)

以下批处理成功解析(编译时),但在运行时它会收到您在问题中提到的错误:

BEGIN TRANSACTION;
  ALTER TABLE dbo.floob ADD b int;

  SELECT b FROM dbo.floob;
COMMIT TRANSACTION;
Run Code Online (Sandbox Code Playgroud)

在 Management Studio 的查询编辑器中,您可以通过以下方式轻松解决此问题:

  1. 高亮前两行,点击执行,然后高亮后两行,点击执行;或者,
  2. 在它们之间放置一个批处理分隔符,如下所示:

    BEGIN TRANSACTION;
      ALTER TABLE dbo.floob ADD c int;
    
    GO
    
      SELECT c FROM dbo.floob;
    COMMIT TRANSACTION;
    
    Run Code Online (Sandbox Code Playgroud)

如果您从 SQL Server 外部运行它(例如,从您的应用程序代码发送一个 SQL 批处理),您可以简单地以类似的方式分别发送两个批处理,或者如果您绝对需要将其作为一个批处理发送,您可以使用动态 SQL(如Gianluca 的回答)来推迟名称解析。