Курсор COBOL Использование оператора IN в предложении WHERE

У меня есть проблема, которую я не могу понять, и мне интересно, является ли это ограничением в среде или чем-то простым, о чем я не подумал.

Я работаю в AIX, используя Microfocus Cobol со встроенным Oracle SQL в программе.

Сегодня этот SQL работает со всей таблицей для производственных запусков, как и было задумано. При запуске этой же программы для системы производственного тестирования нам не нужно возвращать полный набор результатов... нам нужны только записи, возвращаемые для клиента (клиентов) в этом запуске производственного тестирования.

Таким образом, достаточно просто добавить оператор в SQL, чтобы ограничить его следующим образом:

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

Это прекрасно работает, если я могу получить значение (я) в запросе.

Проблема в том, что мы никогда не знаем, сколько из этих 4-значных клиентских значений будет в каждом прогоне. Может быть один, может быть 30 из них. Мы никогда не узнаем, пока не начнем каждый производственный тестовый запуск.

Мое решение состояло в том, чтобы создать файл этих чисел в сценарии AIX Korn Shell, передать их в модуль COBOL, ПРИНЯВ их через переменную ENVIRONMENT-NAME, отформатировав их внутри программы, а затем используя это отформатированное поле в SQL как такой:

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

Однако я не могу заставить SQL распознавать CLIENT NO в этом запросе!

Пример:

Сценарий оболочки 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'

Который находится в поле 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» и вместо этого использую одно значение, он будет получать результаты.
  • Если я жестко закодирую его, чтобы объединить множество операторов «ИЛИ», он будет работать и получать результаты. Но это непрактично для COBOL.
  • Но если я попытаюсь поместить мою правильно (предположительно) отформатированную строку данных в это предложение «IN», это не сработает!

Любая помощь или трюки будут очень признательны! Даже если это невозможно!

отметка


person Mark Ludlow    schedule 01.03.2017    source источник
comment
Не так много знаний о коболе, но sql: ваш список может выглядеть так (чтобы показать свою точку зрения, я сократил список)....... где поле в (8220,8396,8529) или ...... , где поле в ('8220', '8396', '8529'), но никогда: ....... где поле в ('8220,8396,8529') предложение in должно быть отформатировано правильно. И afaik в списке ограничен 1000 элементами. так что будьте осторожны, если у вас есть больше, используйте соединение.   -  person nabuchodonossor    schedule 02.03.2017
comment
Я бы подумал, что вам нужно будет закодировать его как HIT.SYS_TX IN (:WS-CLIENT-NO1, :WS-CLIENT-NO2, ..... :WS-CLIENT-NO*), в настоящее время вы спрашиваете, HIT.SYS_TX = :WS-CLIENT-NOS. Загрузка временной таблицы, такой как Bobc, должна работать. Не могу комментировать ответ Гордона   -  person Bruce Martin    schedule 02.03.2017


Ответы (2)


На мой взгляд, лучший подход - создать таблицу, в которую можно поместить ваши 4-значные числа, а затем просто выполнить соединение с этой таблицей. Скорее всего, это будет проще и эффективнее, поскольку у оптимизатора будет хороший шанс получить правильную кардинальность. Есть несколько способов реализовать это

  1. Используйте глобальную временную таблицу (GTT); данные являются частными для сеанса.
  2. Таблица имеет идентификатор (например, "сеанс"), который является частью ключа соединения.
person BobC    schedule 01.03.2017
comment
Хотя это выглядит красиво, это, скорее всего, невозможно — если вы выполняете несколько производственных циклов одновременно, этот метод вам не поможет. - person Simon Sobisch; 02.03.2017
comment
@SimonSobisch Можете ли вы уточнить, почему? - person BobC; 02.03.2017
comment
Если вы не создадите таблицу, специфичную для каждого прогона, тогда несколько прогонов будут использовать/смешивать свои 4-значные числа: 1-й прогон записывает три числа, начинается; 2-й запуск записывает 512 номеров; начинается; 3-й запуск записывает 5 чисел, но, поскольку 2-й запуск еще не завершен, теперь он использует неправильные числа. Или вы предлагаете создавать и использовать разные таблицы для каждого запуска? - person Simon Sobisch; 03.03.2017
comment
@SimonSobisch Есть два простых подхода. 1. Используйте глобальную временную таблицу (GTT); данные являются частными для сеанса. 2. Таблица имеет идентификатор (например, сеанса), который является частью ключа соединения. Вы могли использовать разные таблицы для каждого запуска, но это становится беспорядочным, так как теперь вам нужно называть каждую таблицу по-разному. - person BobC; 03.03.2017
comment
правильно - предлагаю добавить это в ответ через Edit :-) - person Simon Sobisch; 03.03.2017
comment
@SimonSobisch Готово. Спасибо - person BobC; 03.03.2017

Проблема в том, что это утверждение:

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

действительно эквивалентно:

HIT.SYS_TX = :WS-CLIENT-NOS

Вместо этого вы можете использовать like или регулярные выражения:

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

or

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

На самом деле существуют и другие методы преобразования списка в какую-то таблицу. Однако приведенные выше методы включают изменение только одной строки кода.

person Gordon Linoff    schedule 01.03.2017