在postgresql中根据日期获取数据和总和

时间:2015-12-08 08:55:52

标签: sql postgresql group-by sum greenplum

我在Greenplum工作 - postgresql DB并且具有以下数据结构:

enter image description here

在此我需要以下逻辑来实现(其中一些我已经实现过):

CASE WHEN PDATE IS NOT NULL THEN to_char(PDATE,'YYYY-MM-DD') 
WHEN PDATE IS NULL THEN to_char(NDATE,'YYYY-MM-DD N')
WHEN NDATEIS NULL THEN 'NO PO' ELSE 'NO PO' END

根据我需要QTY和VName。

  

数量:根据min(PDATE和NDATE)得出的总和(数量)

     

VName:VName根据min(PDATE和NDATE)

期望的输出:

DESIRED OUTPUT

到目前为止,我已经在下面进行了查询:

SELECT
    ITEM ,
    MIN(CASE WHEN PDATE IS NOT NULL THEN to_char(PDATE,'YYYY-MM-DD') 
             WHEN PDATE IS NULL THEN to_char(NDATE,'YYYY-MM-DD N')
             WHEN NDATE IS NULL THEN 'NO PO' ELSE 'NO PO' END) AS PRO
FROM
    Table
GROUP BY
    ITEM

请帮我解决问题

3 个答案:

答案 0 :(得分:1)

感谢蒂姆的帮助..我花了一些时间来创建查询,但最后它已经完成了..为了节省时间我在论坛中发布了这个问题,结束了同样的事情 - 花了时间。

这里是查询

SELECT
    FO.ID ,
    (CASE WHEN FO.DateQ IS NOT NULL THEN to_char(FO.DateQ ,'YYYY-MM-DD') 
          WHEN FO.DateQ IS NULL THEN to_char(FO.Datew ,'YYYY-MM-DD N') 
          WHEN FO.Datew IS NULL AND FO.DateQ IS NULL THEN 'NO PO' END) AS DATER ,
    FO.QTY ,
    FO.VNAME
FROM
    (
        SELECT
            NT.ID ,
            PT.DATEQ ,
            PT.DATEW ,
            SUM(NT.QTY) AS QTY ,
            array_to_string(array_agg(NT.VNAME) ,', ') AS VNAME
        FROM
            TABLENAME NT INNER JOIN(
                SELECT
                    AST.ID ,
                    AST.DateQ ,
                    (CASE WHEN AST.DateQ IS NULL THEN AST.DateW ELSE NULL END) AS DateW
                FROM
                    (
                        SELECT
                            ID ,
                            MIN(PDATE) AS DATEQ ,
                            MIN(CASE WHEN pdate IS NULL THEN ndate END) DATEW
                        FROM
                            TABLENAME
                        GROUP BY
                            ID
                    ) AST
            ) PT
                ON NT.ID = PT.ID
            AND NT.PDATE = PT.DATEQ
            OR NT.NDATE = PT.DATEW
        GROUP BY
            NT.ID ,
            PT.DATEQ ,
            PT.DATEW
    ) FO
ORDER BY
    FO.ID

将ID视为项目。

答案 1 :(得分:0)

以下答案假设您使用的是Postgres版本8.4或更高版本,它附带了一个名为ARRAY_AGG()的聚合函数。我使用ARRAY_AGG()为每个VNAME - ITEM群组MIN(DATE)创建以逗号分隔的列表。

SELECT t1.ITEM, t1.DATE, t1.QTY, t1.VNAME
FROM
(
    SELECT t.ITEM, t.DATE AS DATE, SUM(t.QTY) AS QTY, ARRAY_AGG(VNAME) AS VNAME
    FROM
    (
        SELECT t.ITEM, LEAST(t.PDATE, t.NDATE) AS DATE, t.QTY, t.VNAME
        FROM Table t
    ) t
    GROUP BY t.ITEM, t.DATE
) t1
INNER JOIN
(
    SELECT t.ITEM, MIN(LEAST(t.PDATE, t.NDATE)) AS DATE
    FROM Table t
    GROUP BY t.ITEM
) t2
ON t1.ITEM = t2.ITEM AND t1.PDATE = t2.PDATE

<强>解释

第一个查询获取每个QTY - VNAME组合的ITEM总和和PDATE CSV聚合。但是,您只需要每个组中最早日期的聚合。第一个查询加入的第二个查询会过滤掉不需要的组,从而为您提供所需的结果。

由于您使用的是Postgres 8.2,因此您必须定义自己的自定义函数:

CREATE AGGREGATE ARRAY_AGG (anyelement)
(
    sfunc = array_append,
    stype = anyarray,
    initcond = '{}'
);

答案 2 :(得分:0)

Anshul,您的解决方案可以正常工作,但是当您加入桌面两次时会出现性能损失,这会迫使数据库扫描您的表两次。更好的解决方案是使用分析函数,只引用一次表。

以下是一个例子:

    CREATE TABLE anshul
    (
      item character varying,
      pdate date,
      ndate date,
      qty integer,
      vname character varying
    )
    WITH (APPENDONLY=true)
    DISTRIBUTED BY (item);

    INSERT INTO ANSHUL VALUES 
    ('ABC', NULL, '2015-12-31', 10, 'Y JACK SOLLEN'),
    ('HRD', '2016-01-29', '2016-1-8', 5, 'H HARRIS'),
    ('HRD', '2015-09-07', '2015-10-09', 31, 'G JOE'),
    ('HRD', '2015-09-30', '2015-09-07', 28, 'K KAMATH'),
    ('GGT', '2015-12-10', '2015-12-12', 10, 'P QUIK'),
    ('GGT', '2015-12-27', NULL, 20, NULL),
    ('GGT', '2015-12-10', '2016-01-04', 22, 'U RITZ'),
    ('GGT', '2016-01-07', '2016-01-07', 22, 'S SUE DAL'),
    ('OWE', NULL, '2015-12-22', 6, 'J JASON NIT'),
    ('OWE', NULL, '2015-11-05', 2, 'P QUEER'),
    ('OWE', NULL, '2015-11-05', 5, 'K KITTAN');

这是一个查询借用了你已经想到的一些代码。

    SELECT item,
            sum(qty) AS qty,
            array_to_string(array_agg(vname), ',') AS vname
    FROM    (
            SELECT  item, 
                    rank() OVER(PARTITION BY item ORDER BY desired_date) AS rank,
                    qty,
                    vname
            FROM    (SELECT item,
                            qty,
                            vname,
                            CASE WHEN PDATE IS NOT NULL THEN pdate
                            WHEN PDATE IS NULL THEN ndate END AS desired_date
                    FROM anshul
                    ) AS sub1
            ) AS sub
    WHERE sub.rank = 1
    GROUP BY item
    ORDER BY item;

结果:

     item | qty |      vname       
    ------+-----+------------------
     ABC  |  10 | Y JACK SOLLEN
     GGT  |  32 | P QUIK,U RITZ
     HRD  |  31 | G JOE
     OWE  |   7 | K KITTAN,P QUEER