مقدمه :
یکی از نیازمندی های همیشگی وقت با داده های پایگاه داده کار می کنیم، ساخت رشته ها ( عبارت ها) از تجمیع چند رشته (عبارت ) به عنوان خروجی می باشد. در این مستند در این خصوص صحبت خواهیم کرد و تابع کاربردی LISTAGG را معرفی خواهیم کرد.


به طور مثال مجموعه ای از افراد در دپارتمان های مختلف یک شرکت مشغول به کار هستند و حال مدیر مجموعه در خواست گزارشی دارد که در هر دپارتمان نام افراد در یک خط آورده شوند که در این صورت باید به ازای هر دپارتمان چند رکورد را در یک رکورد تجمیع کرد.

Base Data:

DEPTNO ENAME

———- ———-

20 SMITH

30 ALLEN

30 WARD

20 JONES

30 MARTIN

30 BLAKE

10 CLARK

20 SCOTT

10 KING

30 TURNER

20 ADAMS

30 JAMES

20 FORD

10 MILLER

Desired Output:

DEPTNO EMPLOYEES

———- ————————————————–

10 CLARK,KING,MILLER

20 SMITH,FORD,ADAMS,SCOTT,JONES

30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD

آماده سازی محیط تست :

–DROP TABLE emp PURGE;

CREATE TABLE emp (

empno NUMBER(4) CONSTRAINT pk_emp PRIMARY KEY,

ename VARCHAR2(10),

job VARCHAR2(9),

mgr NUMBER(4),

hiredate DATE,

sal NUMBER(7,2),

comm NUMBER(7,2),

deptno NUMBER(2)

);

INSERT INTO emp VALUES (7369,’SMITH’,’CLERK’,7902,to_date(’17-12-1980′,’dd-mm-yyyy’),800,NULL,20);

INSERT INTO emp VALUES (7499,’ALLEN’,’SALESMAN’,7698,to_date(’20-2-1981′,’dd-mm-yyyy’),1600,300,30);

INSERT INTO emp VALUES (7521,’WARD’,’SALESMAN’,7698,to_date(’22-2-1981′,’dd-mm-yyyy’),1250,500,30);

INSERT INTO emp VALUES (7566,’JONES’,’MANAGER’,7839,to_date(‘2-4-1981′,’dd-mm-yyyy’),2975,NULL,20);

INSERT INTO emp VALUES (7654,’MARTIN’,’SALESMAN’,7698,to_date(’28-9-1981′,’dd-mm-yyyy’),1250,1400,30);

INSERT INTO emp VALUES (7698,’BLAKE’,’MANAGER’,7839,to_date(‘1-5-1981′,’dd-mm-yyyy’),2850,NULL,30);

INSERT INTO emp VALUES (7782,’CLARK’,’MANAGER’,7839,to_date(‘9-6-1981′,’dd-mm-yyyy’),2450,NULL,10);

INSERT INTO emp VALUES (7788,’SCOTT’,’ANALYST’,7566,to_date(’13-JUL-87′,’dd-mm-rr’)-85,3000,NULL,20);

INSERT INTO emp VALUES (7839,’KING’,’PRESIDENT’,NULL,to_date(’17-11-1981′,’dd-mm-yyyy’),5000,NULL,10);

INSERT INTO emp VALUES (7844,’TURNER’,’SALESMAN’,7698,to_date(‘8-9-1981′,’dd-mm-yyyy’),1500,0,30);

INSERT INTO emp VALUES (7876,’ADAMS’,’CLERK’,7788,to_date(’13-JUL-87′, ‘dd-mm-rr’)-51,1100,NULL,20);

INSERT INTO emp VALUES (7900,’JAMES’,’CLERK’,7698,to_date(‘3-12-1981′,’dd-mm-yyyy’),950,NULL,30);

INSERT INTO emp VALUES (7902,’FORD’,’ANALYST’,7566,to_date(‘3-12-1981′,’dd-mm-yyyy’),3000,NULL,20);

INSERT INTO emp VALUES (7934,’MILLER’,’CLERK’,7782,to_date(’23-1-1982′,’dd-mm-yyyy’),1300,NULL,10);

برای اینکار می توان از راهکارهایی مانند ساخت تابع به وسیله خودمان استفاده کرد مانند نمونه کد زیر :

CREATE OR REPLACE FUNCTION get_employees (p_deptno in emp.deptno%TYPE)

RETURN VARCHAR2

IS

l_text VARCHAR2(32767) := NULL;

BEGIN

FOR cur_rec IN (SELECT ename FROM emp WHERE deptno = p_deptno) LOOP

l_text := l_text || ‘,’ || cur_rec.ename;

END LOOP;

RETURN LTRIM(l_text, ‘,’);

END;

/

COLUMN employees FORMAT A50

SELECT deptno,

get_employees(deptno) AS employees

FROM emp

GROUP by deptno;

DEPTNO EMPLOYEES

———- ————————————————–

10 CLARK,KING,MILLER

20 SMITH,JONES,SCOTT,ADAMS,FORD

30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES

3 rows selected.

و استفاده از دیگر راهکارهایی مشابه تابع فوق.

تابع LISTAGG:
اوراکل در نسخه 11GR2 تابع LISTAGG را برای ساده سازی تجمیع رشته ها معرفی کرده است . یکی از قابلیت های خوب این تابع، امکان مرتب سازی خروجی براساس المان های دلخواه ما می باشد. به نمونه کد کاربرد این تابع دقت کنید.

COLUMN employees FORMAT A50

SELECT deptno, LISTAGG(ename, ‘,’) WITHIN GROUP (ORDER BY ename) AS employees

FROM emp

GROUP BY deptno;

DEPTNO EMPLOYEES

———- ————————————————–

10 CLARK,KING,MILLER

20 ADAMS,FORD,JONES,SCOTT,SMITH

30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

3 rows selected.