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 是不是有“插入或更新”语句?的主要内容,如果未能解决你的问题,请参考以下文章

SQL 视图中的 DML 语句

DB2 EXPLAIN 命令是不是包含 INSERT 语句的索引更新成本

如何创建表的回滚副本以防我插入或更新错误

MS SQL 技巧总结--持续更新

带条件插入的 Oracle Merge 语句

db2 怎样查一个sql连接执行过的所有语句?