【问题标题】:Oracle: how to query some columns as rowsOracle:如何将某些列查询为行
【发布时间】:2018-09-05 18:10:28
【问题描述】:

我使用 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_VAL 是值 SUM、A、B 和 C 对于 ID=1 and DT=2018-03-03、OLD_VAL 是值 ID=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 和空单元格。如果两个日期中的任何一个都没有数据,我的查询不会返回任何内容。如果该日期没有值,如何使查询返回空单元格?

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

【问题讨论】:

  • 这是一个枢轴问题。阅读:modern-sql.com/use-case/pivot
  • 谢谢。但是如何更轻松地解决两个不同日期的问题?
  • @S.T.第一步 - 取消透视,保留日期,第二步 - 按日期返回分组
  • @Dmitry 有什么小例子吗?

标签: sql oracle plsql oracle-xe


【解决方案1】:

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

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 是 SUM 的值,A B 和 C 对于 ID = 1 and DT = 2018-03-03,OLD_VAL 是 ID = 1 and DT = 2018-03-01 的值

我只是“按原样”对其进行硬编码:

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))
         where id = 1
         )
 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             12           14 
VAL_B             15           16 
VAL_C             17           11 
VAL_SUM           44           41 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多