I have previously posted about the SQL MERGE statement, and how powerful it is here:
Unfortunately, not all databases support this statement. Also, very often it is quite a bit of overkill, when what you want to do is to simply INSERT or UPDATE a single record, depending on whether it already exists.
MySQL’s nice INSERT statement extensions
MySQL has a couple of very nice extensions to the INSERT statement. Some of them are also supported by the CUBRID database. Let’s have a look at two features of the (simplified) syntax definition:
INSERT [IGNORE] [INTO] tbl_name [(col_name,...)] VALUES (expr,...),(...),... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
Essentially, we’re looking at two keywords / clauses:
- IGNORE: This will cause the INSERT statement to silently fail with a warning, if we’re about to insert a duplicate key
- ON DUPLICATE KEY UPDATE: This will cause the INSERT statement to perform an update on all affected records, if we’re about to insert a duplicate key
The full documentation can be seen here:
How jOOQ models these statements in other dialects
jOOQ’s API conveniently allows for using those MySQL features directly in insert statements. An example
// Insert an author who has recently married and thus // changed their last name. If we already have that author, then // update their last name: create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) .values(3, "Smith") .onDuplicateKeyUpdate() .set(AUTHOR.LAST_NAME, "Smith") .execute(); // Alternatively, we may not care if the author already // exists, we just want to insert them without failure: create.insertInto(AUTHOR, AUTHOR.ID, AUTHOR.LAST_NAME) .values(3, "Smith") .onDuplicateKeyIgnore() .execute();
Note how jOOQ doesn’t model the IGNORE keyword as a keyword between INSERT [IGNORE] INTO. This keeps the public API a bit more concise, while at the same time being more consistent with pre-existing functionality, both in the INSERT syntax, as well as in the Loader API:
Now, databases that do not support these syntax elements can simulate them using MERGE. The above statements will render something like this on an Oracle database:
-- ON DUPLICATE KEY UPDATE statement merge into "AUTHOR" using (select 1 from dual) on ("AUTHOR"."ID" = 3) when matched then update set "LAST_NAME" = 'Smith' when not matched then insert ("ID", "LAST_NAME") values (3, 'Smith') -- ON DUPLICATE KEY IGNORE statement merge into "AUTHOR" using (select 1 from dual) on ("AUTHOR"."ID" = 3) when not matched then insert ("ID", "LAST_NAME") values (3, 'Smith')
These practices allow you to write short and concise code using the jOOQ API while still being able to target several backend databases optimally using efficient SQL statements. This will help you increase both your development as well as your runtime performance!