Слияние в таблицу, содержащие столбцы Auto_Increment
Вопрос
Я объявил следующую таблицу для использования с помощью триггеров аудита:
CREATE TABLE audit_transaction_ids (id IDENTITY PRIMARY KEY, uuid VARCHAR UNIQUE NOT NULL, `time` TIMESTAMP NOT NULL);
Триггер будет вызван несколько раз в одной и той же транзакции.
В первый раз, когда триггер вызывает, я хочу, чтобы он вставил новую строку с текущей Transaction_ID () и времени.
В последующие времена, когда триггер вызывается, я хочу, чтобы он вернул существующий «id» (я вызываю ratement.getGeneratedKeys () с этой целью), не изменяя «uuid» или «время».
В текущей схеме, кажется, есть две проблемы.
Когда я призываю
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]
Я подозреваю, что призыв слияния в существующем ряду изменит «время».
Как решить обе эти проблемы?
Решение
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)
. Анкет Значение, повторно используйте идентификатор, если запись существует, используйте NULL в противном случае.
Смотрите также https://stackoverflow.com/a/18819879/14731 для портативного способа вставить или обновлять в зависимости от того, существует ли ряд.
1. Слияние в Audit_transaction_ids (Uuid, Time) Key (ID) VALUES (Transaction_ID (), теперь ())
Если вы просто хотите вставить новый ряд, используйте:INSERT INTO audit_transaction_ids (uuid, time) VALUES(TRANSACTION_ID(), NOW())
MERGE
без установки значения для столбца ID
не имеет смысла, если ID
используется в качестве ключа, потому что таким образом он никогда не может (даже в теории) обновлять существующие строки. То, что вы могли бы сделать, это использовать другой столбец ключа (в приведенном выше случае, который не может быть использован). Смотрите документацию для MERGE
Для деталей.
2. Вызов слияния в существующем ряду изменит «время»
Я не уверен, что вы говорите о том, что значение «Время столбца» изменяется. Это ожидаемое поведение, если вы используете MERGE ... VALUES(.., NOW())
, поскольку MERGE
Заявление должно обновить этот столбец.
Или, может быть, вы имеете в виду, что более старые версии H2 возвращали различные значения в одной и той же транзакции (в отличие от большинства других баз данных, которые возвращают одно и то же значение в одной и той же транзакции). Это верно, однако с помощью H2 версии 1.3.155 (2011-05-27), а затем эта несовместимость исправлена. Смотрите также изменить журнал: «Current_timestamp () и т. Д. Теперь возвращает такое же значение в транзакции». Похоже, это не проблема в вашем случае, потому что вы, похоже, используете версию 1.3.155 (сообщение об ошибке [90081-155] включает номер сборки / версии).
Другие советы
Короткий ответ:
Слияние в AUDIT_TRANCACTION_IDS (UUID, TIME) КЛЮЧ (UUID, TIME) Значения (Transaction_ID (), теперь ());
Маленький совет производительности: убедитесь, что UUID индексирован
Длинный ответ:
MERGE
в основном UPDATE
который INSERT
S, когда не обнаружена записи.
Википедия дает более краткий, стандартизированный синтаксисСлияние Но вы должны предоставить свое собственное обновление и вставить. (Независимо от того, будет ли это поддерживать в H2 или нет, не является моим, чтобы ответить)
Итак, как вы обновляете запись, используя MERGE
в H2? Вы определяете ключ для поиска, если он найден, вы обновляете строку (с именами столбцов, которые вы поставляете, и вы можете определить DEFAULT
Здесь, чтобы сбросить свои столбцы к его значениям по умолчанию), в противном случае вы вставляете строку.
Теперь что есть Null
? Null
означает неизвестный, не найденный, не определен, что -то, что не ищете.
Поэтому Null
Работает как ключ, чтобы найти вверх. Потому что это означает, что запись не найдена.
Слияние в таблицу 1 (id, col1, col2) значения (ID) (NULL, 1, 2)
Null
имеет значение. это значение.
Теперь давайте посмотрим на ваш SQL.
Слияние в таблицу 1 (ID, COL1, COL2) значения (ID) (по умолчанию, 1, 2)
Что это подразумевает? Для меня это говорит, что у меня есть это [по умолчанию, 1, 2], Найди меня DEFAULT
в столбце id
, затем обновление col1
до 1, col2
до 2, если найдено. В противном случае вставьте дефолт в id
, 1 к col1
, 2 до col2
.
Видите, что я там подчеркнул? Что это хотя бы значит? Что такое DEFAULT
? Как сравнить DEFAULT
к id
?
DEFAULT
это просто ключевое слово.
Вы можете делать такие вещи, как,
Слияние в таблицу 1 (id, col1, timestampcol) щедрости (ID) значения (null, 1, по умолчанию)
Но не ставите по умолчанию в столбце ключа.