Day 75: PL/SQL - 13 (How to make custom Aggregate Function in Oracle)
http://beyondrelational.com/modules/2/blogs/80/posts/10768/day-75-plsql-13-how-to-make-custom-aggregate-function-in-oracle.aspx
In this article, we will look into creating our own Aggregate Function in Oracle.
User-defined aggregates are a feature of the Extensibility Framework.It is possbile to make user define Aggregate function because of Oracle's Data Cartridge model which takes advantage of object types and other extensibility features. Inorder to create user-defined aggregate function, we need to implement a set of routines collectively referred to as the ODCIAggregate routines. It is of four types which are
- ODCIAggregateInitialize
- ODCIAggregateIterate
- ODCIAggregateMerge
- ODCIAggregateTerminate
Below is a brief description about the above routines
| ODCIAggregate Routines | Purpose |
| ODCIAggregateInitialize | Initialize the computation of the user-defined aggregate and will be return to Oracle as an object type instance. It is mandatory |
| ODCIAggregateIterate | This routine is repeatedly invoked by Oracle and on every invocation, a new value(s) and current aggregation context is passed as input. It processes the new value(s) and returns the updated aggregation context back to Oracle. It is mandatory |
| ODCIAggregateMerge | Combine two aggregation contexts and returns a single aggregation context.It is optional |
| ODCIAggregateTerminate | This routine is invoked by Oracle as the final step of aggregation which returns the resulting aggregate value. It is mandatory |
It is quite simple to create user define Aggregate function in Oracle.For creating a user define aggreagte function, we need -
- Object type specification
- Object type body
- PL/SQL aggregate function
So armed with all these information, we can now create our own aggregate function that will perform string aggregation.
Let us first see the original source
01.SQL> Select DeptName,EmpName02.From tblDept03.Join tblEmployee04.Using(DeptId)05.Group By DeptName;06. 07.DEPTNAME EMPNAME08.-------------------------------------------------- ----------------------09.IT Deepak Kumar Goyal10.Accounts Shashi Dayal11.IT Amitav Mallik12.Sales Amit Ojha13.Finance Sumanta Manik14.IT Deepak Singh15.IT Shashi Bhushan16.IT Amitav Salonki17.Accounts Deepak Singh18.Accounts Shashi Bhushan19.Accounts Amitav Salonki20.Accounts Manish Bharat21.Accounts Abhijeet Moshambique22.Finance Sarapati Babulal Apte23.Finance Shinarayan Pande24.Finance Fatima Sarani25. 26.16 rows selected.Well Oracle already has WM_Concat(undocumented function in in 10g) and ListAgg function(Oracle 11g R2) for doing so. Let us see what the built-in ListAgg/WM_Concat function is doing.
01.SQL> Select DeptName,ListAgg(EmpName,',') Within Group (Order By EmpName) Concat_Employees02.From tblDept03.Join tblEmployee04.Using(DeptId)05.Group By DeptName;06. 07.- OR - 08. 09.SQL> Select DeptName,WM_Concat(EmpName) Concat_Employees10.From tblDept11.Join tblEmployee12.Using(DeptId)13.Group By DeptName;14. 15.DEPTNAME CONCAT_EMPLOYEES16.-------------------------------------------------- -------------------------------------------------------17.Accounts Shashi Dayal,Deepak Singh,Amitav Salonki,Shashi Bhushan18.,Manish Bharat,Abhijeet Moshambique19. 20.Finance Sumanta Manik,Sarapati Babulal Apte,Fatima Sarani21.,Shinarayan Pande22. 23.IT Deepak Kumar Goyal,Deepak Singh,Amitav Salonki24.,Shashi Bhushan,Amitav Mallik25. 26.Sales Amit OjhaOur aim is to make a similar kind of function.
N.B.~If someone ask me since we already have buit-in function for achieving the result then why we need to build our own? Well it is for our demonstration purpose
Now let us look into the practical aspect of doing so
Step 1: First create the Object type specification
01.SQL> CREATE OR REPLACE TYPE String_Aggregate_Type AS OBJECT(02. 03.str_values VARCHAR2(8000),04. 05.STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT String_Aggregate_Type) 06.RETURN NUMBER,07. 08.MEMBER FUNCTION ODCIAggregateIterate(self IN OUT String_Aggregate_Type 09.,value IN VARCHAR2) 10.RETURN NUMBER,11. 12.MEMBER FUNCTION ODCIAggregateMerge(self IN OUT String_Aggregate_Type 13.,ctx2 IN String_Aggregate_Type) 14.RETURN NUMBER,15. 16.MEMBER FUNCTION ODCIAggregateTerminate (self IN String_Aggregate_Type17.,return_value OUT VARCHAR218.,flags IN NUMBER) 19.RETURN NUMBER20. 21.);22./23.Type created.To keep things simple, our type needs only the string values(str_values). If we look into the original source, it is EMPNAME values
Step 2: Second, create the Object type body
01.SQL> CREATE OR REPLACE TYPE BODY String_Aggregate_Type IS02. 03.STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT String_Aggregate_Type) 04.RETURN NUMBER IS05.BEGIN06.sctx := String_Aggregate_Type(null);07.RETURN ODCIConst.Success;08.END;09. 10.MEMBER FUNCTION ODCIAggregateIterate(self IN OUT String_Aggregate_Type 11.,value IN varchar2) 12.RETURN NUMBER IS13.BEGIN14.str_values := str_values || ',' || value;15.str_values := LTRIM(str_values,',');16.RETURN ODCIConst.Success;17.END; 18. 19.MEMBER FUNCTION ODCIAggregateMerge(self IN OUT String_Aggregate_Type 20.,ctx2 IN String_Aggregate_Type) 21.RETURN NUMBER22.IS23.BEGIN24.str_values := str_values || ctx2.str_values;25.return ODCIConst.Success;26.END;27. 28.MEMBER FUNCTION ODCIAggregateTerminate(self IN String_Aggregate_Type29.,return_value OUT VARCHAR230.,flags IN NUMBER) 31.RETURN NUMBER 32.IS33.BEGIN34.return_value := str_values ;35.return ODCIConst.Success;36.END;37.END;38./39.Type body created.In the ODCIAggregateInitialize, we are initializing str_values with null values. In ODCIAggregateIterate, the values(in this case EMPNAME) are being iterated, appended with a comma(,) delimeter and are store into the str_values.This is the method that tells Oracle on how to aggregate the individual elements that are passed to it. The ODCIAggregateMerge combines two aggregation contexts and returns a single aggregation context.Finally, ODCIAggregateTerminate returns the aggregated result
Step 3: Create the PL/SQL aggregate function
1.SQL> CREATE OR REPLACE FUNCTION Custom_String_Aggregation(inputString VARCHAR2) 2.RETURN VARCHAR23.PARALLEL_ENABLE AGGREGATE USING String_Aggregate_Type;4./5.Function created.So our function is now ready to use and let us use it as under
01.SQL> Select DeptName,Custom_String_Aggregation(EmpName) Concat_Employees02.From tblDept03.Join tblEmployee04.Using(DeptId)05.Group By DeptName;06. 07.DEPTNAME CONCAT_EMPLOYEES08.-------------------------------------------------- -------------------------------------------------------09.Accounts Shashi Dayal,Deepak Singh,Amitav Salonki,Shashi Bhushan10.,Manish Bharat,Abhijeet Moshambique11. 12.Finance Sumanta Manik,Sarapati Babulal Apte,Fatima Sarani13.,Shinarayan Pande14. 15.IT Deepak Kumar Goyal,Deepak Singh,Amitav Salonki16.,Shashi Bhushan,Amitav Mallik17. 18.Sales Amit OjhaFrom SQL Server 2005, we can write our own CLR Aggregate Function
Hope this helps. Thanks for reading
浙公网安备 33010602011771号