ASK TOM_Oracle : [멋져부러~]
9i:
SELECT deptno, CURSOR(SELECT * FROM emp where deptno=dept.deptno) nested_TABLE
FROM dept;
-- User defined agregate through pipelined function
CREATE or replace FUNCTION CONCAT_LIST( cur SYS_REFCURSOR )
RETURN VARCHAR2 IS
ret VARCHAR2(32000);
tmp VARCHAR2(4000);
BEGIN
loop
fetch cur into tmp;
exit when cur%NOTFOUND;
ret := ret || ',' || tmp;
end loop;
RETURN ret;
END;
/
SELECT distinct
deptno,
SUBSTR(CONCAT_LIST(CURSOR(
SELECT ename FROM emp ee WHERE e.deptno = ee.deptno
)),1,40) employees
FROM emp e;
Followup November 28, 2001 - 2pm Central time zone:
Or, even better, in 9i -- use a user defined aggregate so you don't have run the concat_list function once per row and then through out the dups (it would be better to write: select deptno, SUBSTR(CONCAT_LIST(CURSOR( SELECT ename FROM emp ee WHERE e.deptno = ee.deptno )),1,40) employees from ( select distinct deptno from emp ); ) But a good general purpose solution is: scott@ORA9I.WORLD> create or replace type StringAggType as object 2 ( 3 theString varchar2(4000), 4 5 static function 6 ODCIAggregateInitialize(sctx IN OUT StringAggType ) 7 return number, 8 9 member function 10 ODCIAggregateIterate(self IN OUT StringAggType , 11 value IN varchar2 ) 12 return number, 13 14 member function 15 ODCIAggregateTerminate(self IN StringAggType, 16 returnValue OUT varchar2, 17 flags IN number) 18 return number, 19 20 member function 21 ODCIAggregateMerge(self IN OUT StringAggType, 22 ctx2 IN StringAggType) 23 return number 24 ); 25 / Type created. scott@ORA9I.WORLD> scott@ORA9I.WORLD> create or replace type body StringAggType 2 is 3 4 static function ODCIAggregateInitialize(sctx IN OUT StringAggType) 5 return number 6 is 7 begin 8 sctx := StringAggType( null ); 9 return ODCIConst.Success; 10 end; 11 12 member function ODCIAggregateIterate(self IN OUT StringAggType, 13 value IN varchar2 ) 14 return number 15 is 16 begin 17 self.theString := self.theString || ',' || value; 18 return ODCIConst.Success; 19 end; 20 21 member function ODCIAggregateTerminate(self IN StringAggType, 22 returnValue OUT varchar2, 23 flags IN number) 24 return number 25 is 26 begin 27 returnValue := rtrim( ltrim( self.theString, ',' ), ',' ); 28 return ODCIConst.Success; 29 end; 30 31 member function ODCIAggregateMerge(self IN OUT StringAggType, 32 ctx2 IN StringAggType) 33 return number 34 is 35 begin 36 self.theString := self.theString || ',' || ctx2.theString; 37 return ODCIConst.Success; 38 end; 39 40 41 end; 42 / Type body created. scott@ORA9I.WORLD> scott@ORA9I.WORLD> CREATE or replace 2 FUNCTION stringAgg(input varchar2 ) 3 RETURN varchar2 4 PARALLEL_ENABLE AGGREGATE USING StringAggType; 5 / Function created. scott@ORA9I.WORLD> scott@ORA9I.WORLD> column enames format a30 scott@ORA9I.WORLD> select deptno, stringAgg(ename) enames 2 from emp 3 group by deptno 4 / DEPTNO ENAMES ---------- ------------------------------ 10 CLARK,KING,MILLER 20 SMITH,FORD,ADAMS,SCOTT,JONES 30 ALLEN,BLAKE,MARTIN,TURNER,JAME S,WARD scott@ORA9I.WORLD>