2012-02-14 96 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。

相關問題