Не удается выполнить оператор DDL в запросе Oracle - PullRequest
0 голосов
/ 31 октября 2018

Мне нужно получить список различных отформатированных имен источников для запроса. Я написал функцию для этого, и она возвращает нужные мне данные, однако, потому что она усекает и записывает в таблицу, которую нельзя использовать в запросе в Oracle. Так что я озадачен тем, как заставить это работать в запросе. Вот код.

FUNCTION GET_POD_SOURCE_FROM_APP_NO
     (I_APPL_ID_SEQ IN WRD_APPLICATIONS.APPL_ID_SEQ%TYPE,
      I_DELIMITER IN VARCHAR2 DEFAULT ';')

   RETURN VARCHAR2
   IS

   CURSOR C1 IS
    SELECT DISTINCT SOUR.SOUR_ID_SEQ,
           SRNM.SRNM_NM,
           SOUR.FORK_NM,
           DECODE(POD.UNNAMED_TRIBUTARY,
                  'N',
                  NULL,
                  'Y',
                  'UNNAMED TRIBUTARY') POD_UT,
           MRTP.DESCR POD_MINORTYPE,
           DECODE(POD.MAJOR_TYPE,
                  'S',
                  'SURFACE WATER',
                  'G',
                  'GROUNDWATER',
                  NULL,
                  NULL) POD_MAJORTYPE
      FROM WRD_SOURCES             SOUR,
           WRD_SOURCE_NAMES        SRNM,
           WRD_POINT_OF_DIVERSIONS POD,
           WRD_MINOR_TYPES         MRTP,
           WRD_VERSION_APPLICATION_XREFS VAX
     WHERE SOUR.SOUR_ID_SEQ = POD.SOUR_ID_SEQ
       AND SOUR.SRNM_ID_SEQ = SRNM.SRNM_ID_SEQ
       AND POD.MRTP_CD = MRTP.MRTP_CD(+)
       AND POD.WRGT_ID_SEQ = VAX.WRGT_ID_SEQ
       AND POD.VERS_ID_SEQ = VAX.VERS_ID_SEQ
       AND VAX.APPL_ID_SEQ = I_APPL_ID_SEQ;


   CURSOR C2 IS
    SELECT DISTINCT TS.SOURCE_FULL
    FROM WRD.TEMP_SOURCE TS
    ORDER BY TS.SOURCE_FULL;



  C1_R    C1%ROWTYPE;
  C2_R    C2%ROWTYPE;
  ROW_CNT PLS_INTEGER := 0;
  RTN_VAL VARCHAR2(4000);
  SRC_NAME VARCHAR2(400);

BEGIN

  EXECUTE IMMEDIATE 'TRUNCATE TABLE TEMP_SOURCE';

  FOR C1_R IN C1 LOOP

    IF C1_R.POD_UT IS NOT NULL THEN
      SRC_NAME := C1_R.POD_UT || ' OF ';
    END IF;

    SRC_NAME := SRC_NAME || C1_R.SRNM_NM;

    IF C1_R.FORK_NM IS NOT NULL THEN
      SRC_NAME := SRC_NAME ||', '|| C1_R.FORK_NM;
    END IF;

    IF C1_R.POD_MINORTYPE IS NOT NULL THEN
      SRC_NAME := C1_R.POD_MINORTYPE || ', ' || SRC_NAME;
    END IF;

    EXECUTE IMMEDIATE 'INSERT INTO WRD.TEMP_SOURCE VALUES (SRC_NAME)';
    EXECUTE IMMEDIATE 'COMMIT';

    SRC_NAME := '';
  END LOOP;


  FOR C2_R IN C2 LOOP
    ROW_CNT := ROW_CNT + 1;

    IF (ROW_CNT < 2) THEN
      RTN_VAL := C2_R.SOURCE_FULL;
    ELSE
      RTN_VAL := SUBSTR(RTN_VAL, 1, 3600) || I_DELIMITER || ' ' || C2_R.SOURCE_FULL;
    END IF;
  END LOOP;

  RETURN(TRIM(RTN_VAL));

END GET_POD_SOURCE_FROM_APP_NO;

Спасибо.

Ответы [ 3 ]

0 голосов
/ 31 октября 2018

Если решение Вернфрида не работает, я просто хотел бы отметить, что вы можете сделать такое простое форматирование, не прибегая к временной таблице. Я не хотел связываться с вашим форматированием, поэтому я оставил ваш второй цикл на месте, но обычно я бы просто использовал LISTAGG для этого и вообще не использовал PLSQL для этого.

FUNCTION GET_POD_SOURCE_FROM_APP_NO
     (I_APPL_ID_SEQ IN WRD_APPLICATIONS.APPL_ID_SEQ%TYPE,
      I_DELIMITER IN VARCHAR2 DEFAULT ';')

   RETURN VARCHAR2
   IS

   CURSOR C1 IS
    SELECT 
        CASE WHEN POD_MINORTYPE is not null 
            THEN POD_MINORTYPE || ', ' 
            ELSE NULL END 
        || CASE WHEN POD_UT is not null 
            THEN POD_UT || ' OF ' 
            ELSE NULL END 
        || SRNM_NM
        || CASE WHEN FORK_NM is not null 
            THEN ', '|| FORK_NM
            ELSE NULL END 
        AS SOURCE_FULL
    FROM (
    SELECT DISTINCT SOUR.SOUR_ID_SEQ,
               SRNM.SRNM_NM,
               SOUR.FORK_NM,
               DECODE(POD.UNNAMED_TRIBUTARY,
                      'N',
                      NULL,
                      'Y',
                      'UNNAMED TRIBUTARY') POD_UT,
               MRTP.DESCR POD_MINORTYPE,
               DECODE(POD.MAJOR_TYPE,
                      'S',
                      'SURFACE WATER',
                      'G',
                      'GROUNDWATER',
                      NULL,
                      NULL) POD_MAJORTYPE
          FROM WRD_SOURCES             SOUR,
               WRD_SOURCE_NAMES        SRNM,
               WRD_POINT_OF_DIVERSIONS POD,
               WRD_MINOR_TYPES         MRTP,
               WRD_VERSION_APPLICATION_XREFS VAX
         WHERE SOUR.SOUR_ID_SEQ = POD.SOUR_ID_SEQ
           AND SOUR.SRNM_ID_SEQ = SRNM.SRNM_ID_SEQ
           AND POD.MRTP_CD = MRTP.MRTP_CD(+)
           AND POD.WRGT_ID_SEQ = VAX.WRGT_ID_SEQ
           AND POD.VERS_ID_SEQ = VAX.VERS_ID_SEQ
           AND VAX.APPL_ID_SEQ = I_APPL_ID_SEQ
    ) TS;

  C1_R    C1%ROWTYPE;
  ROW_CNT PLS_INTEGER := 0;
  RTN_VAL VARCHAR2(4000);
  SRC_NAME VARCHAR2(400);

BEGIN

  FOR C1_R IN C1 LOOP
    ROW_CNT := ROW_CNT + 1;

    IF (ROW_CNT < 2) THEN
      RTN_VAL := C1_R.SOURCE_FULL;
    ELSE
      RTN_VAL := SUBSTR(RTN_VAL, 1, 3600) || I_DELIMITER || ' ' || C1_R.SOURCE_FULL;
    END IF;
  END LOOP;

  RETURN(TRIM(RTN_VAL));

END GET_POD_SOURCE_FROM_APP_NO;
/
0 голосов
/ 31 октября 2018

Вот версия на чистом SQL, которая устраняет необходимость во временных таблицах и ненужных DDL.

with C1_R as ( 
   SELECT DISTINCT SOUR.SOUR_ID_SEQ,
           SRNM.SRNM_NM,
           SOUR.FORK_NM,
           DECODE(POD.UNNAMED_TRIBUTARY,
                  'N',
                  NULL,
                  'Y',
                  'UNNAMED TRIBUTARY') POD_UT,
           MRTP.DESCR POD_MINORTYPE,
           DECODE(POD.MAJOR_TYPE,
                  'S',
                  'SURFACE WATER',
                  'G',
                  'GROUNDWATER',
                  NULL,
                  NULL) POD_MAJORTYPE
      FROM WRD_SOURCES             SOUR,
           WRD_SOURCE_NAMES        SRNM,
           WRD_POINT_OF_DIVERSIONS POD,
           WRD_MINOR_TYPES         MRTP,
           WRD_VERSION_APPLICATION_XREFS VAX
     WHERE SOUR.SOUR_ID_SEQ = POD.SOUR_ID_SEQ
       AND SOUR.SRNM_ID_SEQ = SRNM.SRNM_ID_SEQ
       AND POD.MRTP_CD = MRTP.MRTP_CD(+)
       AND POD.WRGT_ID_SEQ = VAX.WRGT_ID_SEQ
       AND POD.VERS_ID_SEQ = VAX.VERS_ID_SEQ
       AND VAX.APPL_ID_SEQ = I_APPL_ID_SEQ;
 ) , fmt as (
 select  distinct  nvl2(C1_R.POD_MINORTYPE, C1_R.POD_MINORTYPE || ', ', null)
            || nvl2(C1_R.POD_UT  C1_R.POD_UT || ' OF ', null)
            || C1_R.SRNM_NM
            || nvl2(C1_R.FORK_NM IS, ', '|| C1_R.FORK_NM, null)
           as SRC_NAME;
from C1_R
)
select listagg(src_name, '|') within group (order by source_name) as rtn_val
from fmt
/

Единственное, что это не делает, - это обрабатывает сцепленные строки, превышающие ограничение в 4000 символов. В 12cR2 Oracle дал нам ON OVERFLOW TRUNCATE для предложения listagg(), но вряд ли кто-то еще находится на 12cR2; У Stew Ashton есть обходной путь для более ранних версий. Проверьте это.

0 голосов
/ 31 октября 2018

Эти две команды не должны быть динамическими:

EXECUTE IMMEDIATE 'INSERT INTO WRD.TEMP_SOURCE VALUES (SRC_NAME)';
EXECUTE IMMEDIATE 'COMMIT';

Просто беги INSERT INTO WRD.TEMP_SOURCE VALUES (SRC_NAME);

Я думаю, что главная проблема - ваши TRUNCATE ... и COMMIT. Обе команды завершают транзакцию, это не разрешено в запросе. Я предполагаю, что таблица TEMP_SOURCE является GLOBAL TEMPORARY таблицей.

Измените TRUNCATE на DELETE FROM WRD.TEMP_SOURCE; и удалите COMMIT. Я не уверен, но тогда это должно работать (я не проверял).

...