SQL Table Update with join
本问题已经有最佳答案,请猛点这里访问。
我有两张表,表1和表2,它们没有列数。我需要根据表2更新表1。我想更新表1中的所有列,这些列在表2中的单个列中列出。
例如
1 2 3 4 5 6 7 8 9 10 11 | Table1 A B C D E . . . 1 2 3 4 5 . . . 7 6 5 4 3 . . . Table2 X Y Col_Nam Col_Value 1 2 C 8 1 2 D 9 7 6 E 10 7 6 C 20 . . . . . . . . |
当匹配以下条件table1.a=table2.x时,更新表1中列出的所有列。表1.b=表2.y
平台是SQL Server。我要寻找的是一个动态的解决方案,因为我不知道要更新的列名。表1可以有n个需要更新的列。我用光标尝试了以下操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | DECLARE @s VARCHAR(MAX), @key1 VARCHAR(MAX), @key2 VARCHAR(MAX), @Cname VARCHAR(MAX), @CValue VARCHAR(MAX) DECLARE crs CURSOR FOR SELECT * FROM Table2 OPEN crs; FETCH NEXT FROM crs INTO @key1,@key2,@Cname,@Cvalue; WHILE @@FETCH_STATUS = 0 BEGIN SET @s = 'Update T1 SET ' + @FieldName + ' = ''' + @FieldValue + ''' from Table1 T1' + ' where T1.A = ''' + @key1 + ''' and T1.B = ''' + @key2 EXEC(@s) FETCH NEXT FROM crs INTO @key1,@key2,@Cname,@Cvalue; END CLOSE crs DEALLOCATE crs |
不知怎么的,它不起作用,我想为所有那些不匹配Where条件的记录设置一个默认值。
如有任何其他解决方案或帮助,我们将不胜感激。
警告:在使用任何动态SQL之前,请阅读有关SQL注入的信息。在您的例子中,如果用户有权访问表2,则可以通过将SQL代码写入col_name来对其进行黑客攻击。
SQL小提琴示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | DECLARE @X INT, @Y INT, @stmt nvarchar(MAX), @params nvarchar(MAX) SELECT @params = '@X int, @Y int' DECLARE table_cursor cursor LOCAL fast_forward FOR SELECT DISTINCT X, Y FROM Table2 OPEN table_cursor while 1 = 1 BEGIN fetch table_cursor INTO @X, @Y IF @@fetch_status <> 0 break SELECT @stmt = NULL SELECT @stmt = isnull(@stmt + ', ', '') + Col_Name + ' = ' + CAST(Col_Value AS nvarchar(MAX)) FROM Table2 WHERE X = @X AND Y = @Y SELECT @stmt = 'update Table1 set ' + @stmt + ' where A = @X and B = @Y' EXEC dbo.sp_executesql @stmt = @stmt, @params = @params, @X = @X, @Y = @Y END close table_cursor deallocate table_cursor |
要做到这一点,标准的SQL方法需要相关的子查询:
1 2 3 4 5 6 7 8 9 10 11 | UPDATE table1 SET C = COALESCE((SELECT MAX(col_value) FROM Table2 t2 WHERE table1.A = t2.X AND table1.B = t2.Y AND t2.Col_Name = 'A' ), C), D = COALESCE((SELECT MAX(col_value) FROM Table2 t2 WHERE table1.A = t2.X AND table1.B = t2.Y AND t2.Col_Name = 'D' ), D) |
某些SQL引擎允许联接。下面是一个用于MySQL的方法:
1 2 3 4 5 6 7 8 9 | UPDATE table1 JOIN (SELECT X, Y, MAX(CASE WHEN col_name = 'C' THEN col_value END) AS C, MAX(CASE WHEN col_name = 'D' THEN col_value END) AS D FROM table2 GROUP BY X, Y ) t2 ON t2.X = table1.A AND t2.Y = table2.Y SET C = COALESCE(t2.C, C), D = COALESCE(t2.D, D) |
在这两种情况下,当不匹配时,
编辑
在SQL Server中,更新/联接的语法略有不同:
1 2 3 4 5 6 7 8 9 10 | UPDATE table1 JOIN SET C = COALESCE(t2.C, C), D = COALESCE(t2.D, D) FROM table1 JOIN (SELECT X, Y, MAX(CASE WHEN col_name = 'C' THEN col_value END) AS C, MAX(CASE WHEN col_name = 'D' THEN col_value END) AS D FROM table2 GROUP BY X, Y ) t2 ON t2.X = table1.A AND t2.Y = table2.Y; |