20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
3 rows selected.
1.5 Generic Function usingRef Cursor
An alternative approach is to write a function to concatenateva lues passed using a ref cursor. This is essentially the same as the previousexample, except that the cursor is passed in making it generic, as shown below.
使用游标变量的通用型函数。游标变量作为函数入参。这个方法类似上面方法,只不过是使用游标变量而已。
CREATE OR REPLACE FUNCTION concatenate_list (p_cursor IN SYS_REFCURSOR)
RETURN VARCHAR2
IS
l_return VARCHAR2(32767);
l_temp VARCHAR2(32767);
BEGIN
LOOP
FETCH p_cursor
INTO l_temp;
EXIT WHEN p_cursor%NOTFOUND;
l_return := l_return || ',' || l_temp;
END LOOP;
RETURN LTRIM(l_return, ',');
END;
/
SHOW ERRORS
The CURSOR function is used to allow a query to be passed to thefunction as a ref cursor, as shown below. 这样就允许查询语句作为游标变量参数传递。
COLUMN employees FORMAT A50
SELECT e1.deptno,
concatenate_list(CURSOR(SELECT e2.ename FROM emp e2 WHERE e2.deptno = e1.deptno)) employees
FROM emp e1
GROUP BY e1.deptno;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
3 rows selected.
Once again, the total number of function calls can be reduced byfiltering the distinct values, rather than calling the function for each row.
同样,为了减少函数调用次数,我们提前进行重复值过滤。
COLUMN employees FORMAT A50
SELECT deptno,
concatenate_list(CURSOR(SELECT e2.ename FROM emp e2 WHERE e2.deptno = e1.deptno)) employees
FROM (SELECT DISTINCT deptno
FROM emp) e1;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
3 rows selected.
1.6 ROW_NUMBER() andSYS_CONNECT_BY_PATH functions in Oracle 9i
An example on williamrobertson.net uses the ROW_NUMBER() and SYS_CONNECT_BY_PATH functionsto achieve the same result without the use of PL/SQL or additional typedefinitions.
另外一个例子使用ROW_NUMBER()函数和SYS_CONNECT_BY_PATH层次查询函数实现。
SELECT deptno,
LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees
FROM (SELECT deptno,
ename,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr,
ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev
FROM emp)
GROUP BY deptno
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno
START WITH curr = 1;
DEPTNO EMPLOYEES
---------- --------------------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
3 rows selected.
1.7 COLLECT function inOracle 10g
An example on oracle-developer.net uses the COLLECT functionin Oracle 10g to get the same result. This method requires a table type and afunction to convert the contents of the table type to a string. I've alteredhis method slightly to bring it in line with this article.
最后这个例子使用Oracle10g引入的COLLECT函数。使用这个方法要求先定义一个表类型和一个用于将表类型转换为字符串的函数。
CREATE OR REPLACE TYPE t_varchar2_tab AS TABLE OF VARCHAR2(4000);
/
CREATE OR REPLACE FUNCTION tab_to_string (p_varchar2_tab IN t_varchar2_tab,
p_delimiter IN VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
l_strin