【问题标题】:Correct SQLite syntax - UPDATE SELECT with WHERE EXISTS正确的 SQLite 语法 - UPDATE SELECT with WHERE EXISTS
【发布时间】:2012-06-10 21:06:25
【问题描述】:

我正在尝试更新 SQLite 表中列中的选定值。我只想更新 maintable 中满足条件的单元格,并且必须将单元格更新为从子表中获取的单个值。

我尝试了以下语法,但我只得到一个单元格更新。我还尝试了将所有单元格更新为子表的第一个选定值的替代方法。

UPDATE maintable
SET value=(SELECT subtable.value FROM maintable, subtable
WHERE  maintable.key1=subtable.key1 AND maintable.key2=subtable.key2)
WHERE EXISTS (SELECT subtable.value FROM maintable, subtable
WHERE  maintable.key1=subtable.key1 AND maintable.key2=subtable.key2)

合适的语法是什么?

【问题讨论】:

    标签: sqlite sql-update where exists


    【解决方案1】:

    您需要使用 INSERT OR REPLACE 语句,如下所示:

    假设 maintable 有 4 列:key、c​​ol2、col3、col4
    并且您想使用子表中的匹配值更新 col3

    INSERT OR REPLACE INTO maintable
    SELECT maintable.key, maintable.col2, subtable.value, maintable.col4
    FROM maintable 
    JOIN subtable ON subtable.key = maintable.key
    

    【讨论】:

    • 很好的答案,但您不需要 INSERT OR REPLACE。我找到了另一个答案 :) INSERT OR REPLACE 还需要您拥有主键的所有字段吗?
    • @Jess 答案在哪里?
    • @cikatomo 对不起,我不明白。我以前从未使用过INSERT OR REPLACE
    【解决方案2】:

    您可以使用update select 执行此操作,但一次只能执行一个字段。如果 Sqlite 支持更新语句上的连接会很好,但它不支持。

    这是一个相关的 SO 问题,How do I UPDATE from a SELECT in SQL Server?,但适用于 SQL Server。那里有类似的答案。

    sqlite> create table t1 (id int, value1 int);
    sqlite> insert into t1 values (1,0),(2,0);
    sqlite> select * from t1;
    1|0
    2|0
    sqlite> create table t2 (id int, value2 int);
    sqlite> insert into t2 values (1,101),(2,102);
    sqlite> update t1 set value1 = (select value2 from t2 where t2.id = t1.id) where t1.value1 = 0;
    sqlite> select * from t1;
    1|101
    2|102
    

    【讨论】:

      【解决方案3】:

      在这种情况下,它只从 maintable 中的每个 raw 更新 subtable 中的一个值。 错误是当子表包含在 SELECT 语句中时。

      UPDATE maintable
      SET value=(SELECT subtable.value 
                   FROM subtable
                   WHERE  maintable.key1=subtable.key1 );
      

      【讨论】:

        【解决方案4】:

        默认情况下updatejoins在SQLite中不存在;但是我们可以使用来自https://www.sqlite.org/lang_update.htmlwith-clause + column-name-list + select-stmt 来制作这样的东西:

        CREATE TABLE aa (
        _id INTEGER PRIMARY KEY,
        a1 INTEGER,
        a2 INTEGER);
        
        INSERT INTO aa  VALUES (1,10,20);
        INSERT INTO aa  VALUES (2,-10,-20);
        INSERT INTO aa  VALUES (3,0,0);
        
        --a bit unpleasant because we have to select manually each column and it's just a lot to write
        WITH bb (_id,b1, b2)  
        AS  (SELECT _id,a1+2, a2+1 FROM aa WHERE _id<=2) 
        UPDATE aa  SET a1=(SELECT b1 FROM bb WHERE bb._id=aa._id),a2=(SELECT b2 FROM bb WHERE bb._id=aa._id)
        WHERE _id in (SELECT _id from bb);
        
        --soo now it should be (1,10,20)->(1,12,21) and (2,-10,-20)->(2,-8,-19), and it is
        SELECT * FROM aa;
        
        
        --even better with one select for each row!
        WITH bb (_id,b1, b2)  
        AS  (SELECT _id,a1+2, a2+1 from aa WHERE _id<=2)
        UPDATE aa  SET (a1,a2)=(SELECT b1,b2 FROM bb WHERE bb._id=aa._id)
        WHERE _id in (SELECT _id from bb);
        
        --soo now it should be (1,12,21)->(1,14,22) and (2,-8,-19)->(2,-6,-18), and it is
        SELECT * FROM aa;
        
        
        --you can skip the WITH altogether
        UPDATE aa SET (a1,a2)=(SELECT bb.a1+2, bb.a2+1 FROM aa AS bb WHERE aa._id=bb._id)
        WHERE _id<=2;
        
        --soo now it should be (1,14,22)->(1,16,23) and (2,-6,-18)->(2,-4,-17), and it is
        SELECT * FROM aa;
        

        希望 sqlite 足够聪明,不会增量查询,但根据文档它是。当使用一个选择(案例 2 和 3)设置多个列时,无效的 id(没有 where _id in 行)将给出一个使用 ON IGNORE 无法忽略的错误,案例 1 会将列设置为 null(对于所有ids >2) 这也很糟糕。

        【讨论】:

        • 情况 1 是因为有一个大查询,它做的很生硬,只是很多无意识的人什么都不做对集合行的特殊查询。情况2很漂亮。情况 3 简短而漂亮。
        • 对于android用户,请注意情况2和3仅适用于android 8.0 API 26(即sqllite有v3.15时)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-26
        • 1970-01-01
        • 1970-01-01
        • 2017-11-25
        • 2021-05-26
        • 1970-01-01
        相关资源
        最近更新 更多