【问题标题】:Check if record exists while inserting using User defined table type sql server使用用户定义的表类型 sql server 插入时检查记录是否存在
【发布时间】:2014-11-13 04:57:14
【问题描述】:

我正在尝试在 sql server 中批量插入记录。我正在使用用户定义的表类型来传递来自我的 .net 应用程序的记录集合。请看下面的插入查询。

INSERT INTO MachineItems([Name],[Price],[Quantity],[ItemGroupID],[SubGroup] ,[IsDefault],
    [IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn] )

    SELECT mi.Name
    ,mi.Price
    ,mi.Quantity
    ,(SELECT ID from ItemGroups WHERE NAME=mi.ItemGroup) as ID
    ,mi.SubGroup,
    CASE 
      WHEN mi.IsDefault ='Yes' THEN 1 
      WHEN mi.IsDefault ='No' THEN 0 
      WHEN mi.IsDefault IS NULL THEN 0
     END ,
     CASE 
      WHEN mi.IsRemovable ='Yes' THEN 1 
      WHEN mi.IsRemovable ='No' THEN 0 
     END ,
    (SELECT ID from MachineTypes WHERE Name=mi.MachineType),
    (SELECT ID from MachineItemTypes WHERE Name=mi.ItemType),
    mi.CreatedBy 
    ,mi.CreatedOn       
    FROM @MachineItems mi

我要做的是在插入记录之前进行检查,表中是否已经存在具有 [MachineTypeID] 和 [Name] 的记录。如果不存在则插入 Eles 更新记录。

如何使用用户定义的表类型来做到这一点?

【问题讨论】:

    标签: sql-server constraints sql-insert user-defined-types


    【解决方案1】:
    1. 您应该使用MERGE 命令而不是直接插入。您想要做的并不是真正特定于用户定义的表类型。

    2. 如果您加入 3 个子表而不是为每行执行的列创建子查询,那会更好/更有效。

    例子:

    MERGE MachineItems AS Target
    USING (SELECT mi.Name,
                  mi.Price,
                  mi.Quantity,
                  ig.ID, -- ItemGroupID
                  mi.SubGroup,
                  CASE 
                     WHEN mi.IsDefault ='Yes' THEN 1 
                     WHEN mi.IsDefault ='No' THEN 0 
                     WHEN mi.IsDefault IS NULL THEN 0
                  END, -- IsDefault
                  CASE 
                     WHEN mi.IsRemovable ='Yes' THEN 1 
                     WHEN mi.IsRemovable ='No' THEN 0 
                  END, -- IsRemovable
                  mt.ID, -- MachineTypeID
                  mit.ID, -- ItemType
                  mi.CreatedBy,
                  mi.CreatedOn
           FROM   @MachineItems mi
           INNER JOIN ItemGroups ig
                   ON ig.[Name] = mi.ItemGroup
           INNER JOIN MachineTypes mt
                   ON mt.[Name] = mi.MachineType
           INNER JOIN MachineItemTypes mit
                   ON mit.[Name] = mi.ItemType) AS Source (
                       [Name],[Price],[Quantity],[ItemGroupID],[SubGroup],[IsDefault],
                       [IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn])
    ON (
             Target.[MachineTypeID] = Source.[MachineTypeID]
        AND  Target.[Name] = Source.[Name]
        )
    WHEN MATCHED THEN 
         UPDATE SET Price = Source.Price,
                    Quantity = Source.Quantity,
                    ItemGroupID = Source.ItemGroupID,
                    SubGroup = Source.SubGroup,
                    IsDefault = Source.IsDefault,
                    IsRemovable = Source.IsRemovable,
                    MachineTypeID = Source.MachineTypeID,
                    ItemType = Source.ItemType,
                    CreatedBy = Source.CreatedBy,
                    CreatedOn = Source.CreatedOn
    WHEN NOT MATCHED BY TARGET THEN
         INSERT ([Name],[Price],[Quantity],[ItemGroupID],[SubGroup] ,[IsDefault],
                 [IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn])
         VALUES (Source.[Name], Source.[Price], Source.[Quantity], Source.[ItemGroupID],
                 Source.[SubGroup], Source.[IsDefault], Source.[IsRemovable],
                 Source.[MachineTypeID], Source.[ItemType], Source.[CreatedBy],
                 Source.[CreatedOn]);
    

    【讨论】:

    • 感谢您的建议。我会那样做的。
    • @SachinTrivedi :完成更新。查询应该现在完全可以工作了。
    • 这个更新语句给了我错误。 MERGE 语句多次尝试更新或删除同一行。当目标行匹配多个源行时会发生这种情况。 MERGE 语句不能多次 UPDATE/DELETE 目标表的同一行。优化 ON 子句以确保目标行最多匹配一个源行,或使用 GROUP BY 子句对源行进行分组。
    【解决方案2】:

    您可以在此处使用Merge

    使用Merge

    1. 如果不存在,您可以插入
    2. 如果已经存在,您可以删除
    3. 如果已经存在,您可以更新

    MERGE MachineItems
    USING @MachineItems ON MachineItems.id = @MachineItems.id
    and MachineItems.Name=@MachineItems.Name
    WHEN NOT MATCHED THEN
    INSERT INTO MachineItems([Name],[Price],[Quantity],[ItemGroupID],[SubGroup]         
    ,[IsDefault],
    [IsRemovable],[MachineTypeID],[ItemType],[CreatedBy],[CreatedOn] )
    
        SELECT mi.Name
        ,mi.Price
        ,mi.Quantity
        ,(SELECT ID from ItemGroups WHERE NAME=mi.ItemGroup) as ID
        ,mi.SubGroup,
        CASE 
          WHEN mi.IsDefault ='Yes' THEN 1 
          WHEN mi.IsDefault ='No' THEN 0 
          WHEN mi.IsDefault IS NULL THEN 0
         END ,
         CASE 
          WHEN mi.IsRemovable ='Yes' THEN 1 
          WHEN mi.IsRemovable ='No' THEN 0 
         END ,
        (SELECT ID from MachineTypes WHERE Name=mi.MachineType),
        (SELECT ID from MachineItemTypes WHERE Name=mi.ItemType),
        mi.CreatedBy 
        ,mi.CreatedOn       
        FROM @MachineItems mi
    

    【讨论】:

    • 感谢您的快速回复。我是使用合并的新手。一个问题是您已合并 MachineItems.Id 和 @MachineItems.id。那么这是否意味着如果 id 不匹配,那么只会执行插入?
    • @SachinTrivedi 列在 ON 关键字之后定义,用于匹配条件。现在更新为 name,正如您所说的那样
    • 感谢您的澄清。
    猜你喜欢
    • 2011-01-30
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多