Merge文って?
Merge文はSQL Serverでは2008より、Oracleでは9iぐらいから実装されたSQL構文です。
機能としては、Insert OR Update(存在しなければInsert,存在すればUpdate)、もしくは、Insert OR Update OR Delete(存在しなければInsert,存在すればUpdate OR Delete)を行ってくれます。
ちなみに、SQL ServerとOracleではMerge文の構文が少し違ったりします。Merge文自体SQL2003から追加された標準なのですが、Oracleは以前から実装している関係上、下位互換が必要(Update時にWhere句を付与可能とか)ですし、SQL ServerはSQL Serverで独自の拡張(WHEN MATCHED のあとにANDコンディション付与可能とか)をしています。
差異があるとはいえ、ほぼ同じような構文ですし、今回はExecuteNonQueryにおける違いを説明するので、あんまそっちのほうは詳しく述べません。
ExecuteNonQueryの何が違うの?
まずは次のSQLを用意します。
1. SQL Server 2008用のMerge文
MERGE INTO MergeTable as Target
USING (VALUES(@key1, @col1, @col2, @optLock))
as InputSrc (Key1, Col1, Col2, OptLock)
ON Target.Key1 = InputSrc.Key1
WHEN MATCHED AND Target.OptLock = InputSrc.OptLock THEN
UPDATE SET
Col1 = InputSrc.Col1
, Col2 = InputSrc.Col2
WHEN NOT MATCHED THEN
INSERT (Key1, Col1, Col2)
VALUES (InputSrc.Key1, InputSrc.Col1, InputSrc.Col2);
2. Oracle用のMerge文
MERGE INTO MergeTable Target
USING (SELECT :key1 Key1, :col1 Col1, :col2 Col2, :optLock OptLock
FROM DUAL) InputSrc
ON (Target.Key1 = InputSrc.Key1)
WHEN MATCHED THEN
UPDATE SET
Col1 = InputSrc.Col1
, Col2 = InputSrc.Col2
WHERE Target.OptLock = InputSrc.OptLock
WHEN NOT MATCHED THEN
INSERT (Key1, Col1, Col2, OptLock)
VALUES (InputSrc.Key1, InputSrc.Col1, InputSrc.Col2, systimestamp);
詳しくは述べませんといった舌の根も乾かぬうちに脱線してしまいますが(^^;)、二つのSQLの大きな違いは、SQLServer2008の5行目とOracleの9行目です。これらは楽観ロックを実装している部分です。SQL2003のBNFを確認したところ、そもそも標準にON句以外で追加の条件を指定する仕組みがなく、OracleとSQLServer2008ともに追加条件に対する部分を拡張しているとも取れます。(Oracleはそもそも9iの時代からこうだったのかもしれませんが…(未確認))
閑話休題
さて、ExecuteNonQueryを実行した結果ですが、結論だけ言ってしまうと…
Oracleの場合、ExecuteNonQueryを使用して流すと、メソッドの返却値として「-1」が返ってきてしまいます!(環境はOracleXEとODP.NET 10.2)
一方、SQL Serverの方はといえば、ちゃんと更新した行数が返ってきます。さすがMS大先生。
しかし、MSしっかりしているなぁ~などと思ってMSDNのSqlCommand.ExecuteNonQueryの項目を読んでみると
UPDATE、INSERT、および DELETE ステートメントでの戻り値は、そのコマンドの影響を受ける行数です。他の種類のステートメントでの戻り値は、-1 です。ロールバックが発生した場合も、戻り値は -1 です。
文書が更新されてませんなぁw