この質問 から派生して、その複雑なソートの結果を使用して、どの行のデータを1つのテーブルから別のテーブルに移動するかを決定します。まだ試していませんが、次の方法で「コピー」部分を実行しても問題はないと思います。
INSERT * FROM (...)
かっこ内にそのSELECT
からの私の結果を使用します。
ただし、同じクエリを使用して同じ結果をSELECT
にしようとすると、DELETE FROM
、結果には同じ行が含まれなくなります。したがって、正しいテーブルの正しい行をDELETE
するために、少なくとも主キー(およびOriginテーブル、つまり2つのOriginテーブルと1つの宛先テーブル)を格納する方法が必要です。
私が読んで理解したことから、単一のクエリで実行することは不可能であり、いずれにしてもトランザクションが必要になります(正しく実行する方法を検索する必要があります)。
したがって、私の最初のアプローチは、最初にINSERT
コピーを実行してから、2つのテーブルから、宛先テーブルに表示されている主キーを含む行を削除することです。そのテーブルは2つのOriginテーブルよりもmuch大きくなるため、少し非効率的であり、派生テーブルから、サブクエリから取得したことがわかります。そこにある情報を使用する方がはるかに効率的です。それで、私がこれについてどうやって最善を尽くすことができるかについての手がかりはありますか?
好奇心の強い人のために、@ evanSteinbrennerのヒントのおかげで、これが私がそれを解決した方法です:
LOCK TABLES
main WRITE,
main as t WRITE,
main as t_in WRITE,
main as df WRITE,
main_date WRITE,
main_date as d WRITE,
main_date as d2 WRITE,
main_date as dx WRITE,
main_weekday WRITE,
main_weekday as w WRITE;
CREATE TEMPORARY TABLE IF NOT EXISTS stacks_tmp AS ( $sql_stacks_ready );
SELECT COUNT(*) FROM stacks_tmp ORDER BY date;
INSERT INTO main (id, title, added_on, date) SELECT id, title, added_on, date FROM stacks_tmp;
DELETE FROM main_date WHERE (id) IN (SELECT id FROM stacks_tmp WHERE from_table = 'date') ;
DELETE FROM main_weekday WHERE (id) IN (SELECT id FROM stacks_tmp WHERE from_table = 'weekday') ;
UNLOCK TABLES;
これは、元のPerl/dbi
コードから単純化されています。このコードは、各ステートメントの失敗をチェックするロジックを実行します。私はまだそれを学ぶ必要があるので、私はまだトランザクションを使用してそれを持っていません。 $sql_stacks_ready
変数には、順序付けされたスタックを作成する(したがって、LOCK TABLES
内のすべてのエイリアスの必要性)を作成する(半)複雑なクエリが含まれます。列from_table
はスタック構築クエリによって設定され、元のテーブルが何であったかに設定されます。
table2
から削除されたものをtable1
に挿入するトリガーを使用できます。
CREATE TABLE table1(id int, name varchar(10), level int);
INSERT INTO table1(id, name, level) VALUES
(0, 'a', 0)
, (1, 'b', 1)
, (2, 'c', 0)
, (3, 'd', 2)
, (4, 'e', 1)
, (4, 'f', 0);
CREATE TABLE table2(id int, name varchar(10), level int);
DELIMITER //
CREATE TRIGGER table1_after_delete
AFTER DELETE
ON table1 FOR EACH ROW
trig: BEGIN
IF (@TRIGGER_AFTER_DELETE_ENABLE = FALSE)
THEN
LEAVE trig;
END IF;
INSERT INTO table2
(
id
, name
, level
)
VALUES
(
OLD.id
, OLD.name
, OLD.level
);
END; //
DELIMITER ;
DELETE FROM table1 WHERE level = 1;
SET @TRIGGER_AFTER_DELETE_ENABLE = FALSE;
DELETE FROM table1 WHERE level = 2;
このサンプルは、table1
内のすべてのlevel=1
を削除し、次にlevel=2
を削除します。 table2
の場合にのみ、@TRIGGER_AFTER_DELETE_ENABLE <> FALSE
に移動します。サンプル sqlfiddle を参照してください。
したがって:
d name level
0 a 0
2 c 0
4 f 0
id name level
1 b 1
4 e 1
level=2
のある行はもうありません(サンプル sqlfiddle を参照)。
あなたは基本的にこのように選択します:
@TRIGGER_AFTER_DELETE_ENABLE = FALSE
deleteステートメントの前=>データを削除してコピーする@TRIGGER_AFTER_DELETE_ENABLE <> FALSE
=>データのみを削除問題はこのRDBMSに関するものではありませんが、SQL ServerではOUTPUT
句を使用します。
DELETE FROM t
OUTPUT deleted.id, deleted.name, deleted.level INTO table2
FROM table1 t
WHERE level > 0;
単に削除されたものの出力を別の場所に挿入するだけです。一時テーブルは不要であり、IOはtempdb
で制限されます。
最初にすべてを一時テーブルに挿入します。次に、挿入と削除は、複雑なクエリではなく、一時テーブルのすべてです。これにより、両方を行う方法の問題が解決され、おそらく、複雑なクエリを複数回実行するよりもパフォーマンスが向上します。
My-SQLよりも多くのMS-SQLを実行するため、スタックオーバーフローの別の回答にリンクします。
MS-SQLでは単に
SELECT .... into #MyTempTable FROM ... WHERE..