SQLite内部联接 - 使用另一个表中的值进行更新

时间:2012-08-03 06:44:06

标签: sql sqlite join sql-update

这很容易,已被多次询问,但我无法让它工作。 我认为应该工作的SQL查询是:

    UPDATE table2
       SET dst.a = dst.a + src.a,
           dst.b = dst.b + src.b,
           dst.c = dst.c + src.c,
           dst.d = dst.d + src.d,
           dst.e = dst.e + src.e
      FROM table2 AS dst 
INNER JOIN table1 AS src
        ON dst.f = src.f

5 个答案:

答案 0 :(得分:25)

使用update语句是不可能的,因为不支持更新语句中的sqlite连接。查看文档: update statement

如果您只想将单个列更新为静态值,则可以在update语句中正确使用子查询。请参阅此示例:How do I make an UPDATE while joining tables on SQLite?

现在在您的示例中,假设“列f”上有唯一键 - 我提出的解决方法/解决方案是使用替换语句:

replace into table2
(a, b, c, d, e, f, g)
select src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f

我还在table2“column g”中添加了一个额外的列,以显示如何使用此方法“更新”某些列。

另一件要谨慎的事情是,如果你使用“PRAGMA foreign_keys = ON;”

可以有效地删除和插入行

答案 1 :(得分:5)

我想出了一种使用TRIGGER的替代技术并“反转”更新的方向,虽然代价是源表中的虚拟字段。

一般而言,您有一个Master表和一个Updates表。您想要通过关键字段Master链接的Updates中的相应字段更新Key中的部分/全部记录字段。

而不是UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key,您可以执行以下操作:

  1. TriggerField表添加虚拟字段Updates以充当触发器的焦点。

  2. 在此字段上创建触发器:

    CREATE TRIGGER UpdateTrigger AFTER UPDATE OF TriggerField ON Updates
    BEGIN
        UPDATE Master SET
            Field1 = OLD.Field1,
            Field2 = OLD.Field2,
            ...
        WHERE Master.Key = OLD.Key
    END;
    
  3. 使用以下内容启动更新过程:

    UPDATE Updates SET TriggerField = NULL ;
    
  4. 注释

    1. 虚拟字段只是触发器的锚点,因此任何其他UPDATE Updates SET ...都不会触发更新到Master。如果您只INSERT进入Updates,那么您不需要它(并且可以在创建触发器时删除OF TriggerField子句。)

    2. 从一些粗略的准备时间开始,这似乎与REPLACE INTO的速度大致相同,但避免了删除和添加行的感觉 - 稍微错误的技术。如果您只更新Master中的几个字段,因为您只列出要更改的字段,这也会更简单。

    3. 它比我见过UPDATE ... FROM的其他替代方案快了几个数量级:

      UPDATE Master SET
          Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
          Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
          ...
      ;
      

      对于Tony和我的方法,在1700条记录中更新六个字段大致 0.05s ,对于UPDATE ... ( SELECT... )方法, 2.50s

    4. AFTER UPDATE触发Master似乎按预期触发。

答案 2 :(得分:3)

正如Tony所说,解决方案是替换为方式,但您可以使用sqlite隐藏字段 rowid 来模拟完整更新,例如:

replace into table2
(rowid,a, b, c, d, e, f, g)
select dest.rowid,src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f

如果您没有替换主键或使用连接作为标准方法来执行更新,则可以重新创建完整行。

答案 3 :(得分:2)

SQLITE不支持使用INNER JOIN进行UPDATE,也不支持其他几个DB。内部联接很简单,但只需使用UPDATE和子查询选择即可完成。通过使用where子句和带有子查询的'IN'和'SET'的附加子查询,可以始终实现相同的结果。以下是它的完成方式。

UPDATE table2
  SET a = a + (select a from table1 where table1.f = table2.f),
       b = b + (select b from table1 where table1.f = table2.f),
       c = c + (select c from table1 where table1.f = table2.f),
       d = d + (select d from table1 where table1.f = table2.f),
       e = e + (select e from table1 where table1.f = table2.f)
  WHERE RowId IN (Select table2.RowId from table1 where table1.f = table2.f) 

答案 4 :(得分:-5)

使用以下查询:

UPDATE table2
SET a = Z.a,
    b = Z.b,
    c = Z.c,
    d = Z.d,
    e = Z.e
FROM (SELECT dst.id, 
             dst.a + src.a AS a,
             dst.b + src.b AS b,
             dst.c + src.c AS c,
             dst.d + src.d AS d,
             dst.e + src.e AS e
      FROM table2 AS dst 
      INNER JOIN table1 AS src ON dst.f = src.f
      )Z
WHERE table2.id = z.id