3

問題

次のようなクエリを実行する SQLRPGLE プログラムがあります。

SELECT orapdt, oraptm, orodr#, c.ccctls, orbill, b.cuslmn, b.cusvrp, orocty, orost, o.cubzip, o.cucnty, ordcty, ordst, d.cubzip, d.cucnty
FROM order
LEFT JOIN cmtctlf c ON orbill = c.cccode
LEFT JOIN custmast b ON orbill = b.cucode
LEFT JOIN custmast o ON orldat = o.cucode
LEFT JOIN custmast d ON orcons = d.cucode
WHERE
    orstat != 'C' AND
    orbill IN ('ABCDE', 'VWXYZ', 'JKFRTE') AND
    orapdt BETWEEN 2012365 AND 2013362 AND
    o.cucnty = 'USA' AND 
    (o.cubzip LIKE '760%' OR o.cubzip LIKE '761%' OR o.cubzip LIKE '762%') AND
    d.cubzip = '38652' AND
    ordcty = 'NA' AND
    ordst = 'MS' AND 
    d.cucnty = 'USA'
ORDER BY orapdt, oraptm, orodr#

フィールド定義:

orapdt      7  0
oraptm      4a
orodr#      7a
c.ccctls    6a
orbill      6a
b.cuslmn    2a
b.cusvrp    3a
orocty      4a
orost       2a
o.cubzip    5a
o.cucnty    3a
ordcty      4a
ordst       2a
d.cubzip    5a
d.cucnty    3a
c.cccode    6a
b.cucode    6a
o.cucode    6a
d.cucode    6a

ジョブ ログに次のエラーが表示されます。

Field HVR0001 and value 1 not compatible. Reason 7.
Conversion error on host variable or parameter *N.

追加のメッセージ情報を求めるプロンプトが表示されると、次のように表示されます。

The attributes of variable field HVR0001 in query record format FORMAT0001 are not compatible with the attributes of value number 1. The value is *N. The reason code is 7.
7 -- Value contains numeric data that is not valid

Host variable or parameter *N or entry 1 in a descriptor area contains a value that cannot be converted to the attributes required by the statement. Error type 6 occurred.
6 -- Numeric data that is not valid.

これらのエラーは、カーソルを開くとトリガーされます。

...
exec sql PREPARE S1 FROM :sql_stmt;
exec sql DECLARE C1 SCROLL CURSOR FOR S1;
exec sql OPEN C1;
...

outq には、ダンプ情報で満たされた QSQSVCDMP ファイルもあります。そこにある唯一の有用なものは、CPF4278 と CPD4374 への参照です。

CPF4278 の意味Query definition template &1 not valid.

CPD4374 の意味Field &1 and value &3 not compatible. Reason &5.

残念ながら、エラー メッセージ自体は存在せず、"CPF4278" と "CPD4374" という文字列のみです。

プログラムでは、SQLエラーコードを監視していますが、それらはすべて同じです:

SQLSTATE:  22023
SQLCODE:  -302
SQLERRMC:  <non-displayable character>*N

エラー状態/コードは、「パラメーターまたは変数の値が無効です」を意味します。

私が試したこと...

多くのグーグルの後、私は試しました:

  1. ORDER BY 句の削除 (OPEN では、ORDER BY 句がある場合、データがフェッチされて並べ替えられます)
  2. すべての LEFT JOIN を INNER JOIN に変更します (右側の結果レコードに NULL がないことを確認するためにこれを行いました)
  3. WHERE句に「AND orapdt IS NOT NULL」を追加
  4. 私が忘れてしまった多くのこと

私が求めているのは...

どのフィールドに不正なデータが含まれているかを調べるにはどうすればよいですか? 無効であることはわかってHVR0001いますが、どのフィールドが で表されHVR0001ますか? フィールドを別の順序で選択しようとしましたが、常にHVR0001無効な値が含まれています。

理想的には、すべての HVR* フィールド/値を印刷して検査できるようにしたいと考えています。

コンパイル リストを見ると、HVR* フィールドがリストされていません。いくつかの SQL_* フィールドがリストされており、SQL_00011に入れられるデータを一時的に保持するために使用されていることがわかりorapdtます。(7,0 パック)SQL_00011とまったく同じように定義されます。orapdtそれが私のクエリの唯一の数値フィールドです...

私の問題は、ファイルがどのように結合されているか、無効な値 (おそらく NULL) がorapdtフィールドに配置されていることが原因であると感じています。

また、私の問題は、これらのクエリの多くを次々に実行することと関係があると思います (クエリごとに WHERE 仕様の一部が変更されます)。失敗したクエリの 1 つを取得して、それを独自のプログラムに入れて実行できるからです。そしてそれはうまくいきます。

これは DB2 for i (V6R1) 上にあり、関連するすべてのファイルは DDS を使用して作成されました

編集:ホスト変数(データ構造)とLIKEステートメントに必要な2つの外部データ構造は次のとおりです。

d eds_custmast  e ds    extname('CUSTMAST') inz
d eds_order     e ds    extname('ORDER') inz

d o               ds
d orapdt                like(ORAPDT)
d oraptm                like(ORAPTM)
d orodr#                like(ORODR#)
d orctls                like(CUCODE)
d orbill                like(ORBILL)
d orslmn                like(CUSLMN)
d orcsr                 like(CUSVRP)
d orocty                like(OROCTY)
d orost                 like(OROST)
d orozip                like(CUBZIP)
d orocntry              like(CUCNTY)
d ordcty                like(ORDCTY)
d ordst                 like(ORDST)
d ordzip                like(CUBZIP)
d ordcntry              like(CUCNTY)

// Define an array to indicate nulls...
d o1nv            s     3i 0 dim(15)

実際にデータを取得する fetch ステートメントは次のとおりです。

dow sqlcode = *zeros;
   exec sql FETCH NEXT FROM C1 INTO :o :o1nv;

   if sqlcode = *zeros;
      // process the data.
   endif;
enddo;

exec sql CLOSE C1;

行をFETCHするのではなく、カーソルをOPENするときにエラーが発生するため、以前はこれを含めませんでした。oOPEN ステートメントは、データ構造について何も認識してはなりません。

WHERE 句で何が変更されるかについては、次のもの以外はすべて動的に構築されます (したがって、変更される可能性があります)。

orstat != 'C' AND orapdt BETWEEN 2012365 AND 2013362
4

4 に答える 4

2

実際のエラーが何であるかを見つけるのは簡単ではありません。私は、このようなステートメントを IBM i ナビゲーターにコピーし、Visual Explain を使用して、オプティマイザーが行っている決定を把握しようとする傾向があります。これを行う別の方法は、STRDBG を実行してジョブ ログを調べることです。STRDBG が有効な場合、オプティマイザは通知メッセージをジョブ ログに書き込みます。しかし、それでも、パズルを解くのは難しいでしょう。

この場合、数値列は 1 つだけorapdtです。その列なしでクエリを試して、それが原因かどうかを確認してください。

于 2013-05-15T19:47:38.473 に答える
1

orapdt からエラーが発生すると仮定すると、新しい変数を作成するか、null またはガベージ値を他の数値 (null = 9999999、非数値 = 8888888 など) に置き換えることで監視できます。

SELECT case when orapdt is null 
               then 9999999
            when TRANSLATE(SUBSTR(orapdt,1,LENGTH(orapdt)-1),' ','0123456789',' ') <>' '
               then 8888888
            else orapdt 
       end
       , oraptm,

またはstrsqlをチェックするか、問題のあるレコードについてSQLスクリプトを実行します

SELECT orapdt, oraptm, orodr#,
 ...
WHERE ( orapdt is null or TRANSLATE(SUBSTR(orapdt,1,LENGTH(orapdt)-1),' ','0123456789',' ') <>' ' ) AND
orstat != 'C' AND 
......
于 2013-05-16T03:31:16.603 に答える
1

何が問題と思われます...

質問に投稿したコードはプログラム A にあります。プログラム A は (CALLP 経由で) プログラム B を呼び出します。

S1プログラム A は、組み込み SQL を使用して、 という準備済みステートメントと というスクロール可能カーソルを宣言していますC1S1プログラム B は、たまたま、 というプリペアド ステートメントと というスクロール可能カーソルを宣言していますC1

発生しているように見えるのは、カーソルが同じ名前を持っているため、互いに干渉していることです。私の考えでは、プログラム B で実行されているクエリは、それ自体では有効なデータをフェッチしていますが、プログラム A で定義されたクエリでは無効です。そのため、プログラム A がそのクエリの結果をスクロールし、プログラム B を呼び出すと、プログラムによって実行されたクエリが呼び出されます。 B は、プログラム A に関連付けられたフィールドに無効な値を入力しようとします。これは、両方のプログラムでカーソル名が同じ場合にのみ発生します。

私がしたことは、両方のプログラムでカーソルに一意の名前を付けるだけで(たとえば、および)、エラーが発生しなくなりましたPGMA_C1PGMB_C1カーソル名だけで、他に何も変更されていません。これは、私がここで見つけた情報に反します ( http://pic.dhe.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzala/rzalaccl.htm )

カーソルの有効範囲: cursor-name の有効範囲は、それが定義されているソース プログラムです。つまり、プリコンパイラにサブミットされたプログラムです。したがって、カーソルは、カーソル宣言でプリコンパイルされたステートメントによってのみ参照できます。たとえば、別個にコンパイルされた別のプログラムから呼び出されたプログラムは、呼び出し元のプログラムによって開かれたカーソルを使用できません。

もちろん、そのステートメントは次のステートメントと矛盾しているように見えます。

カーソルは、CRTSQLxxx コマンドで CLOSQLCSR(*ENDJOB)、CLOSQLCSR(*ENDSQL)、または CLOSQLCSR(*ENDACTGRP) が指定されていない限り、プログラム・スタック内のプログラムの同じインスタンスでのみ参照できます。

  • CLOSQLCSR(*ENDJOB) が指定されている場合、プログラム・スタック上のプログラムの任意のインスタンスがカーソルを参照できます。
  • CLOSQLCSR(*ENDSQL) が指定されている場合、カーソルは、プログラム・スタック上の最後の SQL プログラムが終了するまで、プログラム・スタック上のプログラムの任意のインスタンスによって参照できます。
  • CLOSQLCSR(*ENDACTGRP) が指定されている場合、カーソルは、活動化グループが終了するまで、活動化グループ内のモジュールのすべてのインスタンスによって参照できます。

しかし、私たちの場合、プログラム A と B の両方が持っているCLOSQLCSR(*ENDMOD)ので、2 つのカーソルはお互いを認識しないはずです。

残念ながら、これ以上深く掘り下げる時間はありません。各プログラムに一意のカーソル名を付けるだけで問題が解決することを確認しました。

一意のカーソル名を使用すると問題が解決することがわかる前に、すべてのデータを包括的にテストしました。これら 2 つのプログラムで使用されるすべてのファイルのすべてのレコードのすべてのフィールドには、有効なデータが含まれています。エラーメッセージに基づいて、NULLまたはその他の無効な文字がどこかにあると予想していましたが、そうではありませんでした。

返信と提案に感謝します。+1 :-)

于 2013-05-31T21:44:59.273 に答える
1

ORAPDT は唯一の数値列であるため、問題はそこにあるはずです。

問題は、DDS 定義ファイルの動作にあります。DDS 定義ファイルへの書き込み時に値の有効性がチェックされないため、1 つ以上のレコードの ORAPDT に数値以外のデータがあるように見えます。SQL はこれを好まず、エラーをスローします。

SQL (DDL) で定義されたテーブルでは、値が書き込まれる前に値が検証されるため、データベースの整合性がより適切に保護されます。

問題を解決するには、問題のあるレコードを見つけて修正するか削除します。

于 2013-05-16T01:24:50.450 に答える