2012-08-22 66 views
11

我寫了一個查詢,其中一列是一個月。從那我必須得到最小月份,最大月份和中間月份。以下是我的查詢。我如何在postgresql中查詢min,median和max

select ext.employee, 
     pl.fromdate, 
     ext.FULL_INC as full_inc, 
     prevExt.FULL_INC as prevInc, 
     (extract(year from age (pl.fromdate))*12 +extract(month from age (pl.fromdate))) as month, 
     case 
     when prevExt.FULL_INC is not null then (ext.FULL_INC -coalesce(prevExt.FULL_INC,0)) 
     else 0 
     end as difference, 
     (case when prevExt.FULL_INC is not null then (ext.FULL_INC - prevExt.FULL_INC)/prevExt.FULL_INC*100 else 0 end) as percent 
from pl_payroll pl 
    inner join pl_extpayfile ext 
      on pl.cid = ext.payrollid 
     and ext.FULL_INC is not null 
    left outer join pl_extpayfile prevExt 
       on prevExt.employee = ext.employee 
       and prevExt.cid = (select max (cid) from pl_extpayfile 
           where employee = prevExt.employee 
           and payrollid = (
            select max(p.cid) 
            from pl_extpayfile, 
             pl_payroll p 
            where p.cid = payrollid 
            and pl_extpayfile.employee = prevExt.employee 
            and p.fromdate < pl.fromdate 
           )) 
       and coalesce(prevExt.FULL_INC, 0) > 0 
where ext.employee = 17 
and (exists (
    select employee 
    from pl_extpayfile preext 
    where preext.employee = ext.employee 
    and preext.FULL_INC <> ext.FULL_INC 
    and payrollid in (
     select cid 
     from pl_payroll 
     where cid = (
     select max(p.cid) 
     from pl_extpayfile, 
      pl_payroll p 
     where p.cid = payrollid 
     and pl_extpayfile.employee = preext.employee 
     and p.fromdate < pl.fromdate 
    ) 
    ) 
) 
    or not exists (
    select employee 
    from pl_extpayfile fext, 
     pl_payroll p 
    where fext.employee = ext.employee 
    and p.cid = fext.payrollid 
    and p.fromdate < pl.fromdate 
    and fext.FULL_INC > 0 
) 
) 
order by employee, 
     ext.payrollid desc 

如果不可能獲得最大月份和最小月份。

+5

您的查詢幾乎難以辨認。我把它放在一個代碼塊中,但仍然不可能真正遵循。爲了可讀性,您可能需要花時間編輯您的問題並將其格式化;現在有些人會看着它,去「嘎!」然後繼續前進而不試圖回答。儘管如此,我不知道這個問題的重點是什麼。所有你需要的是'min'和'max'聚合函數。對於中位數,你嘗試http://wiki.postgresql.org/wiki/Aggregate_Median?第一次搜索「postgresql中位數」 –

回答

13

您需要名爲minmax的聚合函數。請參閱PostgreSQL文檔和教程:

沒有內置在PostgreSQL中位數,但一個已經實施,並促成了維基:

http://wiki.postgresql.org/wiki/Aggregate_Median

它的使用方法與min和相同一旦你已經加載它,。在PL/PgSQL中編寫它會稍微慢一些,但是如果速度很重要的話,甚至可以使用C版本。

UPDATE評論後:

這聽起來像你要顯示的統計總數旁邊的單個結果。你不能用一個簡單的聚合函數來做到這一點,因爲你不能在結果列表中引用不在GROUP BY中的列。

您需要從子查詢中獲取統計信息,或者將聚合用作窗口函數。

由於虛擬數據:

CREATE TABLE dummystats (depname text, empno integer, salary integer); 
INSERT INTO dummystats(depname,empno,salary) VALUES 
('develop',11,5200), 
('develop',7,4200), 
('personell',2,5555), 
('mgmt',1,9999999); 

...並添加the median aggregate from the PG wiki後:

您可以用普通骨料做到這一點:

regress=# SELECT min(salary), max(salary), median(salary) FROM dummystats; 
min | max |   median   
------+---------+---------------------- 
4200 | 9999999 | 5377.5000000000000000 
(1 row) 

但不是這樣的:

regress=# SELECT depname, empno, min(salary), max(salary), median(salary) 
regress-# FROM dummystats; 
ERROR: column "dummystats.depname" must appear in the GROUP BY clause or be used in an aggregate function 

,因爲它在聚合模型中顯示平均數與個別值並無關係。你可以顯示組:

regress=# SELECT depname, min(salary), max(salary), median(salary) 
regress-# FROM dummystats GROUP BY depname; 
    depname | min | max |   median   
-----------+---------+---------+----------------------- 
personell | 5555 | 5555 | 5555.0000000000000000 
develop | 4200 | 5200 | 4700.0000000000000000 
mgmt  | 9999999 | 9999999 | 9999999.000000000000 
(3 rows) 

...但它聽起來像你想要的個人價值觀。爲此,您必須使用PostgreSQL 8.4中的新功能window

regress=# SELECT depname, empno, 
       min(salary) OVER(), 
       max(salary) OVER(), 
       median(salary) OVER() 
      FROM dummystats; 

    depname | empno | min | max |  median   
-----------+-------+------+---------+----------------------- 
develop | 11 | 4200 | 9999999 | 5377.5000000000000000 
develop |  7 | 4200 | 9999999 | 5377.5000000000000000 
personell |  2 | 4200 | 9999999 | 5377.5000000000000000 
mgmt  |  1 | 4200 | 9999999 | 5377.5000000000000000 
(4 rows) 

參見:

+0

如果我把最大值和最小值的方法,它要求將其餘的列放在group by子句中,之後它也不起作用 –

+0

@DeepakKumar您需要閱讀PostgreSQL教程。它解釋了關於聚合,「GROUP BY」等。猜測你需要通過子查詢來獲得最小值,最大值和中值,或者需要使用窗口函數來計算它們。請參閱http://www.postgresql.org/docs/current/static/tutorial-window.html。 –

+0

@DeepakKumar我懷疑你需要窗口函數。查看上面更新的答案。由於沒有示例數據,我無法運行查詢,但我提供了一個簡單示例。我使用avg()來表達一個意思,因爲沒有內置中值,但可以通過該wiki代碼添加一個。如果您在不添加任何「GROUP BY」的情況下將「OVER()」添加到聚合中,它可能會正常工作。 –

33

要計算中位數的PostgreSQL,乾脆把50%百分位,無需添加額外的功能或任何東西。

SELECT PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER by X) FROM T; 
+0

PERCENTILE_DISC()'在許多情況下可能是首選。 –

+4

就像一個魅力,但觀察這是postgres 9.4 +! –

+0

不錯。我擔心它不會在一個均勻長度的集合中平均值,但它似乎運作良好。 'SELECT PERCENTILE_CONT(0.5)WITHIN GROUP(ORDER BY VAL)FROM generate_series(1,4)as t(val);'返回2.5。但是,PERCENTILE_DISC返回2。 – isapir