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

如何使用Oracle函数将季度分数宽表查询结果转换为窄表?

Oracle宽表转窄表的实现方案

你可以通过两种常用方式将现有宽表转换为目标窄表格式:

方法一:使用UNION ALL(通用兼容方案)

这是所有关系型数据库都支持的通用写法,将每行数据拆分为两行,分别映射过去季度和当前季度的分数与季度信息:

-- 基于原查询结果转换为窄表
SELECT past_score AS SCORE, past_quarter AS Quarter
FROM (
    -- 原有的宽表查询语句
    SELECT Greatest(1, Least(5, score))      AS past_score,
           Greatest(1, Least(5, curr_score)) AS current_score,
           current_quarter,
           past_quarter
    FROM   (SELECT Round(( 0.4 * normalized_sick_leave ) +
                         ( 0.3 * normalized_total ) + (
                                0.3 *
                                        overall_rating ), 1) AS score,
                   Round(( 0.4 * normalized_sick_leave_current ) + ( 0.3 *
                         normalized_total_curr )
                         + (
                         0.3 * overall_rating_curr ), 1)     AS curr_score,
                   current_quarter,
                   past_quarter
            FROM   (SELECT Nvl(abs_record.duration / 10, 0)                  AS
                                   normalized_sick_leave,
                           time_entry.hours / 540                            AS
                           normalized_total,
                           5 - To_number(perf_rating.overall_rating)         AS
                           overall_rating,
                           abs_record_current.duration / 10                  AS
                                   normalized_sick_leave_current,
                           time_entry_current.hours / 540                    AS
                                   normalized_total_curr,
                           5 - To_number(perf_rating_current.overall_rating) AS
                           overall_rating_curr
                                   ,
                           time_entry.quarter
                                   past_quarter,
                           time_entry_current.quarter
                           CURRENT_QUARTER
                    FROM   abs_record ABS_RECORD,
                           time_entry TIME_ENTRY,
                           perf_rating perf_rating,
                           abs_record_current ABS_RECORD_current,
                           time_entry_current TIME_ENTRY_current,
                           perf_rating_current perf_rating_current
                    WHERE  abs_record.person_id(+) = time_entry.person_id
                           AND time_entry.person_id = perf_rating.person_id(+)
                           AND abs_record_current.person_id(+) =
                               time_entry_current.person_id
                           AND time_entry_current.person_id =
                               perf_rating_current.person_id(+)
                           AND time_entry_current.person_id (+) =
                               time_entry.person_id))
UNION ALL
SELECT current_score AS SCORE, current_quarter AS Quarter
FROM (
    -- 原有的宽表查询语句
    SELECT Greatest(1, Least(5, score))      AS past_score,
           Greatest(1, Least(5, curr_score)) AS current_score,
           current_quarter,
           past_quarter
    FROM   (SELECT Round(( 0.4 * normalized_sick_leave ) +
                         ( 0.3 * normalized_total ) + (
                                0.3 *
                                        overall_rating ), 1) AS score,
                   Round(( 0.4 * normalized_sick_leave_current ) + ( 0.3 *
                         normalized_total_curr )
                         + (
                         0.3 * overall_rating_curr ), 1)     AS curr_score,
                   current_quarter,
                   past_quarter
            FROM   (SELECT Nvl(abs_record.duration / 10, 0)                  AS
                                   normalized_sick_leave,
                           time_entry.hours / 540                            AS
                           normalized_total,
                           5 - To_number(perf_rating.overall_rating)         AS
                           overall_rating,
                           abs_record_current.duration / 10                  AS
                                   normalized_sick_leave_current,
                           time_entry_current.hours / 540                    AS
                                   normalized_total_curr,
                           5 - To_number(perf_rating_current.overall_rating) AS
                           overall_rating_curr
                                   ,
                           time_entry.quarter
                                   past_quarter,
                           time_entry_current.quarter
                           CURRENT_QUARTER
                    FROM   abs_record ABS_RECORD,
                           time_entry TIME_ENTRY,
                           perf_rating perf_rating,
                           abs_record_current ABS_RECORD_current,
                           time_entry_current TIME_ENTRY_current,
                           perf_rating_current perf_rating_current
                    WHERE  abs_record.person_id(+) = time_entry.person_id
                           AND time_entry.person_id = perf_rating.person_id(+)
                           AND abs_record_current.person_id(+) =
                               time_entry_current.person_id
                           AND time_entry_current.person_id =
                               perf_rating_current.person_id(+)
                           AND time_entry_current.person_id (+) =
                               time_entry.person_id))

方法二:使用Oracle专属的UNPIVOT函数(更简洁)

Oracle 11g及以上版本支持UNPIVOT操作,可以直接将宽表的多列转换为行,写法更简洁:

-- 使用UNPIVOT转换窄表
SELECT SCORE, Quarter
FROM (
    -- 原有的宽表查询语句
    SELECT Greatest(1, Least(5, score))      AS past_score,
           Greatest(1, Least(5, curr_score)) AS current_score,
           current_quarter,
           past_quarter
    FROM   (SELECT Round(( 0.4 * normalized_sick_leave ) +
                         ( 0.3 * normalized_total ) + (
                                0.3 *
                                        overall_rating ), 1) AS score,
                   Round(( 0.4 * normalized_sick_leave_current ) + ( 0.3 *
                         normalized_total_curr )
                         + (
                         0.3 * overall_rating_curr ), 1)     AS curr_score,
                   current_quarter,
                   past_quarter
            FROM   (SELECT Nvl(abs_record.duration / 10, 0)                  AS
                                   normalized_sick_leave,
                           time_entry.hours / 540                            AS
                           normalized_total,
                           5 - To_number(perf_rating.overall_rating)         AS
                           overall_rating,
                           abs_record_current.duration / 10                  AS
                                   normalized_sick_leave_current,
                           time_entry_current.hours / 540                    AS
                                   normalized_total_curr,
                           5 - To_number(perf_rating_current.overall_rating) AS
                           overall_rating_curr
                                   ,
                           time_entry.quarter
                                   past_quarter,
                           time_entry_current.quarter
                           CURRENT_QUARTER
                    FROM   abs_record ABS_RECORD,
                           time_entry TIME_ENTRY,
                           perf_rating perf_rating,
                           abs_record_current ABS_RECORD_current,
                           time_entry_current TIME_ENTRY_current,
                           perf_rating_current perf_rating_current
                    WHERE  abs_record.person_id(+) = time_entry.person_id
                           AND time_entry.person_id = perf_rating.person_id(+)
                           AND abs_record_current.person_id(+) =
                               time_entry_current.person_id
                           AND time_entry_current.person_id =
                               perf_rating_current.person_id(+)
                           AND time_entry_current.person_id (+) =
                               time_entry.person_id))
UNPIVOT (
    (SCORE, Quarter) FOR score_quarter IN (
        (past_score, past_quarter) AS 'past',
        (current_score, current_quarter) AS 'current'
    )
)

说明:

  • UNION ALL的方式兼容性更强,适合所有数据库环境;
  • UNPIVOT是Oracle原生支持的列转行函数,代码更简洁,执行效率更高,适合Oracle 11g及以上版本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 23:20:19