【问题标题】:Multi loop UPDATE/INSERT Table for selected rows with WHERE conditions具有 WHERE 条件的选定行的多循环 UPDATE/INSERT 表
【发布时间】:2023-03-27 11:29:01
【问题描述】:

我有两张这样的表:

表1

DataS DataH DataO
001    101    ABA
003    101    ABC
001    101    AAB
001    105    BBA
002    102    ABB
002    102    ACA

表2

DataS DataH DataO Result1 Result2 Result3
003   101   ABC
001   105   BBA

我正在尝试使用两个输入参数创建一个过程:@DataS@DataH。应该做什么程序:

  1. 从 Table1 WHERE DataS=@DataS AND DataH=@DataH 中选择所有记录。
  2. 对于每个选定的行,检查表2中是否存在具有相同三个值[DataS][DataH][DataO]的IF记录。
  3. 如果是 - 更新 Table2 中的这一行(SET Result1 = (MyFunction)、SET Result2 = (MyFunction) 等)
  4. 如果否 - 使用所有参数 [DataS] [DataH] [DataO] [Result1] [Result2] [Result3] 插入此行

所以 Table2 在程序执行后应该是这样的:

Table2(更新后)

DataS  DataH DataO Result1 Result2 Result3
003    101   ABC   1.5     1.3     1.4
001    105   BBA   1.6     1.1     1.3
001    101   ABA   1.6     1.3     1.4
001    101   AAB   1.6     1.3     1.4
002    102   ABB   1.1     1.4     1.4
002    102   ACA   1.3     1.4     1.1

是否可以在一个程序中完成?最好的方法是什么(保持良好的效率)?是否可以用 cte 来做,或者有更好的解决方案,一些循环功能?

DECLARE @ID int
SELECT @ID = (SELECT ID FROM Table2 WHERE DataS=@DataS AND DataH=@DataH AND DataO=@DataO)
IF EXISTS @ID
BEGIN
    --UPDATE Table2 SET Result1=... WHERE ID=@ID
END
ELSE
BEGIN
   --INSERT INTO Table2 (.....)
END

更新: 我认为最好的解决方案是使用 MERGE,正如 Luis Cazares 所说(谢谢),所以我做了新的程序,比如:

MERGE Table2 AS ex
USING x AS st
ON (x.DataS = st.DataSAND ex.DataO = st.DataO AND ex.DataH = st.DataH)
WHEN MATCHED THEN UPDATE SET ex.Result1 = 9
WHEN NOT MATCHED THEN
INSERT(DataS,DataH,DataO,Result1)
VALUES(st.DataS,st.DataH,st.DataO,9);

看起来很聪明,但它不起作用,而且我认为 MERGE 在我使用的旧 2005 SQL Server 上不支持(从 2008 年开始)。所以我尝试了 mkRabbani 建议的 CURSOR 函数,它可以工作(谢谢)。

【问题讨论】:

  • 您做了哪些尝试?您能否向我们展示 SQL 并解释为什么它没有按您的预期工作?
  • 请注意,如果涉及并发,您的代码可能会出现问题。一切都可以在一个 MERGE 或 INSERT/UPDATE 集中完成,无需循环(SQL Server 将在幕后完成)。
  • Larnu,好吧,正如您在上面的代码中看到的,我有内部语句 DECLARE @ID... 但我不知道如何循环它。
  • Luis Cazares,感谢您的建议。我尝试了 MERGE 功能,但是因为我有 2005 sql server 数据库版本,所以不支持它。

标签: sql sql-server tsql


【解决方案1】:

这可以使用如下定义的 CURSOR 来实现。测试值应替换为您的函数输出。

DECLARE @DataS VARCHAR(50)
DECLARE @DataH VARCHAR(50)

SET @DataS  =  '003'
SET @DataH = '101'

DECLARE @DataS_T1 VARCHAR(50)
DECLARE @DataH_T1 VARCHAR(50)
DECLARE @DataO_T1 VARCHAR(50)
DECLARE @DataS_T2 VARCHAR(50)
DECLARE @DataH_T2 VARCHAR(50)
DECLARE @DataO_T2 VARCHAR(50)

DECLARE db_cursor CURSOR 
FOR 
SELECT 
T1.DataH DataH_T1,T1.DataO DataO_T1,T1.DataS DataS_T1,
T2.DataH DataH_T2,T2.DataO DataO_T2,T2.DataS DataS_T2  
FROM Table1 T1
LEFT JOIN Table2 T2
    ON T1.DataH = T2.DataH AND T1.DataO =T2.DataO AND T1.DataS = T2.DataS
WHERE T1.DataH = @DataH
AND T1.DataS = @DataS

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @DataH_T1,@DataO_T1,@DataS_T1,@DataH_T2,@DataO_T2,@DataS_T2  

WHILE @@FETCH_STATUS = 0  
BEGIN  

      IF (@DataH_T2 IS NULL)
      BEGIN
          INSERT INTO Table2 (DataS,DataH,DataO,Result1,Result2,Result3)
          VALUES (@DataS_T1,@DataH_T1,@DataO_T1,'Test Result 1','Test Result 2','Test Result 3')
      END

      ELSE
      BEGIN
          UPDATE Table2
          SET Result1 = 'Test',
          Result2= 'test2',
          Result3= 'Test3'
          WHERE DataS = @DataS_T2 
          AND DataH = @DataH_T2
          AND DataO = @DataO_T2
      END

      FETCH NEXT FROM db_cursor INTO @DataH_T1,@DataO_T1,@DataS_T1,@DataH_T2,@DataO_T2,@DataS_T2  
END 

CLOSE db_cursor  
DEALLOCATE db_cursor

【讨论】:

  • mkRabbani,谢谢您的回答。我用你的解决方案做了一个测试,它有效。非常感谢;)
猜你喜欢
  • 2013-06-28
  • 2019-09-16
  • 2023-02-21
  • 2020-07-11
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2023-01-29
  • 2019-08-25
相关资源
最近更新 更多