sql >> Databáze >  >> RDS >> Oracle

PostgreSQL ekvivalent funkce PERCENTILE_CONT společnosti Oracle

Po dalším hledání jsem našel stránku se seznamem pseudokódu, jak Oracle implementuje tuto funkci na :

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

Rozhodl jsem se napsat svou vlastní funkci v PG, abych napodobil funkci Oracle.

Našel jsem techniku ​​řazení polí od Davida Fettera na ::

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

a

Řazení prvků pole

Zde (pro přehlednost) je Davidův kód:

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
);
$$;

Takže zde je funkce, kterou jsem napsal:

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;

Zde jsou výsledky některých srovnávacích testů:

CREATE TABLE testdata
(
  intcolumn bigint,
  fltcolumn real
);

Zde jsou testovací data:

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);

Zde jsou výsledky srovnání:

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

Doufám, že to někomu pomůže, protože nebude muset znovu vynalézat kolo.

Užijte si to! Ray Harris



  1. PHP/MySQL kopíruje data po částech z jedné tabulky do druhé pomocí tlačítka načíst více

  2. Jak rozšířím hodnoty oddělené čárkami do samostatných řádků pomocí SQL Server 2005?

  3. Expresní dotaz pro SQL

  4. Jak odečíst hodiny od data v Oracle, aby to také ovlivnilo den