需要 PL/SQL 存储过程将列转换为行

Posted

技术标签:

【中文标题】需要 PL/SQL 存储过程将列转换为行【英文标题】:Need PL/SQL stored procedure to convert column into rows 【发布时间】:2020-12-14 17:29:38 【问题描述】:

我有桌子-

filename    description                                 value
--------    ------------------------------------------  --------------------
rec_123     PropertyWriteCount_rows_0_month             February 2018
rec_123     rows_PropertyWriteCount_rows_0_description  property write count
rec_123     PropertyWriteCount_rows_0_value_value       1234
rec_123     PropertyWriteCount_rows_0_value_baseType    LONG

我想把它转换成-

filename  month            value    description                 value_basetype
--------  -------------    -----    -------------------------   --------------       
rec_2134  February 2018    1234     PropertyWriteCount_rows_0   long

到目前为止,我可以编写 PL/SQL,需要帮助进行下一步 -

CREATE PROCEDURE rows_column IS
  CURSOR get_rows IS
    SELECT * FROM table1 where description LIKE 'PropertyWriteCount_rows%';
BEGIN
  DBMS_OUTPUT.PUT_LINE('table info -');
END;
/

【问题讨论】:

【参考方案1】:

您可以使用条件聚合来做到这一点:

select 
    filename,
    max(case when description = 'PropertyWriteCount_rows_0_month'            then value end) as month,
    max(case when description = 'rows_PropertyWriteCount_rows_0_description' then value end) as description,
    max(case when description = 'PropertyWriteCount_rows_0_value_value'      then value end) as value,
    max(case when description = 'PropertyWriteCount_rows_0_value_baseType'   then value end) as value_basetype
from table1 
where description like '%PropertyWriteCount_rows%'
group by filename

【讨论】:

谢谢,我发现了 2 个问题 1) 这生成了文件名列 (rec_2134) 的单个记录,但我有多个记录如何处理它 2) 我的描述不会总是“PropertyWriteCount_rows_0”,可以我们添加类似的情况? (1) 这未显示在您的示例数据中,因此我无法对此发表评论 (2) 当然,您可以将等式更改为 like 条件。例如:max(case when description like 'PropertyWriteCount_rows_%_month' then value end) as month. 我仍然想了解如果我必须获取多个文件名记录,那么我们该如何处理? @AkashSarpate - 请编辑您的问题以包含更多示例数据。如果输出中有多行具有相同的filename,您如何知道要将哪些行聚合在一起?当您编辑您的问题并包含该示例数据时,请务必说明您要实施的逻辑,以选择要在输出中组合哪些行。【参考方案2】:

您可以在呈现description 列后使用PIVOT 子句,以便从该列中提取最后一个下划线之后的最后一个单词。

以下查询可能用作静态方法

SELECT *
  FROM
  (
   SELECT REGEXP_SUBSTR(description,'[^_]+$') AS title,
          filename, value
     FROM table1 )
  PIVOT
  (
   MAX(value) FOR title IN ('month' AS month, 'value' AS value, 
                            'description' AS description, 'baseType' AS baseType) 
  )

Demo

但应该首选动态方法,通过创建存储函数,如以下 PL/SQL 代码中所示

CREATE OR REPLACE FUNCTION Get_File_Values RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_col       VARCHAR2(32767);
BEGIN
  SELECT LISTAGG( ''''||titles||''' AS '||titles , ',' ) 
                 WITHIN GROUP ( ORDER BY titles DESC )
    INTO v_col
    FROM ( SELECT DISTINCT REGEXP_SUBSTR(description,'[^_]+$') AS titles  
             FROM table1 ); 

  v_sql :=
  'SELECT *
     FROM (
           SELECT REGEXP_SUBSTR(description,''[^_]+$'') AS title,
                  filename, value
             FROM table1
          )
    PIVOT
    (
     MAX(value) FOR title IN ( '|| v_col ||' )
    )';

  OPEN v_recordset FOR v_sql;
  DBMS_OUTPUT.PUT_LINE(v_sql);
  RETURN v_recordset;
END;
/

然后运行以下代码:

VAR rc REFCURSOR
EXEC :rc := Get_File_Values;
PRINT rc

来自 SQL Developer命令行

BEGIN
  :result := Get_File_Values;
END;

来自PL/SQL Developer测试窗口标记为

为了查看预期结果集的变化,即使 description 列的新值被插入或一些以前的值被删除。

【讨论】:

以上是关于需要 PL/SQL 存储过程将列转换为行的主要内容,如果未能解决你的问题,请参考以下文章

oracle pl sql中如何将列数据转置为行

如何给SQLSERVER存储过程传递数组参数

使用带有布尔输入参数的 PL/SQL 在 oracle 中调用 java 存储过程

PL_sql如何执行oracle存储过程

PL/SQL 存储过程填充事实表

PL/SQL:将词法参数传递给存储过程