You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Oracle 19c中如何使用Pivot将日期行转换为列

Oracle日期行转列(Pivot)解决方案

注意:你提供的原查询生成的是倒序日期,先修正为生成正序连续日期的基础查询:

SELECT
  TO_CHAR((TO_DATE('01-04-2024','DD-MM-YYYY') + LEVEL - 1), 'DD-MM-YYYY') AS day
FROM
  dual
CONNECT BY LEVEL <= (TO_DATE('01-05-2024','DD-MM-YYYY') - TO_DATE('01-04-2024','DD-MM-YYYY') + 1);

一、静态Pivot(固定日期范围)

如果日期范围固定,可以手动指定列名,直接使用Pivot语法转换:

列名为Day1/Day2格式

WITH date_rows AS (
  -- 生成正序日期及对应的列标识
  SELECT
    TO_CHAR((TO_DATE('01-04-2024','DD-MM-YYYY') + LEVEL - 1), 'DD-MM-YYYY') AS day,
    'Day' || LEVEL AS col_name
  FROM dual
  CONNECT BY LEVEL <= (TO_DATE('01-05-2024','DD-MM-YYYY') - TO_DATE('01-04-2024','DD-MM-YYYY') + 1)
)
SELECT *
FROM date_rows
PIVOT (
  -- 用MAX聚合,每个col_name对应唯一日期,MAX/MIN结果一致
  MAX(day) FOR col_name IN (
    'Day1' AS Day1, 'Day2' AS Day2, 'Day3' AS Day3,
    -- 按实际日期范围补充剩余列,例如到Day31
    'Day31' AS Day31
  )
);

列名为日期字符串格式

如果希望列名直接显示日期,可修改如下:

WITH date_rows AS (
  SELECT
    TO_CHAR((TO_DATE('01-04-2024','DD-MM-YYYY') + LEVEL - 1), 'DD-MM-YYYY') AS day,
    TO_CHAR((TO_DATE('01-04-2024','DD-MM-YYYY') + LEVEL - 1), 'DD-MM-YYYY') AS col_name
  FROM dual
  CONNECT BY LEVEL <= (TO_DATE('01-05-2024','DD-MM-YYYY') - TO_DATE('01-04-2024','DD-MM-YYYY') + 1)
)
SELECT *
FROM date_rows
PIVOT (
  MAX(day) FOR col_name IN (
    '01-04-2024' AS "01-04-2024", '02-04-2024' AS "02-04-2024",
    -- 补充剩余日期列
    '01-05-2024' AS "01-05-2024"
  )
);

二、动态Pivot(日期为参数)

如果日期是动态参数(范围不固定),需要用动态SQL自动生成列名列表,示例如下:

列名为Day1/Day2格式

DECLARE
  v_start_date DATE := TO_DATE('01-04-2024','DD-MM-YYYY'); -- 起始日期参数
  v_end_date DATE := TO_DATE('01-05-2024','DD-MM-YYYY');   -- 结束日期参数
  v_col_list VARCHAR2(4000); -- 存储生成的列名列表
  v_sql VARCHAR2(4000);      -- 动态SQL语句
BEGIN
  -- 生成Pivot需要的列名格式:'Day1' AS Day1, 'Day2' AS Day2...
  SELECT LISTAGG('''' || 'Day' || LEVEL || ''' AS Day' || LEVEL, ', ') WITHIN GROUP (ORDER BY LEVEL)
  INTO v_col_list
  FROM dual
  CONNECT BY LEVEL <= (v_end_date - v_start_date + 1);

  -- 构建完整动态SQL
  v_sql := '
    WITH date_rows AS (
      SELECT
        TO_CHAR((:start_date + LEVEL - 1), ''DD-MM-YYYY'') AS day,
        ''Day'' || LEVEL AS col_name
      FROM dual
      CONNECT BY LEVEL <= (:end_date - :start_date + 1)
    )
    SELECT *
    FROM date_rows
    PIVOT (
      MAX(day) FOR col_name IN (' || v_col_list || ')
    )';

  -- 执行动态SQL并绑定参数
  EXECUTE IMMEDIATE v_sql USING v_start_date, v_end_date, v_start_date;
END;
/

列名为日期字符串格式

若要以日期字符串作为列名,修改列名生成逻辑即可:

DECLARE
  v_start_date DATE := TO_DATE('01-04-2024','DD-MM-YYYY');
  v_end_date DATE := TO_DATE('01-05-2024','DD-MM-YYYY');
  v_col_list VARCHAR2(4000);
  v_sql VARCHAR2(4000);
BEGIN
  -- 生成日期字符串格式的列名
  SELECT LISTAGG('''' || TO_CHAR(v_start_date + LEVEL - 1, 'DD-MM-YYYY') || ''' AS "' || TO_CHAR(v_start_date + LEVEL - 1, 'DD-MM-YYYY') || '"', ', ') WITHIN GROUP (ORDER BY LEVEL)
  INTO v_col_list
  FROM dual
  CONNECT BY LEVEL <= (v_end_date - v_start_date + 1);

  v_sql := '
    WITH date_rows AS (
      SELECT
        TO_CHAR((:start_date + LEVEL - 1), ''DD-MM-YYYY'') AS day,
        TO_CHAR((:start_date + LEVEL - 1), ''DD-MM-YYYY'') AS col_name
      FROM dual
      CONNECT BY LEVEL <= (:end_date - :start_date + 1)
    )
    SELECT *
    FROM date_rows
    PIVOT (
      MAX(day) FOR col_name IN (' || v_col_list || ')
    )';

  EXECUTE IMMEDIATE v_sql USING v_start_date, v_end_date, v_start_date;
END;
/

关键说明

  • Oracle的Pivot语法必须配合聚合函数(如MAX/MIN),因为Pivot本质是聚合转换,这里每个列标识对应唯一日期,所以用MAX或MIN结果一致。
  • 动态SQL适用于日期范围不固定的场景,静态Pivot适合范围固定的场景,操作更简单。

内容的提问来源于stack exchange,提问作者Rahul Aggarwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:44:56