MERGE INTO包含AUTO_INCREMENT列的表

时间:2011-06-10 12:48:59

标签: sql h2 sql-merge

我已声明下表供审计触发器使用:

CREATE TABLE audit_transaction_ids (id IDENTITY PRIMARY KEY, uuid VARCHAR UNIQUE NOT NULL, `time` TIMESTAMP NOT NULL);
  1. 触发器将在同一事务中多次调用。

  2. 第一次调用触发器时,我希望它插入一个新的触发器 具有当前TRANSACTION_ID()和时间的行。

  3. 随后调用触发器,我希望它返回 现有的“id”(我为此调用了Statement.getGeneratedKeys()) 不改变“uuid”或“time”。

  4. 目前的架构似乎有两个问题。

    1. 当我调用MERGE INTO audit_transaction_ids (uuid, time) KEY(id) VALUES(TRANSACTION_ID(), NOW())时,我得到:org.h2.jdbc.JdbcSQLException: Column "ID" contains null values; SQL statement: MERGE INTO audit_transaction_ids (uuid, time) KEY(id) VALUES (TRANSACTION_ID(), NOW()) [90081-155]

    2. 我怀疑在现有行上调用MERGE会改变“时间”。

    3. 如何解决这两个问题?

2 个答案:

答案 0 :(得分:1)

MERGE类似于java.util.Map.put(key, value):如果行不存在,它将插入行,如果有,则更新行。话虽这么说,只要您使用另一列作为键,您仍然可以合并到包含AUTO_INCREMENT列的表中。

鉴于customer[id identity, email varchar(30), count int]你可以merge into customer(id, email, count) key(email) values((select max(id) from customer c2 where c2.email='test@acme.com'), 'test@acme.com', 10)。意思是,如果存在记录则重新使用id,否则使用null。

另请参阅https://stackoverflow.com/a/18819879/14731以获取插入或更新的可移植方式,具体取决于行是否已存在。


<强> 1。 MERGE INTO audit_transaction_ids(uuid,time)KEY(id)VALUES(TRANSACTION_ID(),NOW())

如果您只想插入新行,请使用: INSERT INTO audit_transaction_ids (uuid, time) VALUES(TRANSACTION_ID(), NOW())

如果MERGE被用作关键字,那么

ID没有设置列ID的值是没有意义的,因为这种方式它永远不会(甚至在理论上)更新现有行。您可以做的是使用另一个键列(在上面的情况下,没有可以使用的列)。有关详细信息,请参阅MERGE的文档。

<强> 2。在现有行上调用MERGE将改变“时间”

我不确定你是否谈到了'时间'一栏的价值被改变的事实。如果您使用MERGE ... VALUES(.., NOW()),这是预期的行为,因为MERGE语句应该更新该列。

或许您的意思是旧版本的H2在同一个事务中返回不同的值(与大多数其他数据库不同,它们在同一事务中返回相同的值)。这是事实,但是对于H2版本1.3.155(2011-05-27)以及之后的情况,这种不兼容性是固定的。另请参阅change log:“CURRENT_TIMESTAMP()等现在在事务中返回相同的值。”看起来这不是你的问题,因为你似乎使用版本1.3.155(错误消息[90081-155]包括版本/版本号)。

答案 1 :(得分:0)

简答:

合并到AUDIT_TRANSACTION_IDS(uuid,time)KEY(uuid,time)  VALUES(TRANSACTION_ID(),NOW());

一点性能提示:确保将uuid编入索引

长答案:

MERGE基本上是UPDATE INSERT,当没有找到更新的记录时。

维基百科提供了更简洁,标准化的语法 MERGE但您必须提供自己的更新和插入。  (这是否会在H2中得到支持不是我的回答)

那么如何在H2中使用MERGE更新记录?您可以定义要查找的密钥,如果发现您更新了行(使用您提供的列名,并且可以在此处定义DEFAULT,则将列重置为其默认值),否则您将插入行。

现在什么是NullNull表示未知,未找到,未定义,任何不是您正在寻找的东西。

这就是Null作为被关注的关键所在的原因。因为这意味着找不到记录。

  

MERGE INTO table1(id,col1,col2)   KEY(id)VALUES(Null,1,2)

Null有一个值。这是一个价值。

现在让我们看看你的SQL。

  

MERGE INTO table1(id,col1,col2)   KEY(id)VALUES(DEFAULT,1,2)

这意味着什么?对我说,它说  我有[默认,1,2], 在列DEFAULT 中找到id,  然后将col1更新为1,col2更新为2(如果找到)。  否则,默认为id,1为col1,2为col2

看看我在那里强调了什么?那有什么意思?什么是DEFAULT?您如何比较DEFAULTid

DEFAULT只是一个关键字。

你可以做点什么,

  

MERGE INTO table1(id,col1,   timeStampCol)KEY(id)VALUES(Null,1,   DEFAULT)

但不要将DEFAULT放在键列中。