如何在不多次连接的情况下旋转表

时间:2018-12-12 03:06:00

标签: postgresql join pivot

我有一个表ctrlr_err_hist,该表包含以下列:

visit_id
err_cd
err_name
m1_err_cnt
m2_err_cnt

err_cd的可能值为0、1、3。

现在,我想编写一个查询,以使同一行上的visit_id具有不同的错误。例如,如果表具有以下记录:

visit_id    err_cd    err_name    m1_err_cnt
    1         0       encoder        500
    1         3       breakout       212
    2         1       obclose         45
    2         3       breakout       143

此表将与tchn_visit_hist上的visit_id表联接。如果没有任何err_cd的数据,它将为null。最终结果将如下所示:

visit_id    encoder_cnt     breakout_cnt   obclose_cnt
    1         500              212           null
    2         null             143            45

我编写了以下查询,该查询将同一张表连接了三次

select t.visit_id, t.door_id, enc.encoder_cnt, brk.breakout_cnt, ob.ob_close_cnt
from tchn_visit_hist t
left join (
    select m1_err_cnt as encoder_cnt, visit_id
    from ctrlr_err_hist  
    where err_cd = '0' 
) as enc 
on t.visit_id = enc.visit_id
left join (
    select m1_err_cnt as breakout_cnt, visit_id
    from ctrlr_err_hist  
    where err_cd = '3'
) as brk 
on t.visit_id = brk.visit_id
left join (
    select m1_err_cnt as ob_close_cnt, visit_id
    from ctrlr_err_hist  
    where err_cd = '1'
) as ob 
on t.visit_id = ob.visit_id

我想知道是否有更好,更有效的方法来完成此任务。

2 个答案:

答案 0 :(得分:1)

demo: db<>fiddle

通过这种方式可以实现一个简单的枢纽:

SELECT
    visit_id,
    MIN(m1_err_cnt) FILTER (WHERE err_cd = 0) as encoder_cnt,
    MIN(m1_err_cnt) FILTER (WHERE err_cd = 1) as ob_close_cnt,
    MIN(m1_err_cnt) FILTER (WHERE err_cd = 3) as breakout_cnt
FROM
    ctrlr_err_hist
GROUP BY visit_id

visit_id分组并聚合您感兴趣的列。FILTER子句过滤应聚合的元素。在这种情况下,汇总仅适用于一个特殊的err_cd

请注意,您必须使用聚合功能。这是因为理论上您可以使用(visit_id = 1, err_cd = 0)包含两行或更多行。在这种情况下,您必须决定要使用多个值(SUMMINMAXAVG等)来决定要做什么。因为您的示例包含不同的行,所以没关系。

此后,您只需加入tchn_visit_hist表:

SELECT t.visit_id, t.door_id, c.encoder_cnt, c.breakout_cnt, c.ob_close_cnt
FROM (
   SELECT
       visit_id,
       MIN(m1_err_cnt) FILTER (WHERE err_cd = 0) as encoder_cnt,
       MIN(m1_err_cnt) FILTER (WHERE err_cd = 1) as ob_close_cnt,
       MIN(m1_err_cnt) FILTER (WHERE err_cd = 3) as breakout_cnt
   FROM
       ctrlr_err_hist
   GROUP BY visit_id
) c
JOIN tchn_visit_hist t
ON (t.visit_id = c.visit_id)

答案 1 :(得分:0)

您可以在Join

中设置条件
select 
  a.visit_id, 
  max(b.encoder_cnt) as encoder_cnt, 
  max(b.breakout_cnt) as breakout_cnt, 
  max(b.ob_close_cnt) as ob_close_cnt
from 
  tchn_visit_hist a
  left join(select 
              case when err_cd = '0' then m1_err_cnt end as encoder_cnt, 
              case when err_cd = '3' then m1_err_cnt end as breakout_cnt,
              case when err_cd = '1' then m1_err_cnt end as ob_close_cnt,
              case when err_cd = '0' then visit_id end as encoder_visit, 
              case when err_cd = '3' then visit_id end as breakout_visit,
              case when err_cd = '1' then visit_id end as ob_close_visit
            from
              tchn_visit_hist) b on case 
                                      when a.err_cd = '0' then a.visit_id = encoder_visit
                                      when a.err_cd = '3' then a.visit_id = breakout_visit
                                      when a.err_cd = '1' then a.visit_id = ob_close_visit
                                     end
group by
   a.visit_id
order by
   a.visit_id asc

Demo