Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 循环和插入/更新的最佳解决方案_Sql Server - Fatal编程技术网

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

Sql server 循环和插入/更新的最佳解决方案,sql-server,Sql Server,我很想知道是否有比我现有的更好/更优化的解决方案,因为它使用游标,我知道从性能角度来看,游标不是很好 基本上,我的要求是检查一个ID是否存在许多设置,然后相应地更新或插入它们 为此,我必须: DECLARE @UserId UNIQUEIDENTIFIER = '{PUT-GUID-HERE}' 然后我声明一个表变量,将设置名称和值添加到其中,总共大约有15个 DECLARE @SettingsToCheck TABLE (SettingName varchar(100), SettingVa

我很想知道是否有比我现有的更好/更优化的解决方案,因为它使用游标,我知道从性能角度来看,游标不是很好

基本上,我的要求是检查一个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
可能存在某些/无或所有设置已存在的情况。但这里有一个例子

之前:

SettingName  |  SettingValue
____________________________
Setting1     |  Setting1Value
SettingName  |  SettingValue
____________________________
Setting1     |  Setting1ValueUPDATED

Setting2     |  NewSetting
之后:

SettingName  |  SettingValue
____________________________
Setting1     |  Setting1Value
SettingName  |  SettingValue
____________________________
Setting1     |  Setting1ValueUPDATED

Setting2     |  NewSetting

您可以按如下方式使用“合并”

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

我知道人们喜欢使用合并,但我更喜欢将它们与各自的任务分开。Aaron Bertrand在此处记录了MERGE的一些问题:, 但我不确定有多少人仍然坚持这样做

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

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

不循环将是第一步;您正在编写SQL而不是C。在SQL中,基于集合的方法几乎总是比循环执行得快(在某些情况下,这是不正确的,所以“基于集合的循环”)。样本数据和预期结果在这里会有很大帮助。我可以重复IF-EXISTS块进行15个左右的设置,但这将变得非常不可读,但如果需要,我很乐意做出牺牲。代码运行良好,因此预期结果只是表中的更新值;我看不到你的设计,但我怀疑你能在一个声明中做到这一点。如果没有样本数据和预期结果,就无法提出更多建议。我已经用一个非常基本的前后示例更新了我的问题。这有帮助吗?谢谢,今天下午我将尝试一下。我已经使用SettingName来识别记录。您可以在该条件下添加UserId。让我知道任何反馈。。。