sql >> データベース >  >> RDS >> Oracle

OracleのPERCENTILE_CONT関数に相当するPostgreSQL

    さらに検索した後、Oracleがこの関数を実装する方法の擬似コードをリストしたページを見つけました:

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

    Oracleの機能を模倣するために、PG内に独自の関数を作成することにしました。

    ::

    でDavidFetterによる配列ソート手法を見つけました。

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

    および

    配列要素の並べ替え

    ここに(明確にするために)Davidのコードがあります:

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

    これが私が書いた関数です:

    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;
    

    いくつかの比較テストの結果は次のとおりです。

    CREATE TABLE testdata
    (
      intcolumn bigint,
      fltcolumn real
    );
    

    テストデータは次のとおりです:

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

    比較結果は次のとおりです:

    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
    

    これが車輪の再発明をする必要がないことで誰かを助けてくれることを願っています。

    お楽しみください!レイハリス



    1. SQLで指定されたレコードの次のレコードを見つける方法は?

    2. 内部結合select(A、B)on A and B vs where(A、B)in select(A、B)in mysql

    3. プログラムの一部でMySQLクエリキャッシュを明示的に無効にする

    4. 数字を含む文字列によるMySQLの順序