2013-01-13 34 views
8

Có ai đã tìm thấy một tương đương PostgreSQL với hàm PERCENTILE_CONT của Oracle không? Tôi tìm kiếm, và không thể tìm thấy một cái, vì vậy tôi đã viết của riêng tôi.PostgreSQL tương đương với hàm PERCENTILE_CONT của Oracle

Đây là giải pháp mà tôi hy vọng sẽ giúp bạn.

Công ty tôi làm việc vì muốn di chuyển ứng dụng web Java EE từ sử dụng cơ sở dữ liệu Oracle sang sử dụng PostgreSQL. Một số thủ tục được lưu trữ dựa nhiều vào việc sử dụng hàm PERCENTILE_CONT() duy nhất của Oracle. Hàm này không tồn tại trong PostgreSQL.

Tôi đã thử tìm kiếm xem có ai đã "chuyển qua" có hoạt động thành PG không có lịch phát sóng hay không.

Trả lời

17

Sau khi tìm kiếm hơn tôi tìm thấy một trang liệt kê các pseudo-code bao Oracle thực hiện chức năng này tại địa chỉ:

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

tôi xác định để viết chức năng riêng của tôi trong vòng PG để bắt chước tính năng của Oracle.

Tôi tìm thấy một mảng sắp xếp kỹ thuật bởi David Fetter tại ::

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

Sorting array elements

đây (cho rõ ràng) là mã của 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 
); 
$$; 

Vì vậy, đây là hàm tôi viết 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; 

Dưới đây là kết quả của một số thử nghiệm so sánh:

CREATE TABLE testdata 
(
    intcolumn bigint, 
    fltcolumn real 
); 

Đây là dữ liệu thử nghiệm:

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

Đây là kết quả so sánh:

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 

Tôi hy vọng điều này sẽ giúp ai đó o ut bởi không cần phải tái tạo lại bánh xe.

Tận hưởng! Ray Harris

+0

bạn có thể tránh được bằng cách sử dụng arroy_sort ORDER BY. Nó thực sự nhanh hơn một chút so với array_sort. – echo

+0

Tôi đã sử dụng chức năng này và cập nhật cơ sở dữ liệu của mình. Có một hàm có cùng tên bắt đầu bằng 9.4 và có xung đột giữa hai hàm do đặt tên giống nhau và cách chúng được triển khai. Điều này xảy ra sau khi tôi di chuyển từ 9,3 đến 9,6. –

2

Với PostgreSQL 9.4 có hỗ trợ cho percentiles bây giờ, thực hiện trong chức năng tổng hợp Ordered-Thiết:

percentile_cont(fraction) WITHIN GROUP (ORDER BY sort_expression) 

trăm liên tục: trả về một giá trị tương ứng với quy định phần trong trật tự, nội suy giữa các mục nhập liền kề nếu cần

percentile_cont(fractions) WITHIN GROUP (ORDER BY sort_expression) 

nhiều phần trăm liên tục: trả về một kết quả phù hợp với thông số phân số, wi thứ mỗi phần tử không null thay thế bằng giá trị tương ứng với phần trăm

rằng Xem tài liệu để biết thêm chi tiết: http://www.postgresql.org/docs/current/static/functions-aggregate.html

Các vấn đề liên quan