- PR -

Javaでの実行結果とSQL+の実行結果が異なる

投稿者投稿内容
fujie
会議室デビュー日: 2005/04/13
投稿数: 15
投稿日時: 2005-04-13 19:05
藤江と申します。

現在、下記のような現象が起き悩んでいます。

Javaを実行すると、対象レコードに更新はかかっているのですが、
副問合せ部分が正常に取得できず、NULLがセットされてしまいます。

しかし、このような現象になるパターンも掴めておらず、
全てがこのようになるとは限りません。
正常に更新される場合の方が多いのです。


何かご存知でしたら、教えて下さい。
どうぞよろしくお願いいたします。



■DB状態(初期状態)Oracle 9.0.1

DB_A
---------------------------------
CD | KINGAKU | UPDATE_USER
---------------------------------
01 | 0 | system
02 | 0 | system
03 | 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200504 | 500 | system
01 | 200505 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
■Javaソース(JDBC)と実行結果
  

PreparedStatement ps = null;
int para = 1;

String sql =
" update DB_A a " +
" set KINGAKU = (select sum(b.KINGAKU) " +
" from DB_B b " +
" where b.CD = a.CDE " +
" and b.YM = a.YM ) " +
" UPDATE_USER = ? " +
" where (a.CD = ? and " +
" a.YM = ? ) " +
" or (a.CD = ? and " +
" a.YM = ? ) " ;

ps = conn.prepareStatement(sql);
ps.setString (para++, "FUJIE");
ps.setString (para++, "01");
ps.setString (para++, "200503");
ps.setString (para++, "01");
ps.setString (para++, "200504");

ps.executeUpdate();


DB_A
---------------------------------
CD | KINGAKU | UPDATE_USER
---------------------------------
01 | <NULL> | FUJIE ← このレコードに対して更新はかかっていいますが、KINGAKUにNULLがセットされます。
02 | 0 | system
03 | 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200504 | 500 | system
01 | 200505 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
■SQL+での実行結果
  
update DB_A a
set KINGAKU = (select sum(b.KINGAKU)
from DB_B b
where b.CD = a.CDE
and b.YM = a.YM )
UPDATE_USER = 'FUJIE'
where (a.CD = '01' and
a.YM = '200503' )
or (a.CD = '01' and
a.YM = '200504' ) ;


DB_A
---------------------------------
CD | KINGAKU | UPDATE_USER
---------------------------------
01 | 1500 | FUJIE ← 正常に更新されています。
02 | 0 | system
03 | 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200504 | 500 | system
01 | 200505 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------

uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-04-13 19:24
DB_AにYMってカラムはあるんですよね? あったとして合計値が1500になりますか?
SETの各要素間ってカンマ区切りだと思うのですが、スペース区切りで動くんでしたっけ?
fujie
会議室デビュー日: 2005/04/13
投稿数: 15
投稿日時: 2005-04-13 19:31

お返事を頂きありがとうございます。

ソースを転記したときにカンマを落としてしまったようです。
大変申し訳ございません。

実際のソースにはカンマがあります。


update DB_A a
set KINGAKU = (select sum(b.KINGAKU)
from DB_B b
where b.CD = a.CDE
and b.YM = a.YM ) , ← ここにカンマがあります。
UPDATE_USER = 'FUJIE'
where (a.CD = '01' and
a.YM = '200503' )
or (a.CD = '01' and
a.YM = '200504' ) ;


どうぞよろしくお願い致します。
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-04-13 19:39
引用:

ソースを転記したときにカンマを落としてしまったようです。


いや、それはそれでいいんですが、肝心の疑問のほうにお答えいただいていないです。
DB_AとDB_BのCDとYMが一致する条件であれば、1000や500が合計値になりそうなんですが、
テーブルの構成やSQLは本当にあっていますか?
fujie
会議室デビュー日: 2005/04/13
投稿数: 15
投稿日時: 2005-04-13 19:40

色々な個所で辻褄が合わなくなってしまい、申し訳ございません。
再度、記述し直しましたので、どうぞよろしくお願い致します。

uk様、ご指摘頂きまして、どうもありがとうございました。


■DB状態(初期状態)Oracle 9.0.1

DB_A
---------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------
01 |200503| 0 | system
01 |200504| 0 | system
02 |200503| 0 | system
03 |200503| 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200503 | 500 | system
01 | 200504 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
■Javaソース(JDBC)と実行結果
  

PreparedStatement ps = null;
int para = 1;

String sql =
" update DB_A a " +
" set KINGAKU = (select sum(b.KINGAKU) " +
" from DB_B b " +
" where b.CD = a.CDE " +
" and b.YM = a.YM ) , " +
" UPDATE_USER = ? " +
" where (a.CD = ? and " +
" a.YM = ? ) " +
" or (a.CD = ? and " +
" a.YM = ? ) " ;

ps = conn.prepareStatement(sql);
ps.setString (para++, "FUJIE");
ps.setString (para++, "01");
ps.setString (para++, "200503");
ps.setString (para++, "01");
ps.setString (para++, "200504");

ps.executeUpdate();


DB_A
---------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------
01 |200503| <NULL> | FUJIE ← このレコードに対して更新はかかっていいますが、KINGAKUにNULLがセットされます。
01 |200504| 1000 | FUJIE ← 正常に更新されています。
02 |200503| 0 | system
03 |200503| 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200503 | 500 | system
01 | 200504 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
■SQL+での実行結果
  
update DB_A a
set KINGAKU = (select sum(b.KINGAKU)
from DB_B b
where b.CD = a.CDE
and b.YM = a.YM ) ,
UPDATE_USER = 'FUJIE'
where (a.CD = '01' and
a.YM = '200503' )
or (a.CD = '01' and
a.YM = '200504' ) ;


DB_A
---------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------
01 |200503| 1500 | FUJIE ← 正常に更新されています。
01 |200504| 1000 | FUJIE ← 正常に更新されています。
02 |200503| 0 | system
03 |200503| 1500 | system
---------------------------------

DB_B
---------------------------------------
CD | YM | KINGAKU | UPDATE_USER
---------------------------------------
01 | 200503 | 1000 | system
01 | 200503 | 500 | system
01 | 200504 | 1000 | system
02 | 200504 | 1000 | system
02 | 200505 | 1000 | system
03 | 200504 | 1500 | system
---------------------------------------


[ メッセージ編集済み 編集者: fujie 編集日時 2005-04-13 19:42 ]
uk
ぬし
会議室デビュー日: 2003/05/20
投稿数: 1155
お住まい・勤務地: 東京都
投稿日時: 2005-04-13 20:20
少なくともSQLには問題ないようですね。
再現性がない、とのことですがまったく同じSQLで同じパラメータでも問題が出たり出なかったり
するのでしょうか。

まったくのあてずっぽうですが、コネクションやステートメントの使い回しとかしていませんか?
それからSQLの構文を見て思ったのですが、実際のプログラムではSQLを動的に組み立てていたり
しないでしょうか。
fujie
会議室デビュー日: 2005/04/13
投稿数: 15
投稿日時: 2005-04-18 19:37
お返事を頂き、ありがとうございます。

再現性については、同じSQLで同じパラメータでも、問題が出る場合と出ない場合が
あります・・・。
ただ、関係無いかもしれませんが、実行毎に、原因を探るため、
INDEXを変えてみたり、不正に更新されたデータを元の状態に戻すために
データのインポートをしました。


ステートメントは使い回しをしていませんが、コネクションは使い回しています。
1つのトランザクション内で使い回し、正常に終われば、コミットしています。
もしかすると、これが問題なのでしょうか。


また、実際のSQLは、指摘される通り、動的に組み立てています。
出来上がったSQLをSQL+で実行し、その結果と比べて、結果が違うと
判断しました。
これも、問題となるのでしょうか。
今川 美保(夏椰)
ぬし
会議室デビュー日: 2004/06/10
投稿数: 363
お住まい・勤務地: 神奈川県茅ヶ崎市
投稿日時: 2005-04-18 20:07
引用:

fujieさんの書き込み (2005-04-18 19:37) より:
再現性については、同じSQLで同じパラメータでも、問題が出る場合と出ない場合が
あります・・・。
ただ、関係無いかもしれませんが、実行毎に、原因を探るため、
INDEXを変えてみたり、不正に更新されたデータを元の状態に戻すために
データのインポートをしました。


で、少し気になったのですが、集計関数の結果がNULLになるのは
対象行がなかったか、取得した集計対象のデータがすべてNULLの場合に
なると思うのですが・・・
実行時にキーを更新しているとか、データのインポートを実行していたって
いう状態ではなく、まったく他のどのプロセスも更新しない状態で実行しても
再現することがあるのでしょうか?

また発生するときとしないときで状況や、動かし方などに差があったりしますか?

スキルアップ/キャリアアップ(JOB@IT)