轮换表进行同比比较

Wil*_*son 1 oracle pivot reporting oracle-12c

我有一张road_insp桌子:

create table road_insp
(
    insp_id int,
    road_id int,
    insp_year int,
    condition number(10,2)
);

insert into road_insp (insp_id, road_id, insp_year, condition) values ( 1, 100, 2009, 5);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 2, 100, 2011, 3);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 3, 102, 2009, 9);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 4, 102, 2010, 7);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 5, 102, 2013, 5);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 6, 103, 2009, 10);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 7, 103, 2011, 8);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 8, 103, 2012, 6);
insert into road_insp (insp_id, road_id, insp_year, condition) values ( 9, 103, 2013, 4);

commit;

select
    insp_id,
    road_id,
    insp_year,
    condition
from 
    road_insp;

   INSP_ID    ROAD_ID  INSP_YEAR  CONDITION
---------- ---------- ---------- ----------
         1        100       2009          5
         2        100       2011          3
         3        102       2009          9
         4        102       2010          7
         5        102       2013          5
         6        103       2009         10
         7        103       2011          8
         8        103       2012          6
         9        103       2013          4
Run Code Online (Sandbox Code Playgroud)

我想逐年比较道路状况。

我可以通过加入每年的子选择来做到这一点:

select
    a.road_id,
    y09.condition condition_2009,
    y10.condition condition_2010,
    y11.condition condition_2011,
    y12.condition condition_2012,
    y13.condition condition_2013
from
    road_insp a
left join
    (select 
        road_id,
        condition
    from
        road_insp
    where
        insp_year = 2009
    ) y09
    on a.road_id = y09.road_id
left join
    (select 
        road_id,
        condition
    from
        road_insp
    where
        insp_year = 2010
    ) y10
    on a.road_id = y10.road_id
left join
    (select 
        road_id,
        condition
    from
        road_insp
    where
        insp_year = 2011
    ) y11
    on a.road_id = y11.road_id
left join
    (select 
        road_id,
        condition
    from
        road_insp
    where
        insp_year = 2012
    ) y12
    on a.road_id = y12.road_id
left join
    (select 
        road_id,
        condition
    from
        road_insp
    where
        insp_year = 2013
    ) y13
    on a.road_id = y13.road_id
group by
    a.road_id,
    y09.condition,
    y10.condition,
    y11.condition,
    y12.condition,
    y13.condition
order by
    road_id
Run Code Online (Sandbox Code Playgroud)
   ROAD_ID CONDITION_2009 CONDITION_2010 CONDITION_2011 CONDITION_2012 CONDITION_2013
---------- -------------- -------------- -------------- -------------- --------------
       100              5                             3                              
       102              9              7                                            5
       103             10                             8              6              4
Run Code Online (Sandbox Code Playgroud)

但是,这种方法相当繁琐。是否有更简洁的方法来旋转表格以进行年度比较?

And*_*y M 7

是的,您的场景存在更简洁的旋转方法。

选项1

例如,您可以使用PIVOT 运算符

SELECT
  *
FROM
  (
    SELECT
      road_id,
      insp_year,
      condition
    FROM
      road_insp
  ) derived
  PIVOT
  (
    MAX(condition)
    FOR insp_year IN
    (
      2009 AS condition_2009,
      2010 AS condition_2010,
      2011 AS condition_2011,
      2012 AS condition_2012,
      2013 AS condition_2013
    )
  )
;
Run Code Online (Sandbox Code Playgroud)

PIVOT 意味着分组,这就是为什么您可以看到 MAX() 聚合函数应用于condition而不是简单地使用condition.

隐式分组也是您在应用 PIVOT 运算符之前经常需要使用派生表的原因:所有在 PIVOT 子句中未提及的列实际上都参与了分组,因此您需要排除那些不应该是分组条件的列。对于您的特定示例,您确实需要一个派生表,因为您需要排除insp_id.

选项 2

作为 PIVOT 运算符的替代方法,您可以尝试使用老式的条件聚合方法:

SELECT
  road_id,
  MAX(DECODE(insp_year, 2009, condition, NULL)) AS condition_2009,
  MAX(DECODE(insp_year, 2010, condition, NULL)) AS condition_2010,
  MAX(DECODE(insp_year, 2011, condition, NULL)) AS condition_2011,
  MAX(DECODE(insp_year, 2012, condition, NULL)) AS condition_2012,
  MAX(DECODE(insp_year, 2013, condition, NULL)) AS condition_2013
FROM
  road_insp
GROUP BY
  road_id
;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,不需要派生表,因为可以在 GROUP BY 子句中显式指定要分组的列。

—————————

两种方法都产生相同的输出,与您的连接方法生成的输出相同,如dbfiddle.uk 上的演示所示