You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Oracle查询:将多组关联版本列合并为单列并保留主键

实现Oracle列转行需求的解决方案

当然可以搞定这个需求!这本质上是典型的**列转行(Unpivot)**场景,针对Oracle数据库,我给你两种实用的实现方案,都能完美匹配你的输出要求:

方案一:使用UNPIVOT语法(推荐,简洁直观)

UNPIVOT是Oracle专门用于列转行的语法,适合这种有规律的列名转换场景:

SELECT pk, aaa, bbb, ccc
FROM (
    -- 先把原表的AA/BB/CC系列列重命名为带版本号的格式
    SELECT 
        pk,
        aa AS aaa_1, aa2 AS aaa_2, aa3 AS aaa_3, aa4 AS aaa_4, aa5 AS aaa_5,
        bb AS bbb_1, bb2 AS bbb_2, bb3 AS bbb_3, bb4 AS bbb_4, bb5 AS bbb_5,
        cc AS ccc_1, cc2 AS ccc_2, cc3 AS ccc_3, cc4 AS ccc_4, cc5 AS ccc_5
    FROM your_table_name -- 替换成你的实际表名
)
-- 分别对AA、BB、CC系列执行列转行
UNPIVOT (
    aaa FOR version_aaa IN (aaa_1 AS 1, aaa_2 AS 2, aaa_3 AS 3, aaa_4 AS 4, aaa_5 AS 5)
)
UNPIVOT (
    bbb FOR version_bbb IN (bbb_1 AS 1, bbb_2 AS 2, bbb_3 AS 3, bbb_4 AS 4, bbb_5 AS 5)
)
UNPIVOT (
    ccc FOR version_ccc IN (ccc_1 AS 1, ccc_2 AS 2, ccc_3 AS 3, ccc_4 AS 4, ccc_5 AS 5)
)
-- 确保同一版本的AA/BB/CC对应,同时过滤空版本(题目说AA存在则BB/CC必存在)
WHERE version_aaa = version_bbb AND version_bbb = version_ccc
  AND aaa IS NOT NULL
ORDER BY pk, version_aaa;

方案说明:

  1. 首先将原表的AA/AA2等列重命名为带版本号的aaa_1/aaa_2,方便后续关联;
  2. 三次UNPIVOT分别把AA、BB、CC系列的列转成行,同时保留版本号;
  3. 通过版本号关联,确保同一版本的三个值对应成一行;
  4. 过滤掉aaa为空的行(因为题目明确“若存在AA则必有BB和CC”,所以只要AA非空,BB/CC肯定也非空)。

方案二:使用CONNECT BY+CASE表达式(兼容低版本Oracle)

如果你的Oracle版本不支持UNPIVOT(比如11g之前),可以用递归生成行结合CASE表达式实现:

SELECT 
    pk,
    -- 根据版本号取对应列的值
    CASE level 
        WHEN 1 THEN aa
        WHEN 2 THEN aa2
        WHEN 3 THEN aa3
        WHEN 4 THEN aa4
        WHEN 5 THEN aa5
    END AS aaa,
    CASE level 
        WHEN 1 THEN bb
        WHEN 2 THEN bb2
        WHEN 3 THEN bb3
        WHEN 4 THEN bb4
        WHEN 5 THEN bb5
    END AS bbb,
    CASE level 
        WHEN 1 THEN cc
        WHEN 2 THEN cc2
        WHEN 3 THEN cc3
        WHEN 4 THEN cc4
        WHEN 5 THEN cc5
    END AS ccc
FROM your_table_name -- 替换成你的实际表名
-- 生成1-5的版本行,每个PK对应5行
CONNECT BY level <= 5
    AND PRIOR pk = pk
    AND PRIOR SYS_GUID() IS NOT NULL -- 防止递归循环
-- 过滤空版本
WHERE CASE level 
        WHEN 1 THEN aa
        WHEN 2 THEN aa2
        WHEN 3 THEN aa3
        WHEN 4 THEN aa4
        WHEN 5 THEN aa5
    END IS NOT NULL
ORDER BY pk, level;

方案说明:

  1. CONNECT BY level <=5为每个PK生成5行(对应AA到AA5的5个版本);
  2. 通过CASE表达式根据level值取对应版本的AA/BB/CC列;
  3. 过滤掉AA为空的行,只保留有数据的版本;
  4. PRIOR SYS_GUID() IS NOT NULL是为了避免递归时出现循环问题。

这两种方案都能完美输出你想要的结果,比如针对你提供的示例数据,PK=3会生成3行,完全符合要求。

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

火山引擎 最新活动