如何对具有常量/缺失列的多列使用 unpivot?

Posted

技术标签:

【中文标题】如何对具有常量/缺失列的多列使用 unpivot?【英文标题】:How to use unpivot for multiple columns with constants/missing column? 【发布时间】:2019-09-18 11:19:42 【问题描述】:

我正在尝试使用 UNPIVOT 以避免多个联合的老式方式

这样做的理由是我正在收集一些数据(实验室测试、结果、单位……)我想以适当的方式显示以供审查

例如,假设我的原始数据如下所示:

ID, TESTA, RESULTA, UNITA, TESTB, RESULTB, UNITB, OTHER_UNITB
1,  'T1',  10,      1,     'T2',  2.5,          , 'kg',
2,  'T1',  15,      1,     'T2',  1.5,     1,         ,
3,  'T1',    ,       ,     'T2',  1,       1,

以下内容完美运行:对于每个 ID,我在每个测试中检索 1 行,并带有相应的结果和单位:

select  id,
        property as test_code,
        decode(property, 'T1', 'Test 01', 'T2', 'Test 02', 'Unknown test') as test_name,
        result,
        unit
from    my_table
unpivot include nulls
        (
            (result, unit)
            for property in (
              (resulta, unita) as 'T1',
              (resultb, unitb) as 'T2'
            )
        )
;

但是,当我尝试检索特定于测试“T2”的“其他单元”时出现问题(请记住,这是一个示例,我有很多测试,差不多 20 个)

我试过了:

select  id,
        property as test_code,
        decode(property, 'T1', 'Test 01', 'T2', 'Test 02', 'Unknown test') as test_name,
        result,
        unit,
        other_unit
from    my_table
unpivot include nulls
        (
            (result, unit, other_unit)
            for property in (
              (resulta, unita, null) as 'T1',
              (resultb, unitb, other_unitb) as 'T2'
            )
        )
;

对于我放在 unpivot 中的“null”语句,它失败并显示“无效标识符”消息。

我也尝试以这种方式使用常量:

....
unpivot include nulls
        (
            (result, unit, other_unit)
            for property in (
              (resulta, unita, 0) as 'T1',
              (resultb, unitb, other_unitb) as 'T2'
            )
        )
;

这也失败了。

我被困在这里,无法弄清楚如何在不重写所有内容的情况下解决这个问题,这是一个联合声明列表 - 我想不惜一切代价避免,因为维护起来非常复杂:

select resulta as result,
       unita as unit,
       null as other_unit
from   my_table
union
select resultb as result,
       unitb as unit,
       other_unitbas other_unit
from   my_table
union
...

我还找到了一个丑陋的解决方案:

select  id,
        property as test_code,
        decode(property, 'T1', 'Test 01', 'T2', 'Test 02', 'Unknown test') as test_name,
        result,
        unit,
        other_unit
from    (
            select  m.*,
                    null as null_item
            from    my_table m
        )

unpivot include nulls
        (
            (result, unit, other_unit)
            for property in (
              (resulta, unita, null_item) as 'T1',
              (resultb, unitb, other_unitb) as 'T2'
            )
        )
;

但老实说,我很惭愧这样做!

提前感谢您的支持

【问题讨论】:

你为什么对“丑陋”的解决方案感到羞耻?您生成的附加列已适当命名,并且查询很清楚它的作用;没有什么可羞耻的,它不丑,你应该使用它。 我主要关心的是我必须为常量值创建尽可能多的“伪列”。那行得通,我只是想知道是否有办法在 unpivot 子句中写入默认值/空值 【参考方案1】:

您可以查看unpivot clause 的语法图。

https://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10002.htm#CHDJBHHI

它清楚地表明只有columns 可能出现在列表中(不是文字或表达式)。

您可能需要在内联视图中创建与所需的不同常量值一样多的常量列。

作为替代方法,您可以使用老式方法:交叉连接 + 解码。

select id,
       test_code,
       decode(test_code, 'T1', 'Test 01', 'T2', 'Test 02', 'Unknown test') as test_name,
       decode(test_code, 'T1', resulta, 'T2', resultb) result,
       decode(test_code, 'T1', unita, 'T2', unitb) unit,
       decode(test_code, 'T2', other_unitb) other_unit
  from my_table t,
       (select 'T' || level test_code from dual connect by level <= 2)

【讨论】:

谢谢,至少这澄清了我的情况不能做什么!

以上是关于如何对具有常量/缺失列的多列使用 unpivot?的主要内容,如果未能解决你的问题,请参考以下文章

PIVOT/UNPIVOT 多行多列

SQL unpivot 多列

在不确定数量的列上进行 UNPIVOT

SQL Unpivot 多列数据

Pandas使用split函数基于指定分隔符拆分数据列的内容为列表设置expand参数将拆分结果列表内容转化为多列dataframe(不设置参数n则列表长度不同较短的列表会出现缺失值)

多列,多表列到行 unpivot