有没有办法在单个可执行脚本中对三个表进行幂等插入?

Is there any way to make a idempotent insert of three tables in a single executable script?

我目前正在使用 .net 应用程序工作,当您结帐到不同的 git 分支时,该应用程序使用脚本刷新所有数据库。情况是当此脚本 'refreshes' 并清除该分支中的所有旧测试数据时,还会执行名为 'migrations' 的文件夹中的所有迁移文件。所以我正在尝试创建一个迁移,以使用幂等性在某些表中插入一些特定的值。此迁移文件必须与 'migrations' 文件夹中的其他文件一样(幂等)以便每次执行脚本时都执行,这样它就不会重复数据,保持结构并被执行多次并离开数据库处于相同状态。

插页是:

USE [$defaultDB]
GO

INSERT INTO [dbo].[Catalog]
           ([name]
           ,[description]
           ,[createdBy]
           ,[createdOn]
           ,[createdIn]
           ,[modifiedBy]
           ,[modifiedOn]
           ,[modifiedIn]
           ,[isActive]
           ,[catalogTypeID])
     VALUES
           ('PolicyClasificationID',
            'Id de clasificación de póliza',
            2,
            2022-01-20 13:43:09.687,
            '127.0.0.1',
            2,
            2022-01-20 13:43:09.687,
           '127.0.0.1',
            1,
            1,
       )

GO

INSERT INTO [dbo].[CatalogItem]
           ([catalogID]
           ,[catalogFlavorID]
           ,[parentCatalogItemID]
           ,[name]
           ,[displayLabel]
           ,[description]
           ,[catalogValue]
           ,[sequence]
           ,[createdBy]
           ,[createdOn]
           ,[createdIn]
           ,[modifiedBy]
           ,[modifiedOn]
           ,[isActive]
           ,[parentCatalogID]
           ,[parentCatalogValueID])
     VALUES

(271, 1,    NULL, 'Fidem', 'FIDEM', NULL,   1,  1,  2,  '2022-01-20 12:41:12.203', '127.0.0.1', 2,  '2022-01-20 12:41:12.203',  1,  NULL,   NULL) 
(271, 1,    NULL, 'Bac', 'BAC', NULL,   2,  2,  2,  '2022-01-21 12:41:12.203', '127.0.0.1', 2,  '2022-01-21 12:41:12.203',  1,  NULL,   NULL) 

GO

INSERT INTO [dbo].[CompanyComponentFlavor]
           ([companyID]
           ,[componentID]
           ,[subComponentID]
           ,[flavorID])
     VALUES
           (3,
            7,
            271,
            1)

END

如有任何帮助,我们将不胜感激。

没问题。让我们以您的 CatalogItem table 为例,因为您尝试插入多行,因此从概念上讲它是最具挑战性的。但是,如您所见, 并不具有挑战性。

MERGE [dbo].[CatalogItem] AS tgt
USING (
    SELECT *
    FROM (VALUES
        (271, 1,    NULL, 'Fidem', 'FIDEM', NULL,   1,  1,  2,  '2022-01-20 12:41:12.203', '127.0.0.1', 2,  '2022-01-20 12:41:12.203',  1,  NULL,   NULL),
        (271, 1,    NULL, 'Bac', 'BAC', NULL,   2,  2,  2,  '2022-01-21 12:41:12.203', '127.0.0.1', 2,  '2022-01-21 12:41:12.203',  1,  NULL,   NULL) 
    ) as x(
        [catalogID]
        ,[catalogFlavorID]
        ,[parentCatalogItemID]
        ,[name]
        ,[displayLabel]
        ,[description]
        ,[catalogValue]
        ,[sequence]
        ,[createdBy]
        ,[createdOn]
        ,[createdIn]
        ,[modifiedBy]
        ,[modifiedOn]
        ,[isActive]
        ,[parentCatalogID]
        ,[parentCatalogValueID]
    )
) AS src
    ON src.[catalogID] = tgt.[catalogID]
WHEN NOT MATCHED BY TARGET THEN
    INSERT (
            [catalogID]
            ,[catalogFlavorID]
            ,[parentCatalogItemID]
            ,[name]
            ,[displayLabel]
            ,[description]
            ,[catalogValue]
            ,[sequence]
            ,[createdBy]
            ,[createdOn]
            ,[createdIn]
            ,[modifiedBy]
            ,[modifiedOn]
            ,[isActive]
            ,[parentCatalogID]
            ,[parentCatalogValueID]
        )
    VALUES (
        src.[catalogID]
        ,src.[catalogFlavorID]
        ,src.[parentCatalogItemID]
        ,src.[name]
        ,src.[displayLabel]
        ,src.[description]
        ,src.[catalogValue]
        ,src.[sequence]
        ,src.[createdBy]
        ,src.[createdOn]
        ,src.[createdIn]
        ,src.[modifiedBy]
        ,src.[modifiedOn]
        ,src.[isActive]
        ,src.[parentCatalogID]
        ,src.[parentCatalogValueID]
    );

这里基本上发生了两件事。第一个是我正在使用 MERGE 语句。它允许“如果不存在则插入”类型的操作(除其他外)。它因一些奇怪的行为而声名狼藉。但是对于您描述的用例(即铺设一个核开发环境),它感觉很合适。此 MERGE 语句的所有含义是“如果目标 table 中缺少给定行(由目录 ID 标识),则将其插入”。

您可能不习惯看到的第二件事是使用行值构造函数作为数据源。这只是我几年前学会的一个技巧,当临时 table 没有意义时,我倾向于使用它。

我在这里展示的最后一件事是,您可能希望也可能不希望在所有三个 table 中“全有或全无”插入缺失数据。如果是这样,通过将“BEGIN TRAN/COMMIT”放在 begin/end(分别)处,将您想要作为一个单元执行的所有内容包装在事务中。不过,对于这种情况,这对我来说有点过分了。