如果列存在,则有条件地插入表中

时间:2018-01-16 15:54:57

标签: sql-server tsql idempotent

我正在尝试编写一个幂等数据库迁移脚本,除其他外,它需要重新调整一些数据。稍后在脚本中,我选择的一个列被删除(迁移的目的是将数据从该列移动到一个新的位置),所以我有类似的东西(由EF Core生成):

IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'AName')
BEGIN
     INSERT INTO Foos (A, B)
     SELECT OldA, OldB FROM Bars
END

-- a little later in the script:

IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] WHERE [MigrationId] = N'AnotherName')
BEGIN
      ALTER TABLE [Bars] DROP COLUMN [OldB];
END

然而,这并不像我希望的那样是幂等的;第二次运行脚本时,它失败并在第一个INSERT语句中出错,因为OldB列不再存在于Bars

但是,如果OldB被删除,上面的guard子句总是为false,因为在删除OldB的同时,我们也会将该行插入迁移历史(是的,我已经检查过现在也是如此;行存在)。因此INSERT 永远不会运行而不会关注现有的所有列。

如何编写与上述类似的幂等INSERT,在实际运行之前不验证所有列的存在?

1 个答案:

答案 0 :(得分:2)

您可以检查是否所有列都存在:

IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] 
               WHERE [MigrationId] = N'AName')
BEGIN
     IF (SELECT COUNT(*) 
        FROM sys.columns 
        WHERE [object_id] = OBJECT_ID('Bars')
          AND name IN ('OldA', 'OldB')) = 2
     BEGIN
          EXEC('INSERT INTO Foos (A, B)
          SELECT OldA, OldB FROM Bars');
     END
END

-- a little later in the script:

IF NOT EXISTS (SELECT * FROM [__EFMigrationsHistory] 
               WHERE [MigrationId] = N'AnotherName')
BEGIN
      EXEC('ALTER TABLE [Bars] DROP COLUMN [OldB]');
END