循环和插入/更新的最佳解决方案

时间:2020-02-18 11:30:17

标签: sql-server

我很想知道是否有比使用游标的方法更好/更优化的解决方案,我知道这并不是很好的性能。

基本上我的要求是检查ID是否存在许多设置,然后相应地更新或插入它们。

为此,我有:

DECLARE @UserId UNIQUEIDENTIFIER = '{PUT-GUID-HERE}'

然后我声明一个表变量,在其中添加设置名称和值,总共大约有15个。

DECLARE @SettingsToCheck TABLE (SettingName varchar(100), SettingValue varchar(100)
INSERT INTO @SettingsToCheck ('Setting1', 'Setting1 Value') --Repeat...

DECLARE @CurrentSettingName varchar(100)
DECLARE @CurrentSettingValue varchar(100)
DECLARE Settings_Cursor CURSOR FOR SELECT SettingName, SettingValue FROM @SettingsToCheck
OPEN Settings_Cursor

FETCH NEXT FROM Settings_Cursor INTO @CurrentSettingName, @CurrentSettingValue
WHILE @@FETCH_STATUS = 0
BEGIN
    IF EXISTS (SELECT * FROM MyActualTable WHERE UserID = @UserId AND SettingName = @CurrentSettingName)
    BEGIN
        UPDATE MyActualTable SET SettingValue = @CurrentSettingValue WHERE UserID = @UserId AND SettingName = @CurrentSettingName
    END
    ELSE
    BEGIN
        INSERT INTO MyActualTableVALUES (NEWID(), @UserId, GETDATE(), @CurrentSettingName, @CurrentSettingValue)
    END

    FETCH NEXT FROM Settings_Cursor INTO @CurrentSettingName, @CurrentSettingValue
END

CLOSE Settings_Cursor
DEALLOCATE Settings_Cursor

我知道这个问题尚待商定,但我不知道有其他选择。

编辑:

在某些情况下,某些/所有或所有设置都已经存在。但这是一个例子。

之前:

SettingName  |  SettingValue
____________________________
Setting1     |  Setting1Value

之后:

SettingName  |  SettingValue
____________________________
Setting1     |  Setting1ValueUPDATED

Setting2     |  NewSetting

2 个答案:

答案 0 :(得分:1)

您可以按以下方式使用合并

DECLARE @SettingsToCheck TABLE 
(
    SettingName varchar(100)
    ,SettingValue varchar(100)
)

DECLARE @ActualTable TABLE 
(
    SettingName varchar(100)
    ,SettingValue varchar(100)
)

INSERT INTO @SettingsToCheck 
VALUES
('Setting1', 'Setting1 Value') --Repeat...
,('Setting2', 'Setting2 Value') 
,('Setting3', 'Setting3 Value') 
,('Setting4', 'Setting45 Value') 
,('Setting5', 'Setting5 Value') 
,('Setting6', 'Setting6 Value') 
,('Setting7', 'Setting7 Value') 


INSERT INTO @ActualTable 
VALUES
 ('Setting4', 'Setting4 Value')

MERGE INTO @ActualTable  AS target
USING @SettingsToCheck AS source
    ON target.SettingName = source.SettingName
WHEN MATCHED THEN 
    UPDATE SET target.SettingValue = source.SettingValue
WHEN NOT MATCHED BY TARGET THEN
    INSERT (SettingName, SettingValue)
    VALUES (source.SettingName, source.SettingValue);

Select * from @ActualTable

答案 1 :(得分:0)

我知道人们喜欢使用MERGE,但我更喜欢将他们与自己的任务分开。亚伦·伯特兰(Aaron Bertrand)在此处记录了MERGE的一些问题:https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/, 但我不确定其中有多少仍然存在。

无论如何,这是一种选择:

CREATE TABLE #SettingsToCheck 
(
    SettingName varchar(100)
    ,SettingValue varchar(100)
)


CREATE TABLE #ActualTable 
(
    SettingName varchar(100)
    ,SettingValue varchar(100)
)

INSERT INTO #SettingsToCheck 
VALUES
('Setting1', 'Setting1 Value') --Repeat...
,('Setting2', 'Setting2 Value') 
,('Setting3', 'Setting3 Value') 
,('Setting4', 'Setting45 Value') 
,('Setting5', 'Setting5 Value') 
,('Setting6', 'Setting6 Value') 
,('Setting7', 'Setting7 Value') 


INSERT INTO #ActualTable 
VALUES
 ('Setting4', 'Setting4 Value')


 UPDATE #ActualTable 
    SET SettingValue = t2.SettingValue
    FROM #ActualTable t1
    INNER JOIN #SettingsToCheck t2 on t1.SettingName = t2.SettingName

INSERT INTO #ActualTable(SettingName,SettingValue)
SELECT t1.SettingName,t1.SettingValue   
    FROM #SettingsToCheck t1
    LEFT JOIN #ActualTable t2 on t1.SettingName = t2.SettingName
    WHERE t2.SettingName IS NULL

select * from #ActualTable