【问题标题】:SQLite inner join - update using values from another tableSQLite 内连接 - 使用来自另一个表的值进行更新
【发布时间】:2012-08-03 06:44:06
【问题描述】:

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

【问题讨论】:

  • 只需从所有 SET 语句中删除 'dst' 别名 SET a = dst.a + src.a,b = dst.b + src.b,c = dst.c + src.c,d = dst.d + src.d,e = dst.e + src.e
  • @valexhome 更新表 2 SET a = a + src.a, b = b + src.b, c = c + src.c, d = d + src.d, e = e + src .e INNER JOIN table1 AS src ON f = value 在 INNER 附近给出语法错误
  • 对不起,我错过了这是 sqllite。尝试使用子查询而不是FROM,JOIN link

标签: sql sqlite join sql-update


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

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

一般来说,您有一个Master 表和一个Updates 表。您想从Updates 中由关键字段Key 链接的相应字段更新Master 中的部分/所有记录字段。

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

  1. Updates 表中添加一个虚拟字段TriggerField,作为触发器的焦点。

  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 的工作速度大致相同,但避免了删除和添加行的feels-slightly-wrong 技术。如果您只更新 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 ),
        ...
    ;
    

    更新超过 1700 条记录的六个字段对于 Tony 和我的方法来说大约是 0.05s,但对于 UPDATE ... ( SELECT... ) 方法来说是 2.50s

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

【讨论】:

    【解决方案3】:

    正如 Tony 所说,解决方案是 replace into 方式,但您可以使用 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
    

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

    【讨论】:

      【解决方案4】:

      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) 
      

      【讨论】:

      • 我认为您的最后一行输入错误。 table2.RowId 应该是 table1.RowId 或只是 RowId。
      【解决方案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
      

      【讨论】:

      • 这不适用于 sqlite 版本(SQLite 3.7.13 2012-06-11 02:05:22)我正在测试它。 “错误:靠近“FROM”:语法错误”查看 sqlite 文档,您似乎无法在更新查询中使用 from 语句。
      猜你喜欢
      • 2018-07-21
      • 1970-01-01
      • 1970-01-01
      • 2020-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 2018-06-07
      相关资源
      最近更新 更多