将聚合列合并到单个表中

时间:2016-05-06 23:39:20

标签: sql postgresql join aggregate

我有两张桌子。一个表按月显示入库库存,另一个表按月显示出库存。基本上我想在一个表上按月显示入站和出站库存。

1

select 
warehouses.id,
count(pallets.id),
to_char(pallets.in_date, 'FMMonth-YY') as in_month

from pallets

inner join reservations
on pallets.reservation_id = reservations.id

inner join warehouses
on reservations.warehouse_id = warehouses.id

where pallets.in_date is not null

group by 
warehouses.id,
date_part('month', pallets.in_date),
date_part('year', pallets.in_date),
to_char(pallets.in_date, 'FMMonth-YY')

order by 
date_part('year', pallets.in_date),
date_part('month', pallets.in_date)

和2.

select 
warehouses.id as id,
count(pallets.id),
to_char(pallets.out_date, 'FMMonth-YY') as out_month

from pallets

inner join reservations
on pallets.reservation_id = reservations.id

inner join warehouses
on reservations.warehouse_id = warehouses.id

where pallets.in_date is not null and pallets.out_date is not null

group by 
date_part('month', pallets.out_date),
date_part('year', pallets.out_date),
to_char(pallets.out_date, 'FMMonth-YY'),
warehouses.id

order by 
date_part('year', pallets.out_date),
date_part('month', pallets.out_date)

我尝试使用子查询加入第二个表,但返回的值都是各种各样的。

select 
warehouses.id,
count(pallets.id),
count(out.out),
to_char(pallets.in_date, 'FMMonth-YY') as in_month

from pallets

inner join reservations
on pallets.reservation_id = reservations.id

inner join warehouses
on reservations.warehouse_id = warehouses.id

full join (select 
warehouses.id as id,
count(pallets.id) as out,
to_char(pallets.out_date, 'FMMonth-YY') as out_month

from pallets

inner join reservations
on pallets.reservation_id = reservations.id

inner join warehouses
on reservations.warehouse_id = warehouses.id

where pallets.in_date is not null and pallets.out_date is not null

group by 
date_part('month', pallets.out_date),
date_part('year', pallets.out_date),
to_char(pallets.out_date, 'FMMonth-YY'),
warehouses.id

order by 
date_part('year', pallets.out_date),
date_part('month', pallets.out_date)) as out
on out.id=warehouses.id

where pallets.in_date is not null

group by 
warehouses.id,
date_part('month', pallets.in_date),
date_part('year', pallets.in_date),
to_char(pallets.in_date, 'FMMonth-YY')

order by 
date_part('year', pallets.in_date),
date_part('month', pallets.in_date)

我有什么想法可以做到这一点吗?

3 个答案:

答案 0 :(得分:0)

WITH
    inbound AS (
        SELECT 
            warehouses.id,
            count(pallets.id),
            to_char(pallets.in_date, 'FMMonth-YY') AS in_month
        FROM
            pallets
            INNER JOIN
            reservations
                ON pallets.reservation_id = reservations.id
            INNER JOIN
            warehouses
                ON reservations.warehouse_id = warehouses.id
        WHERE pallets.in_date is not null
        GROUP BY
            warehouses.id,
            date_part('month', pallets.in_date),
            date_part('year', pallets.in_date),
            to_char(pallets.in_date, 'FMMonth-YY')),
    outbound AS (
        SELECT
            warehouses.id as id,
            count(pallets.id),
            to_char(pallets.out_date, 'FMMonth-YY') AS out_month
        FROM
            pallets
            INNER JOIN
            reservations
                ON pallets.reservation_id = reservations.id
            INNER JOIN
            warehouses
                ON reservations.warehouse_id = warehouses.id
        WHERE pallets.in_date is not null and pallets.out_date is not null
        GROUP BY
            date_part('month', pallets.out_date),
            date_part('year', pallets.out_date),
            to_char(pallets.out_date, 'FMMonth-YY'),
            warehouses.id)
SELECT
    coalesce(a.id, b.id) AS warehouse_id,
    coalesce(a.in_month, b.out_month) AS which_month,
    coalesce(a.count, 0) AS inbound,
    coalesce(b.count, 0) AS outbound
FROM
    inbound AS a
    FULL JOIN
    outbound AS b ON a.id = b.id AND a.in_month = b.out_month;

答案 1 :(得分:0)

实现此目的的一种方法是使用现有查询(稍作修改)作为内联视图。并使用FULL OUTER JOIN操作来组合它们。

没有给出Warehouse_id是否为NULL的指示,因此代替相等比较,下面的示例使用“null-safe”比较,因此warehouse_id的NULL值将通过join操作“匹配”。 / p>

而不是使用DATE_PART和DATE_FORMAT,只需在内联视图中使用DATE_TRUNC函数。这样可以更容易地进行连接,并且可以使用该值来排序结果(如果这很重要)并将月份作为格式化字符串返回。如果将其存储为表,我将存储日期值,而不是格式化的字符串。

我也更喜欢使用短表别名来限定列引用。

          select coalesce(i.warehouse_id,o.warehouse_id)                 as warehouse_id
               , coalesce(i.in_month,o.out_month)                        as month_
               , to_char(coalesce(i.in_month,o.out_month), 'FMMonth-YY') as month_yy
               , coalesce(i.cnt,0)                                       as in_count
               , coalesce(o.cnt,0)                                       as out_count
            from ( select w.id                              as warehouse_id
                        , date_trunc('month', p.in_date)    as in_month
                        , count(p.id)                       as cnt 
                     from pallets p
                     join reservations r
                       on r.id = p.reservation_id
                     join warehouses w
                       on w.id = r.warehouse_id
                    where p.in_date is not null
                    group by w.id
                           , date_trunc('month', p.in_date)
                 ) i
            full
            join ( select w.id                              as warehouse_id
                        , date_trunc('month', p.out_date)   as out_month
                        , count(p.id)                       as cnt
                     from pallets p
                     join reservations r
                       on r.id = p.reservation_id
                     join warehouses w
                       on w.id = r.warehouse_id
                    where p.in_date is not null
                      and p.out_date is not null
                    group
                       by w.id
                        , date_trunc('month', p.out_date)
                 ) o
              on o.warehouse_id is not distinct from i.warehouse_id
             and o.out_month = i.in_month
           order by coalesce(i.warehouse_id,o.warehouse_id)
                  , coalesce(i.in_month,o.out_month)

我个人的偏好是使用大写字母来表示函数,关键字和保留字。

          SELECT COALESCE(i.warehouse_id,o.warehouse_id)                AS warehouse_id
               , COALESCE(i.in_month,o.out_month)                        AS month_
               , TO_CHAR(COALESCE(I.IN_MONTH,O.OUT_MONTH), 'FMMonth-YY') AS month_yy
               , COALESCE(i.cnt,0)                                       AS in_count
               , COALESCE(o.cnt,0)                                       AS out_count
            FROM ( SELECT w.id                              AS warehouse_id
                        , DATE_TRUNC('month', p.in_date)    AS in_month
                        , COUNT(p.id)                       AS cnt 
                     FROM pallets p
                     JOIN reservations r
                       ON r.id = p.reservation_id
                     JOIN warehouses w
                       ON w.id = r.warehouse_id
                    WHERE p.in_date IS NOT NULL
                    GROUP BY w.id
                           , DATE_TRUNC('month', p.in_date)
                 ) i
            FULL
            JOIN ( SELECT w.id                              AS warehouse_id
                        , DATE_TRUNC('month', p.out_date)   AS out_month
                        , COUNT(p.id)                       AS cnt
                     FROM pallets p
                     JOIN reservations r
                       ON r.id = p.reservation_id
                     JOIN warehouses w
                       ON w.id = r.warehouse_id
                    WHERE p.in_date IS NOT NULL
                      AND p.out_date IS NOT NULL
                    GROUP BY w.id
                           , DATE_TRUNC('month', p.out_date)
                 ) o
              ON o.warehouse_id IS NOT DISTINCT FROM i.warehouse_id
             AND o.out_month = i.in_month
           ORDER BY COALESCE(i.warehouse_id,o.warehouse_id)
                  , COALESCE(i.in_month,o.out_month)

答案 2 :(得分:0)

为简化查询,我认为您可以这样欺骗COUNT:

注意:WIT​​H子句内的查询对您来说已经足够了。但是我添加了WITH子句以便能够建立联合。这取决于你想要输出的内容。

WITH computed_warehouses AS (
  -- Maybe this single select (inside the WITH is what you want)
  select 
    warehouses.id,
    count(pallets.id) as nb_in_date,
    count(pallets.id||pallets.out_date) as nb_out_date,
    -- Edit: count(pallets.out_date) as nb_out_date should also work and it's simpler
    to_char(pallets.in_date,  'FMMonth-YY') as in_month,
    to_char(pallets.out_date, 'FMMonth-YY') as out_month

 from pallets

 inner join reservations
         on pallets.reservation_id = reservations.id

 inner join warehouses
         on reservations.warehouse_id = warehouses.id

 where pallets.in_date is not null

 group by 
       warehouses.id,
       date_part('month', pallets.in_date),
       date_part('year', pallets.in_date),
       to_char(pallets.in_date, 'FMMonth-YY'),
       to_char(pallets.out_date, 'FMMonth-YY')

 order by 
       date_part('year', pallets.in_date),
       date_part('month', pallets.in_date)
)

-- If you wanna make a union
(
  SELECT
    t.id AS warehouse_id,
    t.in_month AS which_month,
    t.nb_in_date AS inbound,
    NULL AS outbound

   FROM computed_warehouses t
)
UNION ALL
(
  SELECT
    t.id AS warehouse_id,
    t.out_month AS which_month,
    NULL AS inbound,
    t.nb_out_date AS outbound

   FROM computed_warehouses t

  WHERE t.nb_out_date IS NOT NULL
    AND t.nb_out_date > 0
)

count(pallets.id || pallets.out_date)有点棘手,只计算out_date不为空的托盘。它可以很好地工作,因为 id out_date 属于同一个表,因为当空值时count不会递增。

修改:   count(pallets.out_date) as nb_out_date应该也可以工作,更简单,也应该更快