带连接的 SQL 表更新 [重复]

Posted

技术标签:

【中文标题】带连接的 SQL 表更新 [重复]【英文标题】:SQL Table Update with join [duplicate] 【发布时间】:2013-07-27 19:24:11 【问题描述】:

我有两张表,Table1 和 Table2,它们有 N 个编号。的列。我需要根据 Table2 更新 Table1。我想更新 Table1 中的所有列,这些列在 Table2 的单个列中列出。

E.G

    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时,更新Table1中所有列在Table2中的列 和 Table1.B = Table2.Y

平台是 SQL Server。 我正在寻找的是一个动态的解决方案,因为我不知道我要更新的列名。表1可以有N个。需要更新的列。我使用光标尝试了以下操作。

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 Server、Oracle、DB2、mysql 等)具有更快的“快捷方式”。什么平台? 相关说明:english.stackexchange.com/questions/68169/… @JamesMohler 我更新了标题。 这个问题已经讨论过很多次了,请在发这个之前,你应该做一个更好的搜索。你也应该指定平台,这很重要。 @Hogan 因为之前应该指定 sql 平台。 【参考方案1】:

警告:在使用任何动态 SQL 之前,请阅读 SQL Injection。在您的情况下,如果用户有权访问 table2,则可以通过将 sql 代码写入 col_name 来破解它。

SQL FIDDLE EXAMPLE

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

【讨论】:

【参考方案2】:

执行此操作的标准 SQL 方法需要相关子查询:

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 一起使用的方法:

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)

在这两种情况下,coalesce() 都旨在在不匹配时保留当前值。如果您希望 NULL 不匹配,则只需删除 coalesce()

编辑

在 SQL Server 中,更新/连接的语法略有不同:

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;

【讨论】:

嗨,戈登,感谢您的回复,我已经更新了我的问题并提供了更多详细信息,我们将不胜感激。

以上是关于带连接的 SQL 表更新 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

T-SQL - 连接多个表会导致重复行

带条件的 Oracle SQL 合并语句

用sql语句进行多表连接查询,怎么不查出重复数据

SQL - 根据另一个表内容更新表行[重复]

用sql语句进行多表连接查询出现重复数据

使用重复值更新 Oracle SQL - 表