MERGE INTO table containing AUTO_INCREMENT columns
I've declared the following table for use by audit triggers:
CREATE TABLE audit_transaction_ids (id IDENTITY PRIMARY KEY, uuid VARCHAR UNIQUE NOT NULL, `time` TIMESTAMP NOT NULL);
The trigger will get invoked multiple times in the same transaction.
The first time the trigger开发者_JAVA技巧 is invoked, I want it to insert a new row with the current TRANSACTION_ID() and time.
The subsequent times the trigger is invoked, I want it to return the existing "id" (I invoke Statement.getGeneratedKeys() to that end) without altering "uuid" or "time".
The current schema seems to have two problems.
When I invoke
MERGE INTO audit_transaction_ids (uuid, time) KEY(id) VALUES(TRANSACTION_ID(), NOW())
I get: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]
I suspect that invoking MERGE on an existing row will alter "time".
How do I fix both these problems?
MERGE
is analogous to java.util.Map.put(key, value)
: it will insert the row if it doesn't exist, and update the row if it does. That being said, you can still merge into a table containing AUTO_INCREMENT
columns so long as you use another column as the key.
Given customer[id identity, email varchar(30), count int]
you could 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)
. Meaning, re-use the id if a record exists, use null otherwise.
See also https://stackoverflow.com/a/18819879/14731 for a portable way to insert-or-update depending on whether a row already exists.
1. MERGE INTO audit_transaction_ids (uuid, time) KEY(id) VALUES(TRANSACTION_ID(), NOW())
If you just want to insert a new row, use:
INSERT INTO audit_transaction_ids (uuid, time) VALUES(TRANSACTION_ID(), NOW())
MERGE
without setting the value for the column ID
doesn't make sense if ID
is used as the key, because that way it could never (even in theory) update an existing rows. What you could do is using another key column (in the case above there is no column that could be used). See the documentation for MERGE
for details.
2. Invoking MERGE on an existing row will alter "time"
I'm not sure if you talk about the fact that the value of the column 'time' is altered. This is the expected behavior if you use MERGE ... VALUES(.., NOW())
, because the MERGE
statement is supposed to update that column.
Or maybe you mean that older versions of H2 returned different values within the same transaction (unlike most other databases, which return the same value within the same transaction). This is true, however with H2 version 1.3.155 (2011-05-27) and later, this incompatibility is fixed. See also the change log: "CURRENT_TIMESTAMP() and so on now return the same value within a transaction." It looks like this is not the problem in your case, because you do seem to use version 1.3.155 (the error message [90081-155] includes the build / version number).
Short Answer:
MERGE INTO AUDIT_TRANSACTION_IDS (uuid, time) KEY (uuid, time) VALUES (TRANSACTION_ID(), NOW());
little performance tip: make sure uuid is indexed
Long Answer:
MERGE
is basically an UPDATE
which INSERT
s when no record found to be updated.
Wikipedia gives a more concise, standardized syntax of MERGE but you have to supply your own update and insert. (Whether this will be supported in H2 or not is not mine to answer)
So how do you update a record using MERGE
in H2? You define a key to be looked up for, if it is found you update the row (with column names you supply, and you can define DEFAULT
here, to reset your columns to its defaults), otherwise you insert the row.
Now what is Null
? Null
means unknown, not found, undefined, anything which is not what you're looking for.
That is why Null
works as key to be looked up for. Because it means the record is not found.
MERGE INTO table1 (id, col1, col2) KEY(id) VALUES (Null, 1, 2)
Null
has a value. it IS a value.
Now let's see your SQL.
MERGE INTO table1 (id, col1, col2) KEY(id) VALUES (DEFAULT, 1, 2)
What is that implying? To me, it says
I have this [DEFAULT, 1, 2], find me a DEFAULT
in column id
,
then update col1
to 1, col2
to 2, if found.
otherwise, insert default to id
, 1 to col1
, 2 to col2
.
See what I emphasized there? What does that even mean? What is DEFAULT
? How do you compare DEFAULT
to id
?
DEFAULT
is just a keyword.
You can do stuff like,
MERGE INTO table1 (id, col1, timeStampCol) KEY(id) VALUES (Null, 1, DEFAULT)
but don't put DEFAULT in the key column.
精彩评论