2011-03-08 49 views
8

假設你有一個表,如下所示:是否有替代MULTISET運算符來避免子查詢?

CREATE TABLE EMPLOYEE_SALES 
(
    EMPLOYEE_ID NUMBER, 
    PRODUCT_ID NUMBER, 
    SALE_AMOUNT NUMBER 
); 

並假定它是填充如下:

 
+-------------+------------+-------------+ 
| EMPLOYEE_ID | PRODUCT_ID | SALE_AMOUNT | 
+-------------+------------+-------------+ 
|  1  |  100 |  1.05 | 
|  1  |  200 |  45.67 | 
|  2  |  100 |  3.25 | 
|  2  |  200 |  34.29 | 
+-------------+------------+-------------+ 

現在,假設我創建一個名爲SALE_TYPE自定義類型代表一個(PRODUCT_ID, SALE_AMOUNT)元組:

CREATE TYPE SALE_TYPE IS OBJECT 
(
    PRODUCT_ID NUMBER, 
    SALE_AMOUNT NUMBER 
); 

並假設我還創建了一個名爲SALES_TYPE的自定義類型,其中repr esents一個TABLESALE_TYPE的:

CREATE TYPE SALES_TYPE IS TABLE OF SALE_TYPE; 

我想EMPLOYEE_ID查詢EMPLOYEE_SALES表組。對於每個EMPLOYEE_ID,我希望創建一個SALES_TYPE包含該員工的銷售。根據該文件,我會做這樣的事情:

SELECT 
    EMPLOYEE_ID, 
    CAST 
    (
    MULTISET 
    (
     SELECT 
     PRODUCT_ID, 
     SALE_AMOUNT 
     FROM 
     EMPLOYEE_SALES inner_employee_sales 
     WHERE 
     inner_employee_sales.employee_id = employee_sales.employee_id 
    ) AS SALES_TYPE 
) AS SALES 
FROM 
    EMPLOYEE_SALES 
GROUP BY 
    EMPLOYEE_ID 

我希望這個查詢產生這樣的事:

 
+-------------+------------------------------+ 
| EMPLOYEE_ID | SALES      | 
+-------------+------------------------------+ 
|  1  | +------------+-------------+ | 
|    | | PRODUCT_ID | SALE_AMOUNT | | 
|    | +------------+-------------+ | 
|    | | 100  |  1.05 | | 
|    | | 200  |  45.67 | | 
|    | +------------+-------------+ | 
+-------------+------------------------------+ 
|  2  | +------------+-------------+ | 
|    | | PRODUCT_ID | SALE_AMOUNT | | 
|    | +------------+-------------+ | 
|    | | 100  |  3.25 | | 
|    | | 200  |  34.29 | | 
|    | +------------+-------------+ | 
+-------------+------------------------------+ 

有沒有一種方法來達到同樣的效果,而不會發出子查詢(real我正在處理的查詢比這個人爲的例子複雜得多)?例如,有沒有這樣的事情:

SELECT 
    EMPLOYEE_ID, 
    CAST 
    (
    COLLECT_ALL_RECORDS_WITHIN_THE_CURRENT_GROUP(
     PRODUCT_ID, 
     SALE_AMOUNT 
    ) 
    AS SALES_TYPE 
) AS SALES 
FROM 
    EMPLOYEE_SALES 
GROUP BY 
    EMPLOYEE_ID 

回答

6

在Oracle 10g中,你可以使用collect操作如下:

select employee_id, 
     cast(collect(sale_type(product_id, sale_amount)) as sales_type) 
from employee_sales 
group by employee_id 
+0

+1:哇,太簡單了! – 2011-03-09 13:20:01

3

你應該能夠編寫沿着被創建11.2和LISTAGG功能之前,連接字符串的聚合函數線custom aggregate function

例如,我可以創造一個EMP_OBJ對象,這些對象(EMP_TBL)的收集和編寫從一個簡單的SQL語句將產生一個EMP_TBL收集

創建基本類型的自定義聚合函數

SQL> create type emp_obj as object (
    2 empno number, 
    3 ename varchar2(100) 
    4 ); 
    5/

Type created. 

SQL> create type emp_tbl 
    2 as 
    3 table of emp_obj; 
    4/

Type created. 

創建,我們將用做聚合

SQL> ed 
Wrote file afiedt.buf 

    1 CREATE OR REPLACE TYPE emp_tbl_agg AS OBJECT 
    2 (
    3 g_emp_coll emp_tbl, 
    4 STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT emp_tbl_agg) 
    5  RETURN NUMBER, 
    6 MEMBER FUNCTION ODCIAggregateIterate(self IN OUT emp_tbl_agg , 
    7           value IN  emp_obj) 
    8  RETURN NUMBER, 
    9 MEMBER FUNCTION ODCIAggregateTerminate(self   IN emp_tbl_agg, 
10           returnValue OUT emp_tbl, 
11           flags  IN NUMBER) 
12  RETURN NUMBER, 
13 MEMBER FUNCTION ODCIAggregateMerge(self IN OUT emp_tbl_agg, 
14          ctx2 IN  emp_tbl_agg) 
15  RETURN NUMBER 
16*); 
17/

Type created. 

SQL> ed 
Wrote file afiedt.buf 

    1 CREATE OR REPLACE TYPE BODY emp_tbl_agg IS 
    2 STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT emp_tbl_agg) 
    3  RETURN NUMBER IS 
    4 BEGIN 
    5  sctx := emp_tbl_agg(NULL); 
    6  sctx.g_emp_coll := new emp_tbl(); 
    7  RETURN ODCIConst.Success; 
    8 END; 
    9 MEMBER FUNCTION ODCIAggregateIterate(self IN OUT emp_tbl_agg, 
10           value IN  emp_obj) 
11  RETURN NUMBER IS 
12 BEGIN 
13  SELF.g_emp_coll.extend(); 
14  SELF.g_emp_coll(self.g_emp_coll.count) := value; 
15  RETURN ODCIConst.Success; 
16 END; 
17 MEMBER FUNCTION ODCIAggregateTerminate(self   IN emp_tbl_agg, 
18           returnValue OUT emp_tbl, 
19           flags  IN NUMBER) 
20  RETURN NUMBER IS 
21 BEGIN 
22  returnValue := self.g_emp_coll; 
23  RETURN ODCIConst.Success; 
24 END; 
25 MEMBER FUNCTION ODCIAggregateMerge(self IN OUT emp_tbl_agg, 
26          ctx2 IN  emp_tbl_agg) 
27  RETURN NUMBER IS 
28 BEGIN 
29  FOR i IN ctx2.g_emp_coll.FIRST .. ctx2.g_emp_coll.LAST 
30  LOOP 
31  self.g_emp_coll.extend(); 
32  self.g_emp_coll(self.g_emp_coll.count) := ctx2.g_emp_coll(i); 
33  END LOOP; 
34  RETURN ODCIConst.Success; 
35 END; 
36* END; 
SQL>/

Type body created. 

類型聲明聚合函數

SQL> create or replace function emp_agg(p_input emp_obj) 
    2 return emp_tbl 
    3 aggregate using emp_tbl_agg; 
    4/

Function created. 

而現在一個簡單的GROUP BY使用我們的自定義聚合功能將產生EMP_TBL收集

SQL> select deptno, emp_agg(emp_obj(empno, ename)) 
    2 from emp 
    3 group by deptno; 

    DEPTNO 
---------- 
EMP_AGG(EMP_OBJ(EMPNO,ENAME))(EMPNO, ENAME) 
-------------------------------------------------------------------------------- 

     10 
EMP_TBL(EMP_OBJ(7782, 'CLARK'), EMP_OBJ(7934, 'MILLER'), EMP_OBJ(7839, 'KING')) 

     20 
EMP_TBL(EMP_OBJ(7369, 'smith'), EMP_OBJ(7902, 'FORD'), EMP_OBJ(7876, 'ADAMS'), E 

MP_OBJ(7788, 'SCOTT'), EMP_OBJ(7566, 'JONES')) 

     30 
EMP_TBL(EMP_OBJ(7499, 'ALLEN'), EMP_OBJ(7900, 'SM2'), EMP_OBJ(7844, 'TURNER'), E 


    DEPTNO 
---------- 
EMP_AGG(EMP_OBJ(EMPNO,ENAME))(EMPNO, ENAME) 
-------------------------------------------------------------------------------- 

MP_OBJ(7698, 'BLAKE'), EMP_OBJ(7654, 'MARTIN'), EMP_OBJ(7521, 'WARD')) 
+0

+ 1:我忘記了自定義聚合函數!當然,這非常詳細,但它確實完成了工作。謝謝! – 2011-03-08 19:07:08