从表值参数插入或更新或删除数据

use*_*567 3 sql sql-server sql-server-2012

我有一个 ProductsAttributesValues 表,其中有,

Id   ProductId   AttributeId   Value   ORDER
-------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

具有属性(相同的 ProductId/AttributeId)的产品可以具有多个值但具有不同的顺序。我有一个类型,

CREATE TYPE [dbo].[ProductsAttributesValuesType] AS TABLE
(
    [AttributeId] [INT],
    [Value] [NVARCHAR](MAX)
)
Run Code Online (Sandbox Code Playgroud)

我ProductsAttributesValuesType在我的存储过程中将此作为带有 ProductId 参数的表值参数传递。现在我需要的似乎很简单,但我被卡住了。中的信息ProductsAttributesValuesType来自 UI。所以,

1)如果一个值为空或空白或空白,那么我不需要做任何事情并从ProductsAttributesValues具有相同 ProductId/AttributeId 的所有现有记录中删除。

2) 如果一个值不为空或非空或非空白,那么可能有一个值或多个值(多个记录ProductsAttributesValuesType)。如果有单个值,我需要在不存在值的情况下插入,如果存在值则更新。如果有多个值(多个记录ProductsAttributesValuesType),如果不存在现有值,我需要插入所有值,如果存在值则更新/插入。

一种方法是简单地删除所有ProductsAttributesValues具有相同 ProductId/AttributeId 的表。然后插入具有非空值的值。但我认为它不是很有效。

更新:目前,我首先删除所有多值属性值。接下来,我将删除值为空的所有属性值。接下来,我将插入/更新单值属性值。接下来,我将插入多值属性值。

M.A*_*Ali 5

避免使用 Merge 语句将其分解为三个语句并将其全部包装在一个事务中,如下所示

CREATE  Procedure Upserting_To_ProductsAttributesValues 
@ProductsAttributesValuesType   [dbo].[ProductsAttributesValuesType] READONLY
AS 
BEGIN
 SET NOCOUNT ON;
 BEGIN TRY
    BEGIN TRANSACTION;

-- Delete values 
  DELETE FROM ProductsAttributesValues 
  FROM ProductsAttributesValues T INNER JOIN @ProductsAttributesValuesType P
  ON T.AttributeId = P.AttributeId
  WHERE P.Value IS NULL OR RTRIM(LTRIM(P.Value)) = ''

-- Update Statement 
UPDATE T
SET T.Value = P.Value
FROM ProductsAttributesValues T INNER JOIN @ProductsAttributesValuesType P
ON T.AttributeId = P.AttributeId

-- Insert Statement
INSERT INTO ProductsAttributesValues (AttributeId, Value)
SELECT AttributeId, Value
FROM @ProductsAttributesValuesType P
WHERE NOT EXISTS (SELECT 1 
                  FROM ProductsAttributesValues
                  WHERE AttributeId = P.AttributeId)

    COMMIT TRANSACTION;  --<-- If nothing went wrong
 END TRY

 BEGIN CATCH


     -- Now make use of ERROR Functions to get detailed information
     -- about the error, these functions are only allowed in catch block

 SELECT ERROR_MESSAGE() AS [ERROR_MESSAGE]
       ,ERROR_LINE()    AS [ERROR_LINE]
       ,ERROR_NUMBER()  AS [ERROR_NUMBER] 
 END CATCH

END
Run Code Online (Sandbox Code Playgroud)

笔记

我建议避免 Merge 语句的原因请参阅 Aaron Bertrand 撰写的这篇文章 Use Caution with SQL Server's MERGE Statement