2015-10-29 93 views
0

这是一个在oracle中聚合字符串的自定义函数。按顺序PLSQL的自定义函数字符串聚合

Date Fruit Number 
1  Apple 1 
1  Apple 4 
1  Apple 3 
1  Kiwi  6 
1  Kiwi  10 

打开到

Date  Fruit Number 
1  Apple 1-3-4 
1  Kiwi  6-10 

通过使用

SELECT Date,fruit, string_agg(number) AS Agg 
FROM fruit 
GROUP BY Date,fruit 

string_agg是下面的代码

CREATE OR REPLACE TYPE t_string_agg AS OBJECT 
(
    g_string VARCHAR2(32767), 

STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_string_agg) 
RETURN NUMBER, 

MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_string_agg, 
            value IN  VARCHAR2) 
RETURN NUMBER, 

MEMBER FUNCTION ODCIAggregateTerminate(self   IN t_string_agg, 
            returnValue OUT VARCHAR2, 
            flags  IN NUMBER) 
RETURN NUMBER, 

MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_string_agg, 
           ctx2 IN  t_string_agg) 
RETURN NUMBER 
); 
/
SHOW ERRORS 


CREATE OR REPLACE TYPE BODY t_string_agg IS 
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_string_agg) 
RETURN NUMBER IS 
BEGIN 
sctx := t_string_agg(NULL); 
RETURN ODCIConst.Success; 
END; 

MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_string_agg, 
            value IN  VARCHAR2) 
RETURN NUMBER IS 
BEGIN 
SELF.g_string := self.g_string || ',' || value; 
RETURN ODCIConst.Success; 
END; 

MEMBER FUNCTION ODCIAggregateTerminate(self   IN t_string_agg, 
            returnValue OUT VARCHAR2, 
            flags  IN NUMBER) 
RETURN NUMBER IS 
BEGIN 
returnValue := RTRIM(LTRIM(SELF.g_string, ','), ','); 
RETURN ODCIConst.Success; 
END; 

MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_string_agg, 
           ctx2 IN  t_string_agg) 
RETURN NUMBER IS 
BEGIN 
SELF.g_string := SELF.g_string || ',' || ctx2.g_string; 
RETURN ODCIConst.Success; 
END; 
END; 
/
SHOW ERRORS 


CREATE OR REPLACE FUNCTION string_agg (p_input VARCHAR2) 
RETURN VARCHAR2 
PARALLEL_ENABLE AGGREGATE USING t_string_agg; 
/
SHOW ERRORS 

但问题我不能命令字符串中创建一个功能按照我希望的方式排列。如何修改自定义函数代码以按照某种顺序进行聚合,例如按数字顺序排序?

顺便说一句:我的版本是10g,所以我不能使用listagg。可以修改此代码以便通过某个输入进行排序?谢谢!

回答

0

不要重新发明轮子。使用LISTAGG

CREATE TABLE tab("Date" INT, Fruit VARCHAR(100), "Number" INT); 

INSERT INTO tab VALUES (1  ,'Apple', 1); 
INSERT INTO tab VALUES (1  ,'Apple',  4); 
INSERT INTO tab VALUES (1  ,'Apple',  3); 
INSERT INTO tab VALUES (1  ,'Kiwi',  6); 
INSERT INTO tab VALUES (1  ,'Kiwi',  10); 


SELECT DISTINCT "Date", Fruit, 
    LISTAGG ("Number" , '-') 
    WITHIN GROUP (ORDER BY "Date") OVER(PARTITION BY "Date", Fruit) AS "Number" 
FROM tab; 

SqlFiddleDemo

警告:

请记住,你需要列ORDER BY。在这种情况下,如果查询将按不同的顺序读取数据,那么您没有使用升序orde的列并使用Date,这些值的所有相同值可能会中断。你应该有这样的事情:

ID Date Fruit Number 
1 1 Apple 1 
2 1 Apple 4 
3 1 Apple 3 
4 1 Kiwi  6 
5 1 Kiwi  10 

和:

LISTAGG ("Number" , '-') 
WITHIN GROUP (ORDER BY ID ASC) OVER(PARTITION BY "Date", Fruit) AS "Number" 

编辑:

LISTAGG可从甲骨文11

+0

欣赏小伙子,但我在版本10g(Listagg不支持),我想要升赚取如何创建定制功能。 – Sailormoon

+0

@SailorMoon伟大的,但未来更具体与您使用的标签 – lad2025

+1

耶谢谢!我不知道我可以在标签上放10g – Sailormoon