2012-02-14 56 views
3

我刚刚实现了ODCIAggregate接口来创建一个自定义聚合函数。它工作的很好,很快,但我希望它能做更多的事情。我有一份声明会是这样的:在用户定义的聚合函数中有序迭代?

SELECT SomeId, myAggregationFunction(Item) FROM 
(
    SELECT 
    Foo.SomeId, 
    SomeType(Foo.SomeValue, Foo.SomeOtherValue) AS Item 
    FROM 
    Foo 
    ORDER BY Foo.SomeOrderingValue 
) 
GROUP BY SomeId; 

我的问题是,项目不会传递给我以同样的顺序,我的内心(有序)SELECT返回他们执行的ODCIAggregateIterate功能。

我谷歌搜索,并没有找到任何Oracle提供的方式来这样做。有没有人根据这个要求尝试过类似的问题?

谢谢!

+0

所以你需要在你的'myAggregationFunction'中的值进行排序?为什么? – vulkanino 2012-02-14 15:43:02

+1

难道你不是'ORDER BY'外面的'SELECT'吗? – vulkanino 2012-02-14 15:47:04

+1

@Frank - 您的聚合函数可以存储数据,然后在返回之前对其进行排序吗?如果您希望该功能在分类输入上运行,那么这是最常见的解决方案。 – 2012-02-14 15:53:29

回答

4

您是否考虑过使用COLLECT而不是数据盒?

至少对于字符串聚合,COLLECT方法更简单快得多。它确实使你的SQL有点怪异。

下面是一个仅使用简单字符串连接的示例。

--Create a type 
create or replace type sometype as object 
(
    someValue varchar2(100), 
    someOtherValue varchar2(100) 
); 

--Create a nested table of the type. 
--This is where the performance improvement comes from - Oracle can aggregate 
--the types in SQL using COLLECT, and then can process all the values at once. 
--This significantly reduces the context switches between SQL and PL/SQL, which 
--are usually more expensive than the actual work. 
create or replace type sometypes as table of sometype; 

--Process all the data (it's already been sorted before it gets here) 
create or replace function myAggregationFunction(p_sometypes in sometypes) 
return varchar2 is 
    v_result varchar2(4000); 
begin 
    --Loop through the nested table, just concatenate everything for testing. 
    --Assumes a dense nested table 
    for i in 1 .. p_sometypes.count loop 
     v_result := v_result || ',' || 
      p_sometypes(i).someValue || '+' || p_sometypes(i).someOtherValue; 
    end loop; 

    --Remove the first delimeter, return value 
    return substr(v_result, 2); 
end; 
/

--SQL 
select someId 
    ,myAggregationFunction 
    (
     cast 
     (
      --Here's where the aggregation and ordering happen 
      collect(sometype(SomeValue, SomeOtherValue) 
       order by SomeOrderingValue) 
      as someTypes 
     ) 
    ) result 
from 
(
    --Test data: note the unordered SoemOrderingValue. 
    select 1 someId, 3 SomeOrderingValue, '3' SomeValue, '3' SomeOtherValue 
    from dual union all 
    select 1 someId, 1 SomeOrderingValue, '1' SomeValue, '1' SomeOtherValue 
    from dual union all 
    select 1 someId, 2 SomeOrderingValue, '2' SomeValue, '2' SomeOtherValue 
    from dual 
) foo 
group by someId; 

--Here are the results, aggregated and ordered. 
SOMEID RESULT 
------ ------ 
1  1+1,2+2,3+3 
+0

感谢您的回答。这绝对是做到这一点的最佳方式。与此同时,我做了贾斯汀在问题的评论中提出的建议,这很好,但我认为你的方式更清洁。 COLLECT函数现在是我的工具箱的一部分;)谢谢你的时间。 – thatfrankdev 2012-02-22 14:38:45

+0

这是一个非常优雅的解决方案。好想法。干杯! – Chiranjib 2015-07-21 13:26:43

-1

Oracle很可能会重写您的查询并删除子查询。我从来没有做过像你在做什么,但你可以在内部查询中添加NO_UNNEST提示吗?

SELECT SomeId, myAggregationFunction(Item) FROM 
(
    SELECT /*+ NO_UNNEST */ 
    Foo.SomeId, ... 

即使如此,我真的不知道它会在子查询中使用ORDER BY。

相关问题