在SQLRPGLE中的OPEN游标上的SQL -302

时间:2013-05-15 17:18:18

标签: db2 ibm-midrange rpgle

问题

我有一个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

错误状态/代码表示"A parameter or variable value is invalid."

我尝试了什么......

经过多次谷歌搜索后,我尝试过:

  1. 删除ORDER BY子句(在OPEN上,获取数据和 在有ORDER BY子句时订购)
  2. 将所有LEFT JOIN更改为INNER JOIN(这样做是为了确保没有NULL) 在右侧的结果记录中)
  3. 将“AND orapdt IS NOT NULL”添加到WHERE子句
  4. 我忘记的更多事情
  5. 我在问什么......

    如何找出哪个字段中包含错误数据?我知道HVR0001无效,但哪个字段由HVR0001表示?我尝试以不同的顺序选择字段,但它总是HVR0001具有无效值。

    理想情况下,我希望能够打印出所有HVR *字段/值,以便我可以检查它们。

    当我查看编译列表时,没有列出HVR *字段。列出了一些SQL_ *字段,我可以看到SQL_00011用于临时保存放入orapdt的数据。 SQL_00011的定义与orapdt(7,0打包)完全相同。这是我查询中唯一的数字字段......

    我觉得我的问题是由文件加入的方式引起的,不知何故,我的orapdt字段中放置了一个无效值(可能是NULL)。

    我还认为我的问题与一个接一个地执行这些查询(每个查询的一些WHERE细节更改)有关,因为我可以将其中一个查询失败并将其放入自己的程序中并运行它,它工作正常。

    这是在DB2 for i(V6R1)上,所有涉及的文件都是使用DDS创建的

    修改的: 这是LIKE语句所需的主机变量(数据结构)和两个外部数据结构:

    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;
    

    我之前没有包含这个,只是因为当我打开游标时发生错误,而不是FETCHing一行。 OPEN语句不应该知道有关o数据结构的任何信息。

    至于WHERE子句中的更改 - 所有这些都是动态构建的(因此可以更改),而不是:

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

4 个答案:

答案 0 :(得分:2)

找出实际错误并不容易。我倾向于将这些语句复制到IBM i Navigator中,并使用Visual Explain来尝试掌握优化器正在做出的决策。另一种方法是执行STRDBG并查看作业日志。当STRDBG生效时,优化器会将信息性消息放入作业日志中。但即便如此,也很难解开。

在这种情况下,只有一个数字列orapdt。尝试不带该列的查询,看看是否是罪魁祸首。

答案 1 :(得分:1)

由于ORAPDT是您唯一的数字列,因此问题必定存在于此。

问题在于DDS定义文件的工作方式。在写入DDS定义文件时,不会检查值的有效性,因此在一个或多个记录中,ORAPDT中显示非数字数据。 SQL不喜欢这样,并抛出错误。

SQL(DDL)定义的表在写入之前验证这些值,从而更好地保护数据库的完整性。

要解决您的问题,请找到有问题的记录并修复或删除它们。

答案 2 :(得分:1)

假设错误来自orapdt,您可以通过创建新的varible或用其他数字替换null或garbage值来监视它。 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 
......

答案 3 :(得分:1)

似乎是什么问题......

我在问题中发布的代码在程序A中。程序A调用(通过CALLP)程序B.没有什么不寻常的。

程序A使用嵌入式SQL声明名为S1的预准备语句和名为C1的可滚动游标。程序B也恰好声明一个名为S1的预准备语句和一个名为C1的可滚动游标。

似乎正在发生的事情是光标互相干扰,因为它们具有相同的名称。我相信在程序B中执行的查询正在获取对自身有效的数据 - 但对于程序A中定义的查询无效。因此,当程序A滚动查询结果并调用程序B时,程序执行查询B尝试在与程序A关联的字段中放置无效值 - 这仅在两个程序中的游标名称相同时才会发生。

我所做的就是给两个程序中的游标提供唯一的名称(例如PGMA_C1PGMB_C1)并且错误停止发生。没有其他改变,只有光标名称。这违反了我在此处找到的信息(http://pic.dhe.ibm.com/infocenter/iseries/v6r1m0/index.jsp?topic=/rzala/rzalaccl.htm

“游标的范围:游标名称的范围是定义它的源程序;也就是说,程序提交给预编译器。因此,游标只能由使用游标声明预编译的语句引用。例如,从另一个单独编译的程序调用的程序不能使用由调用程序打开的游标。“

当然,这句话似乎与这一说法相矛盾:

  

只能在程序的同一个实例中引用游标   在程序堆栈中,除非CLOSQLCSR(* ENDJOB),CLOSQLCSR(* ENDSQL),或   CLOSQLCSR(* ENDACTGRP)在CRTSQLxxx命令中指定。

     
      
  • 如果指定了CLOSQLCSR(* ENDJOB),则程序堆栈上的任何程序实例都可以引用游标。
  •   
  • 如果指定了CLOSQLCSR(* ENDSQL),则程序堆栈上的任何程序实例都可以引用游标,直到最后一个   程序堆栈上的SQL程序结束。
  •   
  • 如果指定了CLOSQLCSR(* ENDACTGRP),则激活组中的所有模块实例都可以引用游标,直到   激活小组结束。
  •   

但是在我们的例子中,程序A和B都有CLOSQLCSR(*ENDMOD) - 因此两个游标不应该彼此了解。

不幸的是,我没有时间深入研究这个问题。我已经确认,简单地给每个程序一个唯一的游标名称可以解决我们的问题。

在我发现使用唯一游标名称解决我们的问题之前,我对所有数据进行了全面测试。这两个程序使用的每个文件中的每个记录中的每个字段都包含有效数据。根据错误消息,我希望某处有一个NULL或其他一些无效字符,但事实并非如此。

感谢您的回复和建议,+1周围: - )