是否有可能在Oracle中有条件地透视不同数据类型的列?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否有可能在Oracle中有条件地透视不同数据类型的列?相关的知识,希望对你有一定的参考价值。

使用Oracle 12c。我有一个查询,该查询返回我需要的所有数据,但是它分为多行。我正在尝试使用数据透视表将n行中的数据合并为1行,将2列中的n个唯一值集转换为n列,有条件地从一组列中选择哪一列对n个转置后的每一个使用值列。我正在努力找出这是否可行或无法实现。

以下是查询返回内容的简化示例:

| ID | Inst_Created | Inst_Modified | Inst_Group | Inst_Prop | VAL_INT | VAL_REAL | VAL_STR |
+----+--------------+---------------+------------+-----------+---------+----------+---------+
| 01 |   1571954537 |    1571954537 |  GenGroup1 |  IntProp1 |       0 |   (null) |  (null) |
| 01 |   1571954537 |    1571954537 |  GenGroup1 | RealProp2 |  (null) | 12.34567 |  (null) |
| 01 |   1571954537 |    1571954537 |  GenGroup1 | RealProp3 |  (null) | 123.4567 |  (null) |
| 01 |   1571954537 |    1571954537 |  GenGroup1 |  StrProp4 |  (null) |   (null) | dirpath |
| 01 |   1571954537 |    1577754537 |  GenGroup2 |  IntProp5 |    1337 |   (null) |  (null) |
| 01 |   1571954537 |    1577754537 |  GenGroup2 | RealProp6 |  (null) |    13.37 |  (null) |
| 01 |   1570054537 |    1570854537 |  GenGroup3 |  StrProp7 |  (null) |   (null) | testing |
| 01 |   1570054537 |    1570854537 |  GenGroup3 |  StrProp8 |  (null) |   (null) |  valid  |
| 02 |   1571954540 |    1571954540 |  GenGroup1 |  IntProp1 |       1 |   (null) |  (null) |
| 02 |   1571954540 |    1571954540 |  GenGroup1 | RealProp2 |  (null) | 12.34568 |  (null) |
| 02 |   1571954540 |    1571954540 |  GenGroup1 | RealProp3 |  (null) | 123.4568 |  (null) |
| 02 |   1571954540 |    1571954540 |  GenGroup1 |  StrProp4 |  (null) |   (null) | dirpat2 |
| 02 |   1571954540 |    1577754540 |  GenGroup2 |  IntProp5 |    1338 |   (null) |  (null) |
| 02 |   1571954540 |    1577754540 |  GenGroup2 | RealProp6 |  (null) |    13.38 |  (null) |
| 02 |   1570054540 |    1570854540 |  GenGroup3 |  StrProp7 |  (null) |   (null) | testin2 |
| 02 |   1570054540 |    1570854540 |  GenGroup3 |  StrProp8 |  (null) |   (null) |  valid2 |
+----+--------------+---------------+------------+-----------+---------+----------+---------+

Inst_Created和Inst_Modified列是模拟纪元时间戳。 VAL_INT,VAL_REAL和VAL_STR列分别是NUMBER(38,0),FLOAT和VARCHAR2(1024)数据类型。对于任何给定的行,只有三列VAL_ *列为非空;您可以通过Inst_Group,Inst_Prop列知道这是哪三个。

以下是我试图通过使用数据透视表进行简化的示例:

| ID | Earliest_Created | Latest_Modified | G1P1_Int | G1P2_Real | G1P3_Real | G1P4_Str | G2P5_Int | G2P6_Real | G3P7_Str | G3P8_Str |
+----+------------------+-----------------+----------+-----------+-----------+----------+----------+-----------+----------+----------+
| 01 |       1570054537 |      1577754537 |        0 |  12.34567 |  123.4567 |  dirpath |     1337 |     13.37 |  testing |    valid |
| 02 |       1570054540 |      1579954540 |        1 |  12.34568 |  123.4568 |  dirpat2 |     1338 |     13.38 |  testin2 |   valid2 |
+----+------------------+-----------------+----------+-----------+-----------+----------+----------+-----------+----------+----------+

我已经弄清楚了如何在重命名列的同时使用ivot_for_clause和pivot_in_clause子句将(Inst_Group,Inst_Prop)值转换为列。我正在努力弄清的是如何将值放入转置的列中,它们是正确的数据类型。

我以前曾尝试在查询中使用LISTAGG函数,将所有VAL_ *值都强制转换为varchar2,因此VAL值只有一列。由于尝试将每个转置的列设置为正确的原始数据类型时遇到问题,并且由于性能下降,所有这些似乎都在造成该问题,因此我放弃了该方法。

答案

您可以使用conditional aggreagation实现它:

Select ID, EARLIEST_CREATED, LATEST_MODIFIED,
MAX(CASE WHEN INST_GROUP = 'GenGroup1' and INST_PROP1 = 'IntProp1' THEN VAL_INT END) AS G1P1_INT,
MAX(CASE WHEN INST_GROUP = 'GenGroup1' and INST_PROP1 = 'RealProp2' THEN VAL_REAL END) AS G1P2_REAL,
...
..
.
From your_table
Group by ID, EARLIEST_CREATED, LATEST_MODIFIED;

干杯!

以上是关于是否有可能在Oracle中有条件地透视不同数据类型的列?的主要内容,如果未能解决你的问题,请参考以下文章

oracle sql中的动态数据透视

如何在 oracle 中有条件地执行 DDL?

在每次迭代中有条件地使用不同数量的项目

oracle SQL查询中,如何在where中用条件语句,判断不同情况,追加不同的And条件?

将数据透视到新的列名 - Oracle SQL

在 oracle11g系统中 约束的类型都有哪些