web-dev-qa-db-ja.com

単一のSQLクエリで異なる値を持つ複数の行を更新する

テーブルmyTableと列idposXposYを持つSQLiteデータベースがあります。行数は絶えず変化します(増減する場合があります)。各行のidの値と行数がわかっている場合、単一のSQLクエリを実行して、すべてのposXおよびposYフィールドを異なる値で更新できますかIDに応じた値?

例えば:

---------------------
myTable:

id   posX    posY

1      35     565
3      89     224
6      11     456
14     87     475
---------------------

SQLクエリの擬似コード:

UPDATE myTable SET posX[id] = @arrayX[id], posY[id] = @arrayY[id] "

@arrayXおよび@arrayYは、posXおよびposYフィールドの新しい値を格納する配列です。

たとえば、arrayXおよびarrayYに次の値が含まれる場合:

arrayX = { 20, 30, 40, 50 }
arrayY = { 100, 200, 300, 400 }

...クエリ後のデータベースは次のようになります。

---------------------
myTable:

id   posX    posY

1      20     100
3      30     200
6      40     300
14     50     400
---------------------

これは可能ですか?現在、クエリごとに1つの行を更新していますが、行数が増えると数百のクエリが必要になります。ところで、私はこれをすべてAIRでやっています。

26
astralmaster

これを実現するには、いくつかの方法がありますdecently効率的に。

最初 -
可能であれば、一時テーブルに何らかの一括挿入を行うことができます。これはRDBMS /ホスト言語にある程度依存しますが、最悪の場合、これは単純な動的SQL(VALUES()句を使用)で達成でき、その後、標準の別のテーブルから更新します。ただし、ほとんどのシステムはバルクロード用のユーティリティを提供します

第二-
これはRDBMSにもある程度依存しているため、動的更新ステートメントを作成できます。この場合、CTE内のVALUES(...)句がオンザフライで作成されています:

WITH Tmp(id, px, py) AS (VALUES(id1, newsPosX1, newPosY1), 
                               (id2, newsPosX2, newPosY2),
                               ......................... ,
                               (idN, newsPosXN, newPosYN))

UPDATE TableToUpdate SET posX = (SELECT px
                                 FROM Tmp
                                 WHERE TableToUpdate.id = Tmp.id),
                         posY = (SELECT py
                                 FROM Tmp
                                 WHERE TableToUpdate.id = Tmp.id)


WHERE id IN (SELECT id
             FROM Tmp)

(ドキュメントによると、このshouldは有効なSQLite構文ですが、フィドルで動作させることはできません)

25
Clockwork-Muse

はい、これを行うことはできますが、クエリのレイテンシが非常に大きい場合を除き、パフォーマンスが向上するとは思いません。

できること:

 UPDATE table SET posX=CASE
      WHEN id=id[1] THEN posX[1]
      WHEN id=id[2] THEN posX[2]
      ...
      ELSE posX END, posY = CASE ... END
 WHERE id IN (id[1], id[2], id[3]...);

合計コストは、NUM_QUERIES *(COST_QUERY_SETUP + COST_QUERY_PERFORMANCE)によって多少なりとも与えられます。このようにして、NUM_QUERIESを少しノックダウンしますが、COST_QUERY_PERFORMANCEは大きく上昇します。 COST_QUERY_SETUPが非常に大きい場合(たとえば、実際に遅いネットワークサービスを呼び出している場合)、はい、まだトップに立つ可能性があります。

それ以外の場合は、IDのインデックス作成、またはアーキテクチャの変更を試みます。

MySQLでは、複数のINSERT ON DUPLICATE KEY UPDATEを使用してこれをより簡単に行うことができると思います(しかし、確かではありませんが、試したことはありません)。

17
LSerni

このような何かがあなたのために働くかもしれません:

"UPDATE myTable SET ... ;
 UPDATE myTable SET ... ;
 UPDATE myTable SET ... ;
 UPDATE myTable SET ... ;"

PosXまたはposYのいずれかの値が同じ場合、それらを1つのクエリに結合できます

UPDATE myTable SET posX='39' WHERE id IN('2','3','40');
5
Brian