13

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?

Smita Ahinave
  • 1,901
  • 7
  • 23
  • 42
AndBB
  • 157
  • 1
  • 1
  • 6

4 Answers4

27

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
Jess
  • 23,901
  • 21
  • 124
  • 145
7

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 );
Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
Marcelo
  • 81
  • 1
  • 1
6

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.

Then Enok
  • 593
  • 5
  • 16
  • 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. – Then Enok Apr 29 '19 at 16:47
  • 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) – Then Enok Nov 03 '19 at 09:54
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
Noah
  • 15,080
  • 13
  • 104
  • 148
  • 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? – Jess Jan 16 '14 at 03:20
  • @Jess where is the answer? – cikatomo Dec 13 '20 at 08:17
  • @cikatomo sorry I don't understand. I have never used `INSERT OR REPLACE` before. – Jess Dec 14 '20 at 13:30