Java 在MySQL中,如何仅在行不';t仅当现有版本较少时才存在和更新
我正在寻找一种方法,只在MySQL中不存在行时插入,并在存在行且现有行的版本小于(或等于)新行的版本时更新 例如,该表定义为:Java 在MySQL中,如何仅在行不';t仅当现有版本较少时才存在和更新,java,mysql,insert,replace,insert-update,Java,Mysql,Insert,Replace,Insert Update,我正在寻找一种方法,只在MySQL中不存在行时插入,并在存在行且现有行的版本小于(或等于)新行的版本时更新 例如,该表定义为: CREATE TABLE documents ( id VARCHAR(64) NOT NULL, version BIGINT UNSIGNED NOT NULL, data BLOB, PRIMARY KEY (id) ); 并包含以下数据: id version data ---------------------------- 1 3
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列是唯一的):
它应该生成以下内容(更新:查看如何仅更新1并插入4):
我已经看过了语句,但它不允许使用某种WHERE子句。此外,我不能真正使用,因为它也不允许在哪里。用一条MySQL语句就可以做到这一点吗
我正在使用Java,并尝试使用with batch(addBatch)插入/更新许多记录。任何帮助都将不胜感激
更新:在Java中,有没有办法将此查询与PreparedStatement一起使用?我有一个包含id、版本和数据的文档对象列表。我认为重复密钥更新时插入是最好的选择。你可以像这样使用它
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)
未经测试的语法,但我相信这个想法应该有效。编辑:在我之前的回答中,我建议在
(id,版本)
上需要一个唯一的约束,但实际上这不是必需的。您仅对id
的唯一约束就足以使解决方案工作
您应该能够按如下方式使用该命令:
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)
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)
然后,IFNULL()
函数负责从主表中“覆盖”最新版本(如果存在),如id=3,version=5。因此:
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)
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
命令。您如何知道何时添加不存在的行?对不起,我忘了提到id是唯一的。但是id
是自动递增的,不是吗?这个问题仍然有待抽象,以便我知道何时应该进行插入或更新,对不起。不,id不是自动递增的,事实上,它是一个varchar列。我使用了两个表作为示例,但实际上我没有两个表。我有一个文档对象列表,其中包含以下字段:id、版本和数据。我正试图通过Java中的PreparedStatements找出这样做的语法。然后去掉table2引用,并将插入值的地方放在?s中。@Todd,我认为你的答案与我实际寻找的最接近。我将对你的答案和丹尼尔的答案进行测试,看看哪一个能产生更好的性能结果。@Mohamed:你说得对,我认为这更快。我忽略了这样一个事实,即REPLACE
在重新插入行之前会删除该行。@Daniel,测试性能似乎没有意义,因为我还必须添加创建临时表、填充临时表以及将其与主表内部联接所需的时间。好的Daniel,还有一个问题。如何在不需要辅助表的情况下执行相同的查询?@Mohamed:如果不需要,要合并的数据将保存在哪里?@Mohamed:您可能需要辅助表:创建临时辅助表(id int,…)代码>。。。然后INSERT
将应用程序中的数据插入临时辅助表,并应用REPLACE
功能。会话终止时会自动删除临时表。@Daniel,假设我有一个列表
,其中包含id
、版本
、和数据
成员,并且我想使用PreparedStatement.addBatch()
。。我想要一个简单的语句(如果不存在,则插入…,否则如果orig.version我对临时表的性能不是很确定。我基本上会在3MM行的区域插入一些东西…我不知道临时表是否能够处理它。但我会设置一个性能测试,看看它是否可以接受。谢谢!