【问题标题】:is there any statement to turn row value into same row but different column in oracle?是否有任何语句可以将行值转换为 oracle 中的同一行但不同的列?
【发布时间】:2021-01-05 21:49:28
【问题描述】:

我希望有人可以回答我的问题。

我有一个看起来像这样的表(即table1),我希望它像我在图片中显示的那样:

table1

"number"  "date"        time
 -------  ----------    -----
 001      19.09.2020    12:30
 001      19.09.2020    14:31
 002      19.09.2020    11:20
 001      19.09.2020    17:20
 002      19.09.2020    14:00
 001      19.09.2020    19:01

预期结果对于 "number"='001'):

"date"      time1  time2  time3  time4
----------  -----  -----  -----  -----
19.09.2020  12:30  14:31  17:20  19:01

【问题讨论】:

  • 您希望它作为列还是所有时间列的逗号分隔值也适合您的要求?如果我们使用pivot,每个数字的硬编码值都可以吗?每个数字 001 的行是否未知?

标签: sql oracle plsql oracle11g pivot


【解决方案1】:

有一些静态透视方法,例如使用PIVOT 子句和Conditional Aggregation所有生成的透视列都应该明确指定,而没有 通过使用仅SQL的直接动态方法。

我认为在存储函数中使用 SYS_REFCURSOR 非常适合您的情况:

CREATE OR REPLACE FUNCTION 
   Get_Table1_RS(
                  i_number        table1."number"%TYPE
                 ) RETURN SYS_REFCURSOR IS
  v_recordset SYS_REFCURSOR;
  v_sql       VARCHAR2(32767);
  v_str       VARCHAR2(32767);
BEGIN
  SELECT LISTAGG( ''''||time||''' AS "'||LOWER(c.column_name)||t.rn||'"' , ',' ) 
                 WITHIN GROUP ( ORDER BY time )
    INTO v_str
    FROM ( SELECT t1.*, ROW_NUMBER() OVER (ORDER BY time) AS rn 
             FROM table1 t1
            WHERE "number" = '001' ) t 
    LEFT JOIN user_tab_cols c
      ON c.table_name = 'TABLE1' 
     AND c.column_name like 'TIME%';  

  v_sql :=
  'SELECT *
     FROM table1
    PIVOT
    (
     MAX(time) FOR time IN ( '|| v_str ||' )
    )
    WHERE "number" = :nr';

  OPEN v_recordset FOR v_sql USING i_number;
  RETURN v_recordset;
END;
/

为了获得动态生成的结果集(例如Dynamic Pivot)。

然后运行以下代码:

VAR rc REFCURSOR
EXEC :rc := Get_Table1_RS('001');
PRINT rc

从 SQL Developer 的命令行查看结果集。

如果您仍然只想使用 SQL 查询,那么更喜欢使用:

pivot子句的情况:

SELECT *
  FROM table1
 PIVOT 
   (
    MAX(time) FOR time IN ( '12:30' AS "time1",'14:31' AS "time2",
                            '17:20' AS "time3",'19:01' AS "time4" )
   )
 WHERE "number" = '001';


   
  number date         time1 time2 time3 time4
  ------ -----------  ----- ----- ----- -----
  001    19.09.2020   12:30 14:31 17:20 19:01
  

条件聚合的情况:

SELECT "number", "date", 
       MAX(CASE WHEN rn = 1 THEN time END) AS "time1",
       MAX(CASE WHEN rn = 2 THEN time END) AS "time2",
       MAX(CASE WHEN rn = 3 THEN time END) AS "time3",
       MAX(CASE WHEN rn = 4 THEN time END) AS "time4"  
  FROM ( SELECT ROW_NUMBER() OVER (ORDER BY time) AS rn,
                t1.*
           FROM table1 t1
          WHERE "number" = '001' ) t  
 GROUP BY "number", "date"    

  number date         time1 time2 time3 time4
  ------ -----------  ----- ----- ----- -----
  001    19.09.2020   12:30 14:31 17:20 19:01

【讨论】:

  • 想提一点,我认为我们可以在透视子句中使用相同的行号来代替时间列。 (可以针对 listagg 的 4000 限制获得一些字符 :))
  • 是的,@Sujitmohanty30 也是可能的,但星号就足够了 :)
猜你喜欢
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
  • 2015-11-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多