我需要为查询提取一系列不同格式的源名称。我编写了一个函数来执行此操作,但是它返回所需的数据,因为它会被截断并写入表中,因此无法在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;
谢谢。
答案 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
。我不确定,但是随后它应该可以工作(我没有测试)。