Oracle:如何将某些列作为行查询

时间:2018-03-27 10:57:52

标签: sql oracle plsql oracle-xe

我使用Oracle 11 XE并拥有下表:

CREATE TABLE tst
(val_a                          NUMBER,
val_b                          NUMBER,
val_c                          NUMBER,
val_sum                        NUMBER,
id                             NUMBER,
dt                             DATE)

一些示例数据:

INSERT INTO tst 
VALUES(12,15,17,44,1,TO_DATE('2018-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'));
INSERT INTO tst 
VALUES(14,16,11,41,1,TO_DATE('2018-03-03 00:00:00', 'YYYY-MM-DD HH24:MI:SS'));
INSERT INTO tst 
VALUES(6,7,8,21,2,TO_DATE('2018-03-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS'));

我需要指定两个日期并获得以下结果(NEW_VALSUMABC ID=1 and DT=2018-03-03 },OLD_VALID=1 and DT=2018-03-01)的值:

ID  X   NEW_VAL    OLD_VAL                                
--- --- --------- --------
1   SUM        41        44
    A          14        12
    B          16        15
    C          11        17

以下是我已实施的查询:

select id, x, new_val, old_val from(

select tst_new.id id0, 1, tst_new.id, 'SUM' x, tst_new.val_sum new_val, tst_old.val_sum old_val from tst tst_new, 
(select * from tst where dt=to_date('01.03.2018', 'dd.mm.yyyy')) tst_old
where tst_new.dt=to_date('03.03.2018', 'dd.mm.yyyy') and tst_new.id = tst_old.id and tst_new.id = 1

UNION ALL

select tst_new.id, 2, null, 'A',  tst_new.val_a, tst_old.val_a from tst tst_new, 
(select * from tst where dt=to_date('01.03.2018', 'dd.mm.yyyy')) tst_old
where tst_new.dt=to_date('03.03.2018', 'dd.mm.yyyy')  and tst_new.id = tst_old.id and tst_new.id = 1

UNION ALL

select tst_new.id, 3, null, 'B', tst_new.val_b, tst_old.val_b from tst tst_new, 
(select * from tst where dt=to_date('01.03.2018', 'dd.mm.yyyy')) tst_old
where tst_new.dt=to_date('03.03.2018', 'dd.mm.yyyy') and tst_new.id = tst_old.id and tst_new.id = 1

UNION ALL

select tst_new.id, 4, null, 'C', tst_new.val_c, tst_old.val_c from tst tst_new, 
(select * from tst where dt=to_date('01.03.2018', 'dd.mm.yyyy')) tst_old
where tst_new.dt=to_date('03.03.2018', 'dd.mm.yyyy') and tst_new.id = tst_old.id and tst_new.id = 1

order by 1, 2
)

它确实提供了所需的结果,但看起来很糟糕。有没有办法让这个结果更容易?

此外,如果特定日期没有数据,结果应包含ID,X和空单元格。如果两个日期中没有任何数据,我的查询只返回任何内容。如果该日期没有值,如何使查询返回空单元格?

更新:我已经看过使用数据透视的示例,但在我的情况下,不仅需要列作为行,还要查询同一表中不同日期的数据。此外,如果没有特定日期的日期,也不清楚如何获取空单元格。

1 个答案:

答案 0 :(得分:1)

内部子查询是unpivot的结果,外部 - 向后旋转:

select *
  from (select to_char(dt, 'dd.mm.yyyy') dt, vals, dt_vals from tst
        unpivot (dt_vals for vals in (val_a, val_b, val_c, val_sum)))
 pivot (sum(dt_vals) for dt in ('01.03.2018', '03.03.2018'))
 order by 1

VALS    '01.03.2018' '03.03.2018'
------- ------------ ------------
VAL_A             18           14 
VAL_B             22           16 
VAL_C             25           11 
VAL_SUM           65           41 

接下来,您需要指定如何过滤这些值的规则:

  

NEW_VAL是值SUMA BC ID = 1 and DT = 2018-03-03OLD_VAL是{{1}的值}}

我只是硬编码了#34;按照":

ID = 1 and DT = 2018-03-01