将多列转置为行
Transpose multiple columns into rows
甲骨文 12c/19c
我继承了以下格式的 table 中的一些数据(请不要打败我为什么有人会以这种格式存储数据等 - 我明白了但必须工作用我所拥有的)。业务需要数月的列转换为行的数据(目标格式如下所示)。
我可以使用下面列出的大联合查询获取我想要的数据,但想看看是否有人有任何 better/efficient 方法来编写它。我也在考虑创建一个夜间作业来将这些数据转换为新格式(或创建一个 mview)。
来源:
ORDER_ID
ORDER_YEAR
QTY_JAN
QTY_FEB
QTY_MAR
QTY_APR
QTY_MAY
QTY_JUN
QTY_JUL
QTY_AUG
QTY_SEP
QTY_OCT
QTY_NOV
QTY_DEC
目标:
ORDER_ID
ORDER_YEAR
ORDER_MONTH
QTY
查询:
select order_id, order_year, '01' order_month, sum(qty_jan) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '02' order_month, sum(qty_feb) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '03' order_month, sum(qty_mar) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '04' order_month, sum(qty_apr) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '05' order_month, sum(qty_may) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '06' order_month, sum(qty_jun) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '07' order_month, sum(qty_jul) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '08' order_month, sum(qty_aug) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '09' order_month, sum(qty_sep) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '10' order_month, sum(qty_oct) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '11' order_month, sum(qty_nov) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '12' order_month, sum(qty_dec) qty
from order_quantity
group by order_id, order_year
;
提前致谢!
最简单的方法是使用 UNPIVOT
运算符,从 Oracle 11.1 开始可用。
我在输出中包含了数量为 NULL 的月份(如果不需要它们,很容易修改)。我还为每个月创建了 两个 列 - 一个用于月份名称,另一个用于月份在一年中的位置。该名称可以在 SELECT
子句中使用(它将显示在输出中),而 "position" 仅在 ORDER BY
子句中使用。
我在 WITH
子句中创建了用于测试的样本数据。当然,这不是现实生活中解决方案的一部分。在主查询中使用实际的 table 和列名。我只包括前三个月 - 您应该很容易更改以包括所有 12 个月。
with
order_quantity (order_id, order_year, qty_jan, qty_feb, qty_mar) as (
select 1001, 2018, 300, 450, 200 from dual union all
select 1001, 2019, 400, 250, null from dual union all
select 1001, 2020, 300, null, 200 from dual union all
select 1002, 2019, 540, 230, null from dual union all
select 1002, 2020, null, 300, 800 from dual
)
select order_id, order_year, order_month, qty
from order_quantity
unpivot include nulls (
qty for (order_month, pos) in ( qty_jan as ('January' , 1)
, qty_feb as ('February', 2)
, qty_mar as ('March' , 3)
)
)
order by order_id, order_year, pos
;
输出:
ORDER_ID ORDER_YEAR ORDER_MONTH QTY
---------- ---------- ----------- ----------
1001 2018 January 300
1001 2018 February 450
1001 2018 March 200
1001 2019 January 400
1001 2019 February 250
1001 2019 March
1001 2020 January 300
1001 2020 February
1001 2020 March 200
1002 2019 January 540
1002 2019 February 230
1002 2019 March
1002 2020 January
1002 2020 February 300
1002 2020 March 800
您可以使用层级查询如下:
SELECT ORDER_ID, ORDER_YEAR,
DECODE(LVL,1,'January',2,'February', ...., 12,'December') AS ORDER_MONTH,
DECODE(LVL,1,QTY_JAN,2,QTY_FEB, ...., 12,QTY_DEC) AS QTY
FROM YOUR_TABLE
CROSS JOIN (SELECT LEVEL AS LVL FROM DUAL CONNECT BY LEVEL <= 12);
甲骨文 12c/19c
我继承了以下格式的 table 中的一些数据(请不要打败我为什么有人会以这种格式存储数据等 - 我明白了但必须工作用我所拥有的)。业务需要数月的列转换为行的数据(目标格式如下所示)。
我可以使用下面列出的大联合查询获取我想要的数据,但想看看是否有人有任何 better/efficient 方法来编写它。我也在考虑创建一个夜间作业来将这些数据转换为新格式(或创建一个 mview)。
来源:
ORDER_ID
ORDER_YEAR
QTY_JAN
QTY_FEB
QTY_MAR
QTY_APR
QTY_MAY
QTY_JUN
QTY_JUL
QTY_AUG
QTY_SEP
QTY_OCT
QTY_NOV
QTY_DEC
目标:
ORDER_ID
ORDER_YEAR
ORDER_MONTH
QTY
查询:
select order_id, order_year, '01' order_month, sum(qty_jan) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '02' order_month, sum(qty_feb) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '03' order_month, sum(qty_mar) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '04' order_month, sum(qty_apr) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '05' order_month, sum(qty_may) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '06' order_month, sum(qty_jun) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '07' order_month, sum(qty_jul) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '08' order_month, sum(qty_aug) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '09' order_month, sum(qty_sep) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '10' order_month, sum(qty_oct) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '11' order_month, sum(qty_nov) qty
from order_quantity
group by order_id, order_year
union
select order_id, order_year, '12' order_month, sum(qty_dec) qty
from order_quantity
group by order_id, order_year
;
提前致谢!
最简单的方法是使用 UNPIVOT
运算符,从 Oracle 11.1 开始可用。
我在输出中包含了数量为 NULL 的月份(如果不需要它们,很容易修改)。我还为每个月创建了 两个 列 - 一个用于月份名称,另一个用于月份在一年中的位置。该名称可以在 SELECT
子句中使用(它将显示在输出中),而 "position" 仅在 ORDER BY
子句中使用。
我在 WITH
子句中创建了用于测试的样本数据。当然,这不是现实生活中解决方案的一部分。在主查询中使用实际的 table 和列名。我只包括前三个月 - 您应该很容易更改以包括所有 12 个月。
with
order_quantity (order_id, order_year, qty_jan, qty_feb, qty_mar) as (
select 1001, 2018, 300, 450, 200 from dual union all
select 1001, 2019, 400, 250, null from dual union all
select 1001, 2020, 300, null, 200 from dual union all
select 1002, 2019, 540, 230, null from dual union all
select 1002, 2020, null, 300, 800 from dual
)
select order_id, order_year, order_month, qty
from order_quantity
unpivot include nulls (
qty for (order_month, pos) in ( qty_jan as ('January' , 1)
, qty_feb as ('February', 2)
, qty_mar as ('March' , 3)
)
)
order by order_id, order_year, pos
;
输出:
ORDER_ID ORDER_YEAR ORDER_MONTH QTY
---------- ---------- ----------- ----------
1001 2018 January 300
1001 2018 February 450
1001 2018 March 200
1001 2019 January 400
1001 2019 February 250
1001 2019 March
1001 2020 January 300
1001 2020 February
1001 2020 March 200
1002 2019 January 540
1002 2019 February 230
1002 2019 March
1002 2020 January
1002 2020 February 300
1002 2020 March 800
您可以使用层级查询如下:
SELECT ORDER_ID, ORDER_YEAR,
DECODE(LVL,1,'January',2,'February', ...., 12,'December') AS ORDER_MONTH,
DECODE(LVL,1,QTY_JAN,2,QTY_FEB, ...., 12,QTY_DEC) AS QTY
FROM YOUR_TABLE
CROSS JOIN (SELECT LEVEL AS LVL FROM DUAL CONNECT BY LEVEL <= 12);