Auto_increment列を含むテーブルにマージします
質問
監査トリガーで使用するために次の表を宣言しました。
CREATE TABLE audit_transaction_ids (id IDENTITY PRIMARY KEY, uuid VARCHAR UNIQUE NOT NULL, `time` TIMESTAMP NOT NULL);
トリガーは、同じトランザクションで複数回呼び出されます。
トリガーが初めて呼び出されたときは、現在のtransaction_id()と時間で新しい行を挿入したいと思います。
その後のトリガーが呼び出された場合、「uuid」または「時間」を変更せずに既存の "id"(statement.getGeneratedKeys()をそのために呼び出します)を返したいと思います。
現在のスキーマには2つの問題があるようです。
呼び出すとき
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)
. 。意味、レコードが存在する場合はIDを再利用して、それ以外の場合はnullを使用します。
参照してください https://stackoverflow.com/a/18819879/14731 行が既に存在するかどうかに応じて、挿入またはアップデートするポータブルな方法。
1. audit_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 ... VALUES(.., NOW())
, 、 なぜなら MERGE
ステートメントは、その列を更新することになっています。
または、H2の古いバージョンが同じトランザクション内で異なる値を返したことを意味します(同じトランザクション内で同じ値を返す他のほとんどのデータベースとは異なります)。これは当てはまりますが、H2バージョン1.3.155(2011-05-27)では、この互換性が固定されています。を参照してください ログを変更します: :「current_timestamp()など、トランザクション内で同じ値を返します。」バージョン1.3.155(エラーメッセージ[90081-155]にはビルド /バージョン番号が含まれている)を使用しているように見えるため、これは問題ではないようです。
他のヒント
簡潔な答え:
audit_transaction_ids(uuid、time)key(uuid、time)values(transaction_id()、now())にマージします。
パフォーマンスのヒントはほとんどありません:UUIDがインデックス化されていることを確認してください
長い答え:
MERGE
基本的にです UPDATE
どれの INSERT
sレコードが更新されていないことがわかったとき。
ウィキペディアは、より簡潔で標準化された構文を提供しますマージ ただし、独自の更新と挿入を提供する必要があります。 (これがH2でサポートされるかどうかは私のものではありません)
では、どのようにしてレコードを更新しますか MERGE
H2で?調べる鍵を定義します。それが見つかった場合は、行を更新します(提供する列名が付いていて、定義できます DEFAULT
ここで、列をデフォルトにリセットするには)、それ以外の場合は行を挿入します。
今何ですか Null
? Null
不明、見つかりません、未定義で、あなたが探しているものではないものは何でも意味します。
それが理由です Null
調べる鍵として機能します。レコードが見つからないことを意味するからです。
table1(id、col1、col2)key(id)values(null、1、2)にマージ
Null
値があります。それは値です。
それでは、あなたのSQLを見てみましょう。
table1(id、col1、col2)key(id)values(デフォルト、1、2)にマージする
それは何を暗示していますか?私にとって、それは私がこれを持っていると言います[デフォルト、1、2]、 私を見つけてください DEFAULT
列に id
, 、更新します col1
1に、 col2
見つかった場合は2に。それ以外の場合は、デフォルトを挿入します id
, 、1 to col1
, 、2 to col2
.
私がそこで強調したことを見てください?それは一体何の意味ですか?とは DEFAULT
?どのように比較しますか DEFAULT
に id
?
DEFAULT
単なるキーワードです。
あなたはようなことをすることができます、
table1(id、col1、timestampcol)key(id)values(null、1、default)にマージする
ただし、キー列にデフォルトを入れないでください。