MERGE INTO таблица, содержащая столбцы AUTO_INCREMENT - PullRequest
1 голос
/ 10 июня 2011

Я объявил следующую таблицу для использования триггерами аудита:

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".

Кажется, что в текущей схеме есть две проблемы.

  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 в существующей строке изменит "время".

Как мне исправить обе эти проблемы?

Ответы [ 2 ]

1 голос
/ 10 июня 2011

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).Это означает, что повторно используйте идентификатор, если запись существует, в противном случае используйте ноль.

См. Также https://stackoverflow.com/a/18819879/14731 для переносного способа вставки или обновления в зависимости от того, существует ли уже строка.


1.MERGE INTO aud_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) и позже, эта несовместимость исправлена.См. Также журнал изменений : «CURRENT_TIMESTAMP () и т. Д. Теперь возвращает то же значение в транзакции».Похоже, что это не проблема в вашем случае, потому что вы, похоже, используете версию 1.3.155 (сообщение об ошибке [90081-155] включает номер сборки / версии).

0 голосов
/ 15 июня 2011

Краткий ответ:

MERGE INTO AUDIT_TRANSACTION_IDS (UUID, время) KEY (UUID, время) VALUES (TRANSACTION_ID (), NOW ());

небольшой совет по производительности: убедитесь, что uuid проиндексирован

Длинный ответ:

MERGE - это, по сути, UPDATE, что INSERT с, если не найдено записей для обновления.

Википедия дает более сжатый, стандартизированный синтаксис MERGE но вы должны предоставить собственное обновление и вставить. (Будет ли это поддерживаться в H2 или нет, я не отвечаю)

Так как же обновить запись, используя MERGE в H2? Вы определяете ключ для поиска, если он найден, вы обновляете строку (с указанными вами именами столбцов, и вы можете определить DEFAULT здесь, чтобы вернуть столбцам значения по умолчанию), иначе вы вставляете строку.

Теперь, что такое Null? Null означает неизвестное, не найденное, неопределенное, все, что не то, что вы ищете.

Именно поэтому Null работает как ключ, который нужно искать. Потому что это означает, что запись не найдена.

MERGE INTO table1 (id, col1, col2) КЛЮЧ (id) ЗНАЧЕНИЯ (ноль, 1, 2)

Null имеет значение. это значение.

Теперь посмотрим ваш SQL.

MERGE INTO table1 (id, col1, col2) КЛЮЧ (id) ЗНАЧЕНИЯ (ПО УМОЛЧАНИЮ, 1, 2)

Что это значит? Для меня это говорит У меня есть это [ПО УМОЛЧАНИЮ, 1, 2], найди мне DEFAULT в столбце id, затем обновите col1 до 1, col2 до 2, если найдено. в противном случае введите значение по умолчанию id, от 1 до col1, от 2 до col2.

Видите, что я там подчеркнул? Что это хотя бы значит? Что такое DEFAULT? Как вы сравниваете DEFAULT с id?

DEFAULT - это просто ключевое слово.

Вы можете делать такие вещи, как,

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

но не ставьте DEFAULT в ключевой столбец.

...