无法在Oracle查询中运行DDL语句

时间:2018-10-31 18:03:40

标签: oracle plsql ddl

我需要为查询提取一系列不同格式的源名称。我编写了一个函数来执行此操作,但是它返回所需的数据,因为它会被截断并写入表中,因此无法在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 :(得分:3)

这是一个纯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为listagg()子句提供了ON FORFLOW TRUNCATE,但是几乎没有人使用12cR2。 Stew Ashton对于较早版本具有解决方法。 Check it out.

答案 1 :(得分:1)

如果Wernfried的解决方案不起作用,我只想指出,您可以进行简单的格式化,而无需使用临时表。我不想弄乱您的格式,所以我保留了第二个循环,但是通常我也只使用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;
/

答案 2 :(得分:0)

这两个命令不必是动态的:

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。我不确定,但是随后它应该可以工作(我没有测试)。