2017-03-01 170 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個數字,但由於第二次運行尚未完成,現在它使用錯誤的數字。 或者您是否建議爲每次運行創建並使用不同的表格? –