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. SQL_00011定义与orapdt(7,0 packed) 完全相同。这是我查询中唯一的数字字段...

我觉得我的问题是由文件的连接方式引起的,以某种方式将无效值(可能为 NULL)放入我的orapdt字段中。

我还认为我的问题与一个接一个地执行许多这些查询有关(每个查询的某些 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;

我之前没有包含这个只是因为当我打开游标而不是获取一行时发生错误。oOPEN 语句不应该对数据结构有任何了解。

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

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

4 回答 4

2

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

在这种情况下,只有一个数字列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

由于 ORAPDT 是您唯一的数字列,所以问题一定出在那儿。

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

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

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

于 2013-05-16T01:24:50.450 回答
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

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

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

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

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

但在我们的例子中,程序 A 和 B 都有CLOSQLCSR(*ENDMOD)- 所以两个游标不应该相互感知。

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

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

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

于 2013-05-31T21:44:59.273 回答