【问题标题】:COBOL cursor Using IN operator in the WHERE clauseCOBOL 游标 在 WHERE 子句中使用 IN 运算符
【发布时间】:2017-03-01 18:39:44
【问题描述】:

我有一个我似乎无法弄清楚的问题,想知道这是环境的限制,还是我没有想到的简单问题。

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

今天,此 SQL 正在针对整个表运行,以按设计进行生产运行。当为生产测试系统运行相同的程序时,我们不需要返回完整的结果集......我们只需要在该生产测试运行中为客户端返回的记录。

所以很容易在 SQL 中添加一条语句来限制它,如下所示:

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

如果我可以将值放入查询中,那就很好了。

问题是我们永远不知道每次运行中这些 4 位数的客户值中有多少。可以是一个,也可以是30个。在我们开始每次生产测试运行之前,我们永远不会知道。

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

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

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

例子:

Korn Shell 脚本准备一个包含以下内容的字段:

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'

位于 WORKING STORAGE 字段 - 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,'0123456789',' ')),
               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 (' ') 结构中,那么我会得到 结果,所以我的结构和格式很好。
  • 如果我将“”标记硬编码到光标而不是 工作存储字段我没有得到任何结果。
  • 如果我将 ( ) 放在工作存储字段中而不是硬编码到 SQL 则无法编译。
  • 如果我将关系运算符更改为“=”而不是“IN”并使用 相反,它会拉取结果。
  • 如果我对其进行硬编码以连接许多“OR”语句,它将起作用 并拉出结果。但这对 COBOL 来说并不实用。
  • 但是,如果我尝试将我正确(据称)格式化的数据行 进入那个“IN”子句是行不通的!

任何帮助或技巧将不胜感激!即使这是做不到的事情!

标记

【问题讨论】:

  • 关于 cobol 的知识不多,但是 sql:你的 in 列表可能看起来像(为了表明我的观点,我减少了列表)....... where field in (8220,8396,8529 ) 或 ....... where field in ( '8220', '8396', '8529' ) but never: ....... where field in ( '8220,8396,8529' ) in 子句必须格式正确。而且 afaik in 列表仅限于 1000 个元素。所以要小心,如果你有更多,请使用连接。
  • 我认为您需要将其编码为HIT.SYS_TX IN (:WS-CLIENT-NO1, :WS-CLIENT-NO2, ..... :WS-CLIENT-NO*),目前您正在询问是否为HIT.SYS_TX = :WS-CLIENT-NOS。加载像 Bobc 这样的临时表应该可以工作。无法评论戈登的回答

标签: sql oracle cobol where-in


【解决方案1】:

在我看来,最好的方法是创建一个表格来放入您的 4 位数字,然后简单地加入该表格。它可能更容易且性能更好,因为优化器将有机会获得正确的基数。 有几种方法可以实现这一点

  1. 使用全局临时表 (GTT);数据是会话私有的。
  2. 该表有一个(例如“会话”)标识符,它是连接键的一部分。

【讨论】:

  • 虽然这看起来不错,但它可能是不可能的 - 如果您同时进行多个生产运行,此技术将无济于事。
  • @SimonSobisch 你能详细说明原因吗?
  • 如果您没有为每次运行创建一个特定的表格,那么多次运行将使用/混合它们的 4 位数字:第一次运行写入三个数字,开始;第二次运行写入 512 个数字;开始;第 3 次运行写入 5 个数字,但由于第 2 次运行尚未完成,它现在使用了错误的数字。或者您是否建议为每次运行创建和使用不同的表?
  • @SimonSobisch 有两种简单的方法。 1.使用全局临时表(GTT);数据是会话私有的。 2. 表有一个(例如“会话”)标识符,它是连接键的一部分。您可以为每次运行使用不同的表,但这会变得很混乱,因为您现在必须以不同的方式命名每个表
  • 正确 - 我建议通过编辑将此添加到答案中:-)
【解决方案2】:

问题是这样的说法:

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, ',', '|') || '$')

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

【讨论】:

    猜你喜欢
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多