web-dev-qa-db-ja.com

正しいSQLite構文-WHEREEXISTSを使用したUPDATESELECT

SQLiteテーブルの列で選択した値を更新しようとしています。基準が満たされているメインテーブルのセルのみを更新する必要があります。セルは、サブテーブルから取得した個々の値に更新する必要があります。

次の構文を試しましたが、セルの更新は1つしかありません。また、すべてのセルがサブテーブルの最初に選択された値に更新される代替案も試しました。

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)

適切な構文は何ですか?

12
AndBB

これはupdate selectで実行できますが、一度に実行できるフィールドは1つだけです。 Sqliteが更新ステートメントで結合をサポートしていればいいのですが、そうではありません。

これは関連するSO質問、 SQL ServerのSELECTから更新するにはどうすればよいですか? ですが、SQLServerの場合です。同様の回答があります。

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
19
Jess

次のようなINSERT OR REPLACEステートメントを使用する必要があります。

Maintableにkey、c​​ol2、col3、col4の4つの列があると仮定します
そして、サブテーブルからの一致する値でcol3を更新したい

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

https://www.sqlite.org/lang_update.html からwith-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;
--WHERE _id IN (SELECT bb._id FROM aa AS bb 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はインクリメンタルにクエリを実行しないほど賢いですが、ドキュメントによるとそうです。 1つの選択を使用して複数の列を設定する場合(ケース2および3)、無効なIDは、ON IGNOREを使用して無視できないエラーを返します。ケース1は、列をnullに設定します。これも悪いことです。

1
Then Enok

この場合、maintableからのrawごとにsubtableから1つの値のみを更新します。エラーは、サブテーブルがSELECT文に含まれている場合です。

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

1
Marcelo