web-dev-qa-db-ja.com

SQLite内部結合-別のテーブルの値を使用して更新

これは非常に簡単で、何度も尋ねられましたが、私はそれを機能させることができません。私がうまくいくと思うSQLクエリは次のとおりです。

    UPDATE table2
       SET dst.a = dst.a + src.a,
           dst.b = dst.b + src.b,
           dst.c = dst.c + src.c,
           dst.d = dst.d + src.d,
           dst.e = dst.e + src.e
      FROM table2 AS dst 
INNER JOIN table1 AS src
        ON dst.f = src.f
13
navgeet

Sqliteではupdateステートメントでの結合がサポートされていないため、updateステートメントを使用することはできません。ドキュメントを参照してください: 更新ステートメント

単一の列を静的な値に更新するだけの場合は、updateステートメントでサブクエリを正しく使用できます。この例を参照してください: SQLiteでテーブルを結合しているときにUPDATEを作成するにはどうすればよいですか?

ここで、あなたの例では、「列f」に一意のキーがあると仮定しています。私が思いついた回避策/解決策は、replaceステートメントを使用することです。

replace into table2
(a, b, c, d, e, f, g)
select src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f

また、table2の「columng」に列を追加して、このメソッドで一部の列のみを「更新」する方法を示しました。

「PRAGMAforeign_keys = ON;」を使用する場合は、もう1つ注意が必要です。行が効果的に削除および挿入されるため、これに問題が発生する可能性があります。

25
Tony Gibbs

ソーステーブルのダミーフィールドが犠牲になりますが、TRIGGERを使用して更新の方向を「逆にする」代替手法を思いつきました。

一般的に、MasterテーブルとUpdatesテーブルがあります。キーフィールドMasterによってリンクされたUpdatesの対応するフィールドからKeyのレコードの一部/すべてのフィールドを更新するとします。

_UPDATE Master SET ... FROM Master INNER JOIN Updates ON Mater.Key = Updates.Key_の代わりに、次のようにします。

  1. ダミーフィールドTriggerFieldUpdatesテーブルに追加して、トリガーのフォーカスとして機能させます。

  2. このフィールドにトリガーを作成します。

    _CREATE TRIGGER UpdateTrigger AFTER UPDATE OF TriggerField ON Updates
    BEGIN
        UPDATE Master SET
            Field1 = OLD.Field1,
            Field2 = OLD.Field2,
            ...
        WHERE Master.Key = OLD.Key
    END;
    _
  3. 次の方法で更新プロセスを開始します。

    _UPDATE Updates SET TriggerField = NULL ;
    _

ノート

  1. ダミーフィールドはトリガーの単なるアンカーであるため、他の_UPDATE Updates SET ..._はMasterへの更新をトリガーしません。 INSERTUpdatesに入れるだけの場合は、それは必要ありません(トリガーの作成時に_OF TriggerField_句を削除できます)。

  2. いくつかのラフアンドレディーのタイミングから、これは_REPLACE INTO_とほぼ同じ速度で動作するようですが、feels-slightly-wrongテクニックを回避します行の削除と追加のMasterのいくつかのフィールドのみを更新する場合も、変更するフィールドのみをリストするため、より簡単です。

  3. これは、_UPDATE ... FROM_に対して私が見た他の選択肢よりも桁違いに高速です。

    _UPDATE Master SET
        Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
        Field1 = ( SELECT Field1 FROM Updates WHERE Mater.Key = Updates.Key ),
        ...
    ;
    _

    1700レコードを超える6つのフィールドの更新は、Tonyと私のメソッドではおおよそ.05sでしたが、UPDATE ... ( SELECT... )メソッドでは2.50sでした。

  4. Masterの_AFTER UPDATE_トリガーは期待どおりに起動するようです。

5
TripeHound

Tonyが言うように、解決策はreplace intoの方法ですが、sqliteの非表示フィールドrowidを使用して完全な更新をシミュレートできます。次のように参加します:

replace into table2
(rowid,a, b, c, d, e, f, g)
select dest.rowid,src.a, src.b, src.c, src.d, src.e, dest.f, dest.g
from table1 src
inner join table2 dest on src.f = dest.f

これを使用すると、置換用の主キーがない場合、または結合を使用して更新を行うための標準的な方法として、完全な行を再作成できます。

3
lluishzi

SQLITEは、INNER JOINを使用したUPDATEをサポートしておらず、他のいくつかのDBもサポートしていません。内部結合は素晴らしくシンプルですが、UPDATEとサブクエリselectを使用するだけで実行できます。 where句と「IN」をサブクエリと「SET」の追加サブクエリとともに使用することで、常に同じ結果を得ることができます。以下はそれがどのように行われるかです。

UPDATE table2
  SET a = a + (select a from table1 where table1.f = table2.f),
       b = b + (select b from table1 where table1.f = table2.f),
       c = c + (select c from table1 where table1.f = table2.f),
       d = d + (select d from table1 where table1.f = table2.f),
       e = e + (select e from table1 where table1.f = table2.f)
  WHERE RowId IN (Select table2.RowId from table1 where table1.f = table2.f) 
2
user4097428