我正在尝试编写一个幂等数据库迁移脚本,除其他外,它需要重新调整一些数据。稍后在脚本中,我选择的一个列被删除(迁移的目的是将数据从该列移动到一个新的位置),所以我有类似的东西(由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
,在实际运行之前不验证所有列的存在?
答案 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