Fusionarse en la tabla que contiene columnas auto_increment
Pregunta
He declarado la siguiente tabla para su uso por desencadenantes de auditoría:
CREATE TABLE audit_transaction_ids (id IDENTITY PRIMARY KEY, uuid VARCHAR UNIQUE NOT NULL, `time` TIMESTAMP NOT NULL);
El disparador se invocará varias veces en la misma transacción.
La primera vez que se invoca el disparador, quiero que inserte una nueva fila con la transacción actual_id () y la hora.
Las veces posteriores se invoca el desencadenante, quiero que devuelva la "ID" existente (invoco Declary.getGeneratedKeys () a ese fin) sin alterar "uuid" o "tiempo".
El esquema actual parece tener dos problemas.
Cuando invoco
MERGE INTO audit_transaction_ids (uuid, time) KEY(id) VALUES(TRANSACTION_ID(), NOW())
Yo obtengo: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]
Sospecho que invocar la fusión en una fila existente alterará el "tiempo".
¿Cómo soluciono ambos problemas?
Solución
MERGE
es análogo a java.util.Map.put(key, value)
: Insertará la fila si no existe, y actualizará la fila si lo hace. Dicho esto, aún puedes fusionarte en una mesa que contiene AUTO_INCREMENT
columnas siempre que use otra columna como clave.
Dado customer[id identity, email varchar(30), count int]
tú podrías 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)
. Es decir, reutilizar la identificación Si existe un registro, use nulo de otra manera.
Ver también https://stackoverflow.com/a/18819879/14731 Para una forma portátil de insertar o actualizar dependiendo de si ya existe una fila.
1. Fusionar en audit_transaction_ids (UUID, Time) Key (ID) Valores (Transaction_id (), ahora ()))
Si solo desea insertar una nueva fila, use:INSERT INTO audit_transaction_ids (uuid, time) VALUES(TRANSACTION_ID(), NOW())
MERGE
sin establecer el valor para la columna ID
no tiene sentido si ID
se usa como clave, porque de esa manera nunca podría (incluso en teoría) actualizar las filas existentes. Lo que podría hacer es usar otra columna clave (en el caso anterior, no hay una columna que pueda usarse). Ver la documentación para MERGE
para detalles.
2. Invocar la fusión en una fila existente alterará el "tiempo"
No estoy seguro de si hablas sobre el hecho de que el valor de la columna 'tiempo' está alterado. Este es el comportamiento esperado si usa MERGE ... VALUES(.., NOW())
, porque el MERGE
Se supone que la declaración actualiza esa columna.
O tal vez quiere decir que las versiones anteriores de H2 devolvieron diferentes valores dentro de la misma transacción (a diferencia de la mayoría de las otras bases de datos, que devuelven el mismo valor dentro de la misma transacción). Esto es cierto, sin embargo, con H2 versión 1.3.155 (2011-05-27) y más tarde, esta incompatibilidad es fija. Ver también el Registro de cambio: "Current_timestamp () y así sucesivamente devuelve el mismo valor dentro de una transacción". Parece que este no es el problema en su caso, porque parece usar la versión 1.3.155 (el mensaje de error [90081-155] incluye el número de compilación / versión).
Otros consejos
Respuesta corta:
Fusionarse en audit_transaction_ids (uuid, time) key (uuid, time) valores (transaccion_id (), ahora ());
Poco consejo de rendimiento: asegúrese de que UUID esté indexado
Respuesta larga:
MERGE
es básicamente un UPDATE
cual INSERT
S cuando no se actualiza ningún registro.
Wikipedia ofrece una sintaxis estandarizada más concisa deUNIR Pero debe proporcionar su propia actualización e insertar. (Si esto será compatible en H2 o no, no es mío para responder)
Entonces, ¿cómo se actualiza un registro usando MERGE
en H2? Defina una clave para ser revelada, si se encuentra que actualiza la fila (con los nombres de la columna que suministra, y puede definir DEFAULT
Aquí, para restablecer sus columnas a sus valores predeterminados), de lo contrario, inserta la fila.
Ahora que es Null
? Null
significa desconocido, no encontrado, indefinido, cualquier cosa que no sea lo que estás buscando.
Es por eso que Null
Funciona como clave para ser admirado. Porque significa que el registro no se encuentra.
Fusionar en los valores de la tecla (ID, COL1, Col2) (ID) (NULL, 1, 2)
Null
tiene un valor. Es un valor.
Ahora veamos tu SQL.
Fusionar en los valores de la tecla (ID, COL1, COL2) (ID) de la Tabla1 (ID, COL1, COL2) (predeterminado, 1, 2)
¿Qué está implicando eso? Para mí, dice que tengo este [predeterminado, 1, 2], Encuéntrame un DEFAULT
en columna id
, luego actualizar col1
a 1, col2
a 2, si se encuentra. De lo contrario, inserte predeterminado a id
, 1 a col1
, 2 a col2
.
¿Ves lo que enfaticé allí? ¿Y eso que significa? Que es DEFAULT
? ¿Cómo se compara? DEFAULT
a id
?
DEFAULT
es solo una palabra clave.
Puedes hacer cosas como,
Fusionar en la Tabla1 (ID, COL1, Timestampcol) Key (ID) Valores (NULL, 1, predeterminado)
Pero no ponga predeterminado en la columna clave.