В MySQL, как вставить только тогда, когда строка не существует, и обновить только тогда, когда существующая версия меньше - PullRequest
3 голосов
/ 14 сентября 2010

Я ищу способ вставки, только когда строка не существует в 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

И я хочу объединить следующую таблицу (ОБНОВЛЕНИЕ:Столбец 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.Кроме того, я не могу использовать REPLACE , потому что он также не позволяет WHERE.Возможно ли это даже с одним оператором MySQL?

Я использую Java и пытаюсь вставить / обновить множество записей, используя PreparedStatement с пакетной обработкой (addBatch).Буду признателен за любую помощь.

ОБНОВЛЕНИЕ: Есть ли способ использовать этот запрос с PreparedStatement в Java?У меня есть список объектов Document с id, версией и данными.

Ответы [ 2 ]

3 голосов
/ 14 сентября 2010

РЕДАКТИРОВАТЬ: В моем предыдущем ответе я предположил, что на (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.

2 голосов
/ 14 сентября 2010

Я думаю, INSERT ON DUPLICATE KEY UPDATE - ваша лучшая ставка.Вы можете использовать его как

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)

Непроверенный синтаксис, но я верю, что идея должна работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...