2012-08-22 67 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