2017-03-01 164 views
0

我有一个问题,我似乎无法弄清楚并怀疑它是环境中的限制,还是我没有想到的简单的东西。COBOL游标在WHERE子句中使用IN运算符

我在AIX中运行,在程序中使用Microfocus Cobol和嵌入式Oracle SQL。

今天,这个SQL针对整个生产运行表运行,这是按照设计的。当为生产测试系统运行同一个程序时,我们不需要返回一整套结果......我们只需要在生产测试运行中为客户返回的记录。

所以这是很容易的添加语句转换成SQL来限制它像如下:

AND OLM.SYS_TX IN ('8220,8245,8993') 

这工作就好了,如果我能得到的值(一个或多个)进入查询。

问题是我们永远不知道这些4位数的客户端值将在每次运行中有多少。可能是一个,可能是其中的一个。直到我们开始每个生产测试运行,我们才会知道。

我的解决方案是在这些数字的AIX Korn Shell脚本中创建一个文件,将它们传递到COBOL模块中,方法是通过一个ENVIRONMENT-NAME变量接受它们,在程序中格式化它们,然后使用格式化的字段在SQL中是这样的:

AND HIT.SYS_TX IN (:WS-CLIENT-NOS) 

但是,我无法让SQL将SQLENT识别到该查询中!

实施例:

Korn外壳脚本准备了场与它下面的:

8220,8396,8529,8685,8499,8218,8383,8150,8778,8255,8773,8993,8299 

COBOL程序接受此订单,并格式化一个新的在SQL使用。
我已经通过上面的数字圈出了我有多少非空格字符,然后我使用STRING命令来格式化在SQL中使用的新行。因此,格式化后,我有这样的:

'8220,8396,8529,8685,8499,8218,8383,8150,8778,8255,8773,8993,8299' 

驻留在工作存储领域 - WS-CLIENT-NOS

而那场在以下CURSOR使用:

EXEC SQL DECLARE PRETEST_EXT_HIT_LIST_CSR CURSOR FOR 
SELECT HIT.ACCOUNT_NUMBER, 
     HIT.SYS_TX, 
     HIT.PRIN_TX, 
     LPAD(NVL(RANK, 99999),5, 0), 
     NON_OPTIONAL, 
     LPAD(LOC.LOCATION_ID, 10, 0), 
     LPAD (TRIM (ITEM_ID), 10, '0'), 
     TO_CHAR (HIT.START_DT, 'YYYYMMDD'), 
     EXT_CLIENT_HIT_LIST_PK 
    FROM OLM_MSG_MASTER OMM, 
     EXT_CLIENT_HIT_LIST HIT, 
     OLM_LOCATIONS LOC 
    WHERE DECODE(TRIM(TRANSLATE(item_id,'',' ')), 
       NULL, 'number','contains char') = 'number' 
    AND LOC.OLM_LOCATIONS_PK = OMM.OLM_LOCATIONS_FK 
    AND OLM_MSG_MASTER_PK = ITEM_ID 
    AND APPLICATION_ID = 'MMSG' 
    AND HIT.START_DT <= 
      TO_DATE (:HV-PROCESS-DATE, 'MMDDYYYY') 
    AND (HIT.END_DT IS NULL 
     OR HIT.END_DT >= 
      TO_DATE (:HV-PROCESS-DATE, 'MMDDYYYY')) 
    AND HIT.SYS_TX IN (:WS-CLIENT-NOS) <============================ 
ORDER BY HIT.SYS_TX, HIT.PRIN_TX, HIT.ACCOUNT_NUMBER, 
     ITEM_ID 
END-EXEC. 

但查询不会返回任何结果。

  • 如果我将相同的数据硬编码为IN('')结构,那么我得到 结果,所以我的结构和格式都很好。
  • 如果我将''标记硬编码到光标而不是在 工作存储字段中,我不会得到任何结果。
  • 如果我将()放在Working-Storage字段中,而不是硬编码到SQL中,那么它将不会编译。
  • 如果我将关系运算符更改为'='而不是“IN”,并使用单个值而不是它将取得结果。
  • 如果我对它进行硬编码以连接大量的“或”语句,它将工作 并拉取结果。但对于COBOL来说这是不实际的。
  • 但是,如果我尝试将我的正确(据称)格式的数据行 纳入该“IN”条款,它不起作用!

任何帮助或窍门将不胜感激!即使这是无法完成的事情!

马克

+2

没有那么多关于cobol的知识,但sql:你在列表中可能看起来像(显示我的观点,我减少了列表).......其中字段在(8220,8396,8529)或。 ......('8220','8396','8529')中的字段,但从未:.......其中('8220,8396,8529')字段必须格式化正确。并且afaik列表中的限制为1000个元素。所以要小心,如果你有更多,请使用连接。 – nabuchodonossor

+0

我想你会需要像'HIT.SYS_TX IN(:WS-CLIENT-NO1,:WS-CLIENT-NO2,.....:WS-CLIENT-NO *)'编写代码,现在你是询问“HIT.SYS_TX =:WS-CLIENT-NOS”。加载像Bobc这样的临时表应该可行。无法对Gordons发表评论 –

回答

0

的问题是,这样的说法:

HIT.SYS_TX IN (:WS-CLIENT-NOS) 

是真的等同于:

HIT.SYS_TX = :WS-CLIENT-NOS 

相反,你可以使用like或正则表达式:

:WS-CLIENT-NOS '%,' || HIT.SYS_TX || ',%' 

regexp_like(HIT.SYS_TX, '^' || replace(:WS-CLIENT-NOS, ',', '|') || '$') 

实际上还有其他方法将列表转换为某种表格。但是,上述方法仅涉及更改一行代码。

1

在我看来,最好的方法是创建一个表来放入4位数字,然后简单地加入到这张表中。这可能会更容易,更好地执行,因为优化器在获得正确的基数方面会有一个很好的选择。 有几种方法可以执行此操作

  1. 使用全局临时表(GTT);数据是会话专用的。
  2. 该表具有属于连接键的一部分(例如“会话”)标识符。
+0

虽然这看起来不错,但它可能不可能 - 如果您同时进行多次生产运行,此技术对您无能为力。 –

+0

@SimonSobisch你能详细说明原因吗? – BobC

+0

如果您没有为每次运行创建特定的表,那么多次运行将使用/混合它们的4位数字:第1次运行写入三个数字,开始;第二次运行写入512个数字;启动;第三次运行写入5个数字,但由于第二次运行尚未完成,现在它使用错误的数字。 或者您是否建议为每次运行创建并使用不同的表格? –