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

Posted

技术标签:

【中文标题】在不确定数量的列上进行 UNPIVOT【英文标题】:UNPIVOT on an indeterminate number of columns 【发布时间】:2013-02-26 21:55:02 【问题描述】:

如何编写一个查询,将始终具有 1 行和多列的表取消透视到具有 2 列的结果集:column_name 和 value。我知道表格的底层结构是真正的问题所在,但我无法改变这一点。此查询也必须不知道所述表中的名称和/或列数,因为经常添加列(再次,我知道,糟糕的设计,无法更改它),我不想要每次添加新列时都必须更新查询。我已经能够使用 unpivot 完成一些接近的事情,但是该查询需要对列名进行硬编码。

这可能吗?

Oracle 11gR2

【问题讨论】:

是否需要在查询中解决?不能通过应用语言来操作吗? @Mt.Schneiders 理想情况下是一个查询,因为我想根据该查询创建一个视图。 【参考方案1】:

听起来您想取消透视表(透视需要从多行 2 列变为 1 行多列)。您很可能需要使用动态 SQL 来生成查询,然后使用 DBMS_SQL 包(或可能是 EXECUTE IMMEDIATE)来执行它。您还应该能够构建一个执行反透视的流水线表函数。您还需要在流水线表函数中使用动态 SQL,但它可能会减少代码。不过,我希望使用 UNPIVOT 的纯动态 SQL 语句更有效。

一种低效但相对容易遵循的方法,例如

SQL> ed
Wrote file afiedt.buf

  1  create or replace type emp_unpivot_type
  2  as object (
  3    empno number,
  4    col   varchar2(4000)
  5* );
SQL> /

Type created.

SQL> create or replace type emp_unpivot_tbl
  2  as table of emp_unpivot_type;
  3  /

Type created.

SQL> ed
Wrote file afiedt.buf

  1  create or replace function unpivot_emp
  2  ( p_empno in number )
  3    return emp_unpivot_tbl
  4    pipelined
  5  is
  6    l_val varchar2(4000);
  7  begin
  8    for cols in (select column_name from user_tab_columns where table_name = 'EMP')
  9    loop
 10      execute immediate 'select ' || cols.column_name || ' from emp where empno = :empno'
 11         into l_val
 12       using p_empno;
 13      pipe row( emp_unpivot_type( p_empno, l_val ));
 14    end loop;
 15    return;
 16* end;
SQL> /

Function created.

然后您可以在 SQL 语句中调用它(我认为您至少需要第三列带有列名)

SQL> ed
Wrote file afiedt.buf

  1  select *
  2*   from table( unpivot_emp( 7934 ))
SQL> /

     EMPNO COL
---------- ----------------------------------------
      7934 7934
      7934 MILLER
      7934 CLERK
      7934 7782
      7934 23-JAN-82
      7934 1301
      7934
      7934 10

8 rows selected.

更有效的方法是改编 Tom Kyte 的 show_table pipelined table function。

【讨论】:

不完全是我希望的,但它完成了工作。

以上是关于在不确定数量的列上进行 UNPIVOT的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在T-SQL中将行转换为可变数量的列?

根据 Python 函数输出指定的列在 Google BigQuery 上进行查询

在不同于使用 XQuery 处理的数据库上进行查询

K 表示在不均匀大小的簇上进行聚类

将计数行视为查询结果中的列

如何在不使用数据透视的情况下将行转换或转置为 SQL 中的列?