2017-03-02 48 views
1

下表收集了许多考试的学生成绩数据。来自直方图数据的百分位

CREATE TABLE grades 
AS 
    SELECT name, exams, grade_poor, grade_fair, grade_good, grade_vgood 
    FROM (VALUES 
    ('arun' , 8 , 1 , 4 , 2 , 1), 
    ('neha' , 10 , 3 , 2 , 1 , 4), 
    ('ram' , 5 , 1 , 1 , 3 , 0), 
    ('radha' , 8 , 0 , 3 , 1 , 4) 
) AS t(name,exams,grade_poor,grade_fair,grade_good,grade_vgood); 

成绩排序在vgood>好>公平感>差

将有可能(或它将使意义上)找到每个学生,这个数据的第50百分位等级?例如 - 如果我们将数据视为一系列等级类别,学生姓名为arun,则第50百分位数为grade_fair

+0

你想如何处理一个领带,如neha和radha的情况? – Patrick

+0

不太确定,抛硬币? – user3206440

+1

对不起,你运气不好。 PostgreSQL不能投掷硬币。 – Patrick

回答

2

首先你需要清楚这一点。我们是这样做的......

SELECT name, 
    ARRAY[grade_poor, grade_fair, grade_good, grade_vgood] 
FROM grades 

name | array 
-------+----------- 
arun | {1,4,2,1} 
neha | {3,2,1,4} 
ram | {1,1,3,0} 
radha | {0,3,1,4} 

然后,我们需要索引档次......我们这样做与CROSS JOIN LATERAL。我们有4行,数组为4.我们想要4 * 4行。

SELECT name, grades, gs1.x, grades[gs1.x] AS gradeqty 
FROM (
    SELECT name, 
    ARRAY[grade_poor, grade_fair, grade_good, grade_vgood] 
    FROM grades 
) AS t(name, grades) 
    CROSS JOIN LATERAL generate_series(1,4) AS gs1(x) 
ORDER BY name, x; 


name | grades | x | gradeqty 
-------+-----------+---+---------- 
arun | {1,4,2,1} | 1 |  1 
arun | {1,4,2,1} | 2 |  4 
arun | {1,4,2,1} | 3 |  2 
arun | {1,4,2,1} | 4 |  1 
neha | {3,2,1,4} | 1 |  3 
neha | {3,2,1,4} | 2 |  2 
neha | {3,2,1,4} | 3 |  1 
neha | {3,2,1,4} | 4 |  4 
radha | {0,3,1,4} | 1 |  0 
radha | {0,3,1,4} | 2 |  3 
radha | {0,3,1,4} | 3 |  1 
radha | {0,3,1,4} | 4 |  4 
ram | {1,1,3,0} | 1 |  1 
ram | {1,1,3,0} | 2 |  1 
ram | {1,1,3,0} | 3 |  3 
ram | {1,1,3,0} | 4 |  0 
(16 rows) 

现在剩下,是我们需要CROSS JOIN LATERAL再次重现X(我们年级),在gradeqty

SELECT name, 
    gs1.x 
FROM (
    SELECT name, 
    ARRAY[grade_poor, grade_fair, grade_good, grade_vgood] 
    FROM grades 
) AS t(name, grades) 
CROSS JOIN LATERAL generate_series(1,4) AS gs1(x) 
CROSS JOIN LATERAL generate_series(1,grades[gs1.x]) AS gs2(x) 
ORDER BY name, gs1.x; 

name | x 
-------+--- 
arun | 1 
arun | 2 
arun | 2 
arun | 2 
arun | 2 
arun | 3 
arun | 3 
arun | 4 
neha | 1 
neha | 1 
neha | 1 
neha | 2 
neha | 2 
neha | 3 
neha | 4 
neha | 4 
neha | 4 
neha | 4 
radha | 2 
radha | 2 
radha | 2 
radha | 3 
radha | 4 
radha | 4 
radha | 4 
radha | 4 
ram | 1 
ram | 2 
ram | 3 
ram | 3 
ram | 3 
(31 rows) 

现在我们GROUP BY name,然后我们用一个Ordered-Set Aggregate Functions percent_disc来完成这项工作..

SELECT name, percentile_disc(0.5) WITHIN GROUP (ORDER BY gs1.x) 
FROM (
    SELECT name, 
    ARRAY[grade_poor, grade_fair, grade_good, grade_vgood] 
    FROM grades 
) AS t(name, grades) 
CROSS JOIN LATERAL generate_series(1,4) AS gs1(x) 
CROSS JOIN LATERAL generate_series(1,grades[gs1.x]) AS gs2(x) 
GROUP BY name ORDER BY name; 

name | percentile_disc 
-------+----------------- 
arun |    2 
neha |    2 
radha |    3 
ram |    3 
(4 rows) 

想进一步进入它,让它漂亮......

SELECT name, (ARRAY['Poor', 'Fair', 'Good', 'Very Good'])[percentile_disc(0.5) WITHIN GROUP (ORDER BY gs1.x)] 
FROM (
    SELECT name, 
    ARRAY[grade_poor, grade_fair, grade_good, grade_vgood] 
    FROM grades 
) AS t(name, grades) 
CROSS JOIN LATERAL generate_series(1,4) AS gs1(x) 
CROSS JOIN LATERAL generate_series(1,grades[gs1.x]) AS gs2(x) 
GROUP BY name 
ORDER BY name; 

name | array 
-------+------- 
arun | Fair 
neha | Fair 
radha | Good 
ram | Good 
(4 rows) 

如果我们抬起一个新用户,我们可以得到一个稍微多一点的出来。

INSERT INTO grades (name,grade_poor,grade_fair,grade_good,grade_vgood) 
VALUES ('Bob', 0,0,0,100); 

name | array 
-------+----------- 
arun | Fair 
Bob | Very Good 
neha | Fair 
radha | Good 
ram | Good 
(5 rows) 
+0

感谢您的详细解释 - 我使用了Ordered-Set Aggregate Functions'percent_disc'之前的所有步骤。这一个给出错误 - http://sqlfiddle.com/#!15/f53f1/17 – user3206440

+0

我什至不能看到。但它可能是一个sqlfiddle问题。 SQL小提琴吸收一切。永远不要使用它。 –

+1

http://rextester.com/live/VTSP33905 –

1
SELECT name, exams, 
     CASE WHEN 0.5 * exams <= grade_poor 
       THEN 'grade_poor' 
      WHEN 0.5 * exams <= grade_poor + grade_fair 
       THEN 'grade_fair' 
      WHEN 0.5 * exams <= grade_poor + grade_fair + grade_good 
       THEN 'grade_good' 
      ELSE 'grade_vgood' END AS median_grade; 

这几轮联系下来,NEHA将比分“grade_fair”和拉达将比分“grade_good”。如果要整理,请将<=更改为<