15

这很容易,并且已被多次询问,但我无法让它工作。我认为应该工作的 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
4

5 回答 5

28

使用更新语句是不可能的,因为在 sqlite 中不支持更新语句中的连接。请参阅文档: 更新声明

如果您只想将单个列更新为静态值,则可以在更新语句中正确使用子查询。请参阅此示例:如何在 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“列 g”中添加了一个额外的列,以显示您如何使用此方法仅“更新”某些列。

需要注意的另一件事是,如果您使用“PRAGMA foreign_keys = ON;” 由于该行被有效地删除和插入,因此可能会出现问题。

于 2012-08-23T20:48:06.733 回答
5

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

一般来说,你有一张Master桌子和一张Updates桌子。您想从key field 链接Master的相应字段中更新一些/所有记录字段。UpdatesKey

而不是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 ;
    

笔记

  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.05 秒,但方法需要2.50 秒UPDATE ... ( SELECT... )

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

于 2014-03-18T14:03:18.973 回答
3

正如托尼所说,解决方案是替换方式,但您可以使用 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

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

于 2013-11-28T00:15:50.843 回答
2

SQLITE 不支持使用 INNER JOIN 进行更新,其他几个数据库也不支持。内部连接既好又简单,但它可以通过仅使用 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) 
于 2014-10-01T04:23:11.647 回答
-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
于 2012-08-25T06:45:45.413 回答