2013-01-13 16 views
8

Czy ktoś znalazł PostgreSQL odpowiednik funkcji PERCENTILE_CONT Oracle? Szukałem i nie mogłem go znaleźć, więc napisałem własne.PostgreSQL odpowiednik funkcji PERCENTILE_CONT Oracle

Oto rozwiązanie, które, mam nadzieję, pomoże.

Firma, w której pracuję, chciała migrować aplikację internetową Java EE z wykorzystaniem bazy danych Oracle do korzystania z PostgreSQL. Kilka procedur przechowywanych polegało głównie na użyciu unikalnej funkcji PERCENTILE_CONT() firmy Oracle. Ta funkcja nie istnieje w PostgreSQL.

Próbowałem sprawdzić, czy ktoś "przeportował" tę funkcję w PG bez skutku.

Odpowiedz

17

Po więcej poszukiwaniach znalazłem stronę, która wymieniła pseudo-kod jak Oracle realizuje tę funkcję w:

http://docs.oracle.com/cd/B19306_01/server.102/b14200/functions110.htm

postanowiłem napisać własną funkcję w PG naśladować funkcji Oracle.

znalazłem tablicę techniki sortowania David Fetter w ::

http://postgres.cz/wiki/PostgreSQL_SQL_Tricks#General_array_sort

i

Sorting array elements

Tutaj (dla jasności) David Kod:

CREATE OR REPLACE FUNCTION array_sort (ANYARRAY) 
RETURNS ANYARRAY LANGUAGE SQL 
AS $$ 
SELECT ARRAY(
    SELECT $1[s.i] AS "foo" 
    FROM 
     generate_series(array_lower($1,1), array_upper($1,1)) AS s(i) 
    ORDER BY foo 
); 
$$; 

Oto funkcja, którą wykonuję e:

CREATE OR REPLACE FUNCTION percentile_cont(myarray real[], percentile real) 
RETURNS real AS 
$$ 

DECLARE 
    ary_cnt INTEGER; 
    row_num real; 
    crn real; 
    frn real; 
    calc_result real; 
    new_array real[]; 
BEGIN 
    ary_cnt = array_length(myarray,1); 
    row_num = 1 + (percentile * (ary_cnt - 1)); 
    new_array = array_sort(myarray); 

    crn = ceiling(row_num); 
    frn = floor(row_num); 

    if crn = frn and frn = row_num then 
    calc_result = new_array[row_num]; 
    else 
    calc_result = (crn - row_num) * new_array[frn] 
      + (row_num - frn) * new_array[crn]; 
    end if; 

    RETURN calc_result; 
END; 
$$ 
    LANGUAGE 'plpgsql' IMMUTABLE; 

Oto wyniki niektórych testów porównania:

CREATE TABLE testdata 
(
    intcolumn bigint, 
    fltcolumn real 
); 

Oto dane testowe:

insert into testdata(intcolumn, fltcolumn) values (5, 5.1345); 
insert into testdata(intcolumn, fltcolumn) values (195, 195.1345); 
insert into testdata(intcolumn, fltcolumn) values (1095, 1095.1345); 
insert into testdata(intcolumn, fltcolumn) values (5995, 5995.1345); 
insert into testdata(intcolumn, fltcolumn) values (15, 15.1345); 
insert into testdata(intcolumn, fltcolumn) values (25, 25.1345); 
insert into testdata(intcolumn, fltcolumn) values (495, 495.1345); 
insert into testdata(intcolumn, fltcolumn) values (35, 35.1345); 
insert into testdata(intcolumn, fltcolumn) values (695, 695.1345); 
insert into testdata(intcolumn, fltcolumn) values (595, 595.1345); 
insert into testdata(intcolumn, fltcolumn) values (35, 35.1345); 
insert into testdata(intcolumn, fltcolumn) values (30195, 30195.1345); 
insert into testdata(intcolumn, fltcolumn) values (165, 165.1345); 
insert into testdata(intcolumn, fltcolumn) values (65, 65.1345); 
insert into testdata(intcolumn, fltcolumn) values (955, 955.1345); 
insert into testdata(intcolumn, fltcolumn) values (135, 135.1345); 
insert into testdata(intcolumn, fltcolumn) values (19195, 19195.1345); 
insert into testdata(intcolumn, fltcolumn) values (145, 145.1345); 
insert into testdata(intcolumn, fltcolumn) values (85, 85.1345); 
insert into testdata(intcolumn, fltcolumn) values (455, 455.1345); 

Oto wyniki porównania:

ORACLE RESULTS 
ORACLE RESULTS 

select percentile_cont(.25) within group (order by fltcolumn asc) myresult 
from testdata; 
select percentile_cont(.75) within group (order by fltcolumn asc) myresult 
from testdata; 

myresult 
- - - - - - - - 
57.6345     

myresult 
- - - - - - - - 
760.1345    

POSTGRESQL RESULTS 
POSTGRESQL RESULTS 

select percentile_cont(array_agg(fltcolumn), 0.25) as myresult 
from testdata; 

select percentile_cont(array_agg(fltcolumn), 0.75) as myresult 
from testdata; 

myresult 
real 
57.6345 

myresult 
real 
760.135 

Mam nadzieję, że to pomoże komuś ut przez nie wymyślanie koła.

Ciesz się! Ray Harris

+0

można uniknąć arroy_sort za pomocą ORDER BY. W rzeczywistości jest trochę szybszy niż array_sort. – echo

+0

Użyłem tej funkcji i zaktualizowałem moją bazę danych. Istnieje funkcja o tej samej nazwie zaczynająca się od 9.4, a między tymi dwiema funkcjami istnieje konflikt, ponieważ nazywa się podobieństwa i sposób ich implementacji. Stało się tak po migracji z wersji 9.3 do 9.6. –

2

Z PostgreSQL 9.4 jest natywne wsparcie dla percentyla obecnie realizowany w nakazał-Set funkcji agregujących:

percentile_cont(fraction) WITHIN GROUP (ORDER BY sort_expression) 

ciągły percentyla: zwraca wartość odpowiadającą określonej frakcji w zamawianiu interpolację między sąsiednimi elementów wejściowych w razie potrzeby

percentile_cont(fractions) WITHIN GROUP (ORDER BY sort_expression) 

wielokrotne ciągłe percentyl: zwraca tablicy wyników odpowiadających kształt parametru frakcje, wi th każdego niepuste elementu zastąpiona przez wartość odpowiadającą tej percentyla

Zobacz dokumentację po więcej szczegółów: http://www.postgresql.org/docs/current/static/functions-aggregate.html