3

MySQLに行が存在しない場合にのみ挿入し、行が存在し、既存の行のバージョンが新しい行のバージョンよりも小さい(または等しい)場合に更新する方法を探しています。

たとえば、テーブルは次のように定義されます。

CREATE TABLE documents (
  id VARCHAR(64) NOT NULL,
  version BIGINT UNSIGNED NOT NULL,
  data BLOB,
  PRIMARY KEY (id)
);

また、次のデータが含まれています。

id  version  data
----------------------------
1   3        first data set
2   2        second data set
3   5        third data set

そして、次のテーブルをマージしたいと思います(UPDATE:id列は一意です):

id  version  data
----------------------------
1   4        updated 1st
3   3        updated 2nd
4   1        new 4th

そして、それは以下を生成するはずです(更新:1つだけが更新され、4つが挿入される方法を参照してください):

id  version  data
----------------------------
1   4        updated 1st
2   2        second data set
3   5        third data set
4   1        new 4th

INSERT ... ON DUPLICATE KEY UPDATE ...ステートメントを見てきましたが、ある種のWHERE句は許可されていません。また、WHEREも許可されていないため、REPLACEを実際に使用することはできません。これは、単一のMySQLステートメントでも可能ですか?

私はJavaを使用しており、PreparedStatementとバッチ処理(addBatch)を使用して、多くのレコードを挿入/更新しようとしています。どんな助けでもいただければ幸いです。

更新:JavaのPreparedStatementでこのクエリを使用する方法はありますか?ID、バージョン、およびデータを含むドキュメントオブジェクトのリストがあります。

4

2 に答える 2

3

編集:私の以前の回答で、に一意の制約が必要であることを提案しました(id, version)が、実際にはこれは必要ありません。ソリューションが機能するには、のみに対する独自の制約でid十分です。


REPLACE次のようにコマンドを使用できるはずです。

REPLACE INTO main 
SELECT  IFNULL(m.id, s.id) id, 
        IFNULL(m.version, s.version) version, 
        IFNULL(m.data, s.data) data
FROM       secondary s
LEFT JOIN  main m ON (m.id = s.id AND m.version > s.version);

テストケース:

CREATE TABLE main ( 
   id int, 
   version int, 
   data varchar(50), 
   PRIMARY KEY (id)
);

CREATE TABLE secondary (id int, version int, data varchar(50));

INSERT INTO main VALUES (1, 3, 'first data set');
INSERT INTO main VALUES (2, 2, 'second data set');
INSERT INTO main VALUES (3, 5, 'third data set');

INSERT INTO secondary VALUES (1, 4, 'updated 1st');
INSERT INTO secondary VALUES (3, 3, 'udated 2nd');
INSERT INTO secondary VALUES (4, 1, 'new 4th');

結果:

SELECT * FROM main;
+----+---------+-----------------+
| id | version | data            |
+----+---------+-----------------+
|  1 |       4 | updated 1st     |
|  2 |       2 | second data set |
|  3 |       5 | third data set  |
|  4 |       1 | new 4th         |
+----+---------+-----------------+
4 rows in set (0.00 sec)

REPLACE補足として、そのコマンドで何が起こっているかを理解しやすくするために、次の点に注意してください。

SELECT     s.id s_id, s.version s_version, s.data s_data,
           m.id m_id, m.version m_version, m.data m_data
FROM       secondary s
LEFT JOIN  main m ON (m.id = s.id AND m.version > s.version);

+------+-----------+-------------+------+-----------+----------------+
| s_id | s_version | s_data      | m_id | m_version | m_data         |
+------+-----------+-------------+------+-----------+----------------+
|    1 |         4 | updated 1st | NULL |      NULL | NULL           |
|    3 |         3 | udated 2nd  |    3 |         5 | third data set |
|    4 |         1 | new 4th     | NULL |      NULL | NULL           |
+------+-----------+-------------+------+-----------+----------------+
3 rows in set (0.00 sec)

次に、IFNULL()id = 3、version = 5の場合のように、メインテーブルから最新バージョンが存在する場合、関数は最新バージョンを「上書き」していました。したがって、次のようになります。

SELECT  IFNULL(m.id, s.id) id, 
        IFNULL(m.version, s.version) version, 
        IFNULL(m.data, s.data) data
FROM       secondary s
LEFT JOIN  main m ON (m.id = s.id AND m.version > s.version);

+------+---------+----------------+
| id   | version | data           |
+------+---------+----------------+
|    1 |       4 | updated 1st    |
|    3 |       5 | third data set |
|    4 |       1 | new 4th        |
+------+---------+----------------+
3 rows in set (0.00 sec)

上記の結果セットにはセカンダリテーブルのレコードのみが含まれていますが、これらのレコードのいずれかがメインテーブルに新しいバージョンを持っている場合、行はメインテーブルのデータで上書きされます。これは、REPLACEコマンドにフィードする入力です。

于 2010-09-14T01:59:09.497 に答える
2

重複キー更新時に挿入するのが最善の策だと思います。あなたはそれを次のように使うことができます

INSERT INTO table1 SELECT * FROM table2 ON DUPLICATE KEY UPDATE table1.data=IF(table1.version > table2.version, table1.data, table2.data), table1.version=IF(table1.version > table2.version, table1.version, table2.version)

構文はテストされていませんが、このアイデアは機能するはずです。

于 2010-09-14T01:37:13.057 に答える