Correct SQLite syntax - UPDATE SELECT with WHERE EXISTS
Asked Answered
K

5

14

I am trying to update a selected values in a column in a SQLite table. I only want update of the cells in the maintable where the criteria are met, and the cells must be updated to individual values, taken from a subtable.

I have tried the following syntax, but I get only a single cell update. I have also tried alternatives where all cells are updated to the first selected value of the subtable.

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)

What is the appropriate syntax?

Kreutzer answered 6/6, 2012 at 19:51 Comment(0)
C
29

You can do this with an update select, but you can only do one field at a time. It would be nice if Sqlite supported joins on an update statement, but it does not.

Here is a related SO question, How do I UPDATE from a SELECT in SQL Server?, but for SQL Server. There are similar answers there.

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
Carlisle answered 16/1, 2014 at 3:24 Comment(0)
M
9

By default update with joins does not exist in SQLite; But we can use the with-clause + column-name-list + select-stmt from https://www.sqlite.org/lang_update.html to make something like this:

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;

Hopefully sqlite is smart enough to not query incrementally but according to the documentation it is. When setting multiple columns using one select (case 2 and 3) a not valid id (no where _id in line) will give an error that can not be ignored using ON IGNORE, case 1 will set columns to null (for all ids >2) which is also bad.

Maris answered 29/4, 2019 at 16:10 Comment(2)
Situation 1 is for having one big query that does the blunt and just a lot of mindless do nothing special queries for the set line. Situation 2 is fancy and pretty. Situation 3 is short and pretty.Maris
For android users, please be aware that situation 2 and 3 is only available for android 8.0 API 26 (that's when sqllite has v3.15)Maris
M
8

In this case, it only updates one value from subtable per each raw from maintable. The error is when subtable is include into of SELECT sentence.

UPDATE maintable
SET value=(SELECT subtable.value 
             FROM subtable
             WHERE  maintable.key1=subtable.key1 );
Maryland answered 22/1, 2019 at 22:18 Comment(0)
B
5

You need to use an INSERT OR REPLACE statement, something like the following:

Assume maintable has 4 columns: key, col2, col3, col4
and you want to update col3 with the matching value from subtable

INSERT OR REPLACE INTO maintable
SELECT maintable.key, maintable.col2, subtable.value, maintable.col4
FROM maintable 
JOIN subtable ON subtable.key = maintable.key
Barclay answered 15/3, 2013 at 4:34 Comment(3)
Good answer, but you do not need to do INSERT OR REPLACE. I found another answer :) Also INSERT OR REPLACE would require you to have all fields of the primary key right?Carlisle
@Carlisle where is the answer?Hague
@Hague sorry I don't understand. I have never used INSERT OR REPLACE before.Carlisle
G
0

You can do it this way

UPDATE stocks
SET name = (
    SELECT s2.name
    FROM stocks s2
    WHERE s2.id = stocks.id    -- on what to join
    AND s2.date = '2024-04-17' -- criteria from where join
)
WHERE name IS NULL             -- criteria which rows to update
Gaffrigged answered 26/4 at 13:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.