DB2 是不是有“插入或更新”语句?
Posted
技术标签:
【中文标题】DB2 是不是有“插入或更新”语句?【英文标题】:Does DB2 have an "insert or update" statement?DB2 是否有“插入或更新”语句? 【发布时间】:2010-09-24 17:17:17 【问题描述】:从我的代码 (Java) 中,我想确保在我的代码执行后数据库 (DB2) 中存在一行。
我的代码现在执行select
,如果没有返回结果,它执行insert
。我真的不喜欢这段代码,因为它让我在多线程环境中运行时遇到并发问题。
我想做的是把这个逻辑放在 DB2 中,而不是放在我的 Java 代码中。
DB2 是否有insert-or-update
语句?或者我可以使用的任何类似的东西?
例如:
insertupdate into mytable values ('myid')
另一种方法可能是始终执行插入并捕获“SQL-code -803 主键已存在”,但如果可能的话,我想避免这种情况。
【问题讨论】:
每个线程一个事务不是更好吗? DBMS 擅长多线程,这就是发明事务的原因。他们会解决并发问题。 这并不能解决并发问题,因为事务只能通过阻塞已经存在的行来工作。如果该行不存在,则事务无法对其进行阻塞,因此这种操作仍然存在并发问题 【参考方案1】:是的,DB2 有 MERGE 语句,它将执行 UPSERT(更新或插入)。
MERGE INTO target_table USING source_table ON match-condition
WHEN [NOT] MATCHED
THEN [UPDATE SET ...|DELETE|INSERT VALUES ....|SIGNAL ...]
[ELSE IGNORE]
见:
http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.admin.doc/doc/r0010873.htm
https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0010873.html
https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/merge?lang=en
【讨论】:
示例很有用:使用 (values('col1', 'col2')) as tmp (code, name) on mytable.code = tmp.code 当匹配时合并到 mytable更新集名称= col2' DB2 对合并语句有一些过时的限制。 #1 有关通过合并完成的插入/更新/删除数量的统计信息是垃圾,并且已记录在案。 #2。更重要的是,如果您需要从在插入时自动创建 ID 的列返回标识值,则无法通过 Merge 执行此操作。 IDENTITY_VAL_LOCAL 无法获取与插入关联的新 ID。我曾担任过 DBA,并针对如此多的数据库进行了编程,而 DB2 是我在这 25 多年中经历过的最古怪、最困难、最奇怪、过时的特性数据库。【参考方案2】:我找到这个线程是因为我真的需要一个用于 DB2 INSERT OR UPDATE 的单行代码。
以下语法似乎有效,不需要单独的临时表。
它通过使用 VALUES() 创建表结构来工作。 SELECT * 恕我直言似乎多余,但没有它我会遇到语法错误。
MERGE INTO mytable AS mt USING (
SELECT * FROM TABLE (
VALUES
(123, 'text')
)
) AS vt(id, val) ON (mt.id = vt.id)
WHEN MATCHED THEN
UPDATE SET val = vt.val
WHEN NOT MATCHED THEN
INSERT (id, val) VALUES (vt.id, vt.val)
;
如果您必须插入多行,则可以重复 VALUES 部分,而无需复制其余部分。
VALUES
(123, 'text'),
(456, 'more')
结果是一个可以插入或更新一行或多行的单个语句,大概是原子操作。
【讨论】:
您有可能想使用SELECT 'value' name FROM SYSIBM.SYSDUMMY1
而不是SELECT * FROM TABLE VALUES
“大概作为原子操作” - 这取决于您的事务隔离级别,至少对我而言,在默认设置的并发用例中导致错误。解决方案是使用关键字WITH RR
显式设置隔离级别“可重复读取”。 db2 中的隔离级别:ibm.com/support/knowledgecenter/en/SSEPGG_10.5.0/…
我很伤心,我们不能在这个请求中使用准备好的语句。【参考方案3】:
此回复希望能完全回答 MrSimpleMind 在use-update-and-insert-in-same-query 中的查询,并提供一个简单的 DB2 MERGE 语句示例,其中包含一次性插入和更新的场景(ID 为 2 的记录已更新,记录 ID 3 个插入)。
CREATE TABLE STAGE.TEST_TAB ( ID INTEGER, DATE DATE, STATUS VARCHAR(10) );
COMMIT;
INSERT INTO TEST_TAB VALUES (1, '2013-04-14', NULL), (2, '2013-04-15', NULL); COMMIT;
MERGE INTO TEST_TAB T USING (
SELECT
3 NEW_ID,
CURRENT_DATE NEW_DATE,
'NEW' NEW_STATUS
FROM
SYSIBM.DUAL
UNION ALL
SELECT
2 NEW_ID,
NULL NEW_DATE,
'OLD' NEW_STATUS
FROM
SYSIBM.DUAL
) AS S
ON
S.NEW_ID = T.ID
WHEN MATCHED THEN
UPDATE SET
(T.STATUS) = (S.NEW_STATUS)
WHEN NOT MATCHED THEN
INSERT
(T.ID, T.DATE, T.STATUS) VALUES (S.NEW_ID, S.NEW_DATE, S.NEW_STATUS);
COMMIT;
【讨论】:
我想指出一些ibm数据库使用SYSIBM.SYSDUMMY1
作为虚拟表而不是SYSIBM.DUAL
【参考方案4】:
另一种方法是执行这 2 个查询。它比创建 MERGE 语句更简单:
update TABLE_NAME set FIELD_NAME=xxxxx where MyID=XXX;
INSERT INTO TABLE_NAME values (MyField1,MyField2)
WHERE NOT EXISTS(select 1 from TABLE_NAME where MyId=xxxx);
如果 MyId 存在,第一个查询只会更新您需要的字段。 如果 MyId 不存在,则第二个将行插入 db。
结果是只有一个查询在您的数据库中执行。
【讨论】:
如果您的 DB2 版本有MERGE
,则更喜欢这样 - 这将有助于消除某些潜在的并发问题。不过,我不会自动将其标记为“更简单”;处理两个语句(必须保持同步!)会产生额外的开销,并且它并不能真正解决在UPDATE
和您自己的INSERT
之间插入行的不同进程的可能性...
insert
语句在语法上不正确。【参考方案5】:
我从休眠项目开始,休眠允许您保存或更新()。 我将该项目转换为 JDBC 项目,问题在于保存和更新。 我想使用 JDBC 同时保存和更新。 所以,我做了一些研究,发现了重复密钥更新:
String sql="Insert into tblstudent (firstName,lastName,gender) values (?,?,?)
ON DUPLICATE KEY UPDATE
firstName= VALUES(firstName),
lastName= VALUES(lastName),
gender= VALUES(gender)";
上述代码的问题是它两次更新主键,这是真的 根据 mysql 文档: 受影响的行只是一个返回码。 1 行表示您已插入,2 表示您已更新,0 表示未发生任何事情。
我引入了 id 并将其递增到 1。现在我正在递增 id 的值而不是 mysql。
String sql="Insert into tblstudent (id,firstName,lastName,gender) values (?,?,?)
ON DUPLICATE KEY UPDATE
id=id+1,
firstName= VALUES(firstName),
lastName= VALUES(lastName),
gender= VALUES(gender)";
上面的代码对我来说插入和更新都有效。
希望它也对你有用。
【讨论】:
问题是关于 DB/2。你在谈论MySQL。您是否真的检查过您提出的语法在 DB/2 中是否可用?以上是关于DB2 是不是有“插入或更新”语句?的主要内容,如果未能解决你的问题,请参考以下文章