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

基于NIF分组的分区与子分区生成需求(含累计值重置规则)

为my_table表生成PARTITION与SUBPARTITION列的实现方案

需求说明

现有仅包含NIF、FILE_、FILESIZE列的数据表my_table,需新增PARTITION和SUBPARTITION列,规则如下:

  • PARTITION从1开始,每当SUBPARTITION数量达到8时递增1
  • 单个NIF的所有记录必须归属同一个PARTITION(最严格约束)
  • 按记录顺序累计FILESIZE,累计值达到10时,SUBPARTITION递增1,同时累计值重置

示例输出

NIF  FILE FILESIZE    PARTITION   SUBPARTITION
  ----------------------------------------------
   A     C1        1            1              1
   A     C2        1            1              1
   A     C3        2            1              1
   A     C4        1            1              1
   B     C5        5            1              2
   B     C6        1            1              2
   C     C7        2            1              2
   C     C8        1            1              2
   D     C9        4            1              3
   D    C10        5            1              3
   D    C11        1            1              3
   D    C12        2            1              4
   D    C13        3            1              4
   D    C14        4            1              4
   D    C15        5            1              5
   E    C16        3            1              6
   E    C17        2            1              6
   E    C18        3            1              6
   E    C19        4            1              7
   F    C20        6            2              1
   F    C21        2            2              1

数据表创建及插入脚本

DROP TABLE my_table;
-- 创建表
CREATE TABLE my_table (
  NIF VARCHAR2(10),
  FILE_ VARCHAR2(10),
  FILESIZE NUMBER
);

-- 插入测试数据
INSERT INTO my_table (NIF, FILE_, FILESIZE)
    SELECT 'A', 'C1', 1 FROM DUAL UNION ALL
    SELECT 'A', 'C2', 1 FROM DUAL UNION ALL
    SELECT 'A', 'C3', 2 FROM DUAL UNION ALL
    SELECT 'A', 'C4', 1 FROM DUAL UNION ALL
    SELECT 'B', 'C5', 5 FROM DUAL UNION ALL
    SELECT 'B', 'C6', 1 FROM DUAL UNION ALL
    SELECT 'C', 'C7', 2 FROM DUAL UNION ALL
    SELECT 'C', 'C8', 1 FROM DUAL UNION ALL
    SELECT 'D', 'C9', 4 FROM DUAL UNION ALL
    SELECT 'D', 'C10', 5 FROM DUAL UNION ALL
    SELECT 'D', 'C11', 1 FROM DUAL UNION ALL
    SELECT 'D', 'C12', 2 FROM DUAL UNION ALL
    SELECT 'D', 'C13', 3 FROM DUAL UNION ALL
    SELECT 'D', 'C14', 4 FROM DUAL UNION ALL
    SELECT 'D', 'C15', 5 FROM DUAL UNION ALL
    SELECT 'E', 'C16', 3 FROM DUAL UNION ALL
    SELECT 'E', 'C17', 2 FROM DUAL UNION ALL
    SELECT 'E', 'C18', 3 FROM DUAL UNION ALL
    SELECT 'E', 'C19', 4 FROM DUAL UNION ALL
    SELECT 'F', 'C20', 6 FROM DUAL UNION ALL
    SELECT 'F', 'C21', 2 FROM DUAL;
    
COMMIT;

解决方案

方案一:单SQL查询实现

利用Oracle分析函数计算累计值,通过嵌套查询逐步生成符合规则的分区列:

WITH step1 AS (
    -- 计算全局累计FILESIZE,标记每个NIF的起始记录位置
    SELECT 
        t.*,
        SUM(FILESIZE) OVER (ORDER BY ROWID) AS global_cumulative,
        MIN(ROWID) OVER (PARTITION BY NIF) AS nif_min_rowid
    FROM my_table t
),
step2 AS (
    -- 初步划分SUBPARTITION:累计值每满10开启新分组
    SELECT 
        s1.*,
        FLOOR((global_cumulative - 1) / 10) + 1 AS raw_subpartition
    FROM step1 s1
),
step3 AS (
    -- 确保同一NIF的记录起始子分区统一,避免跨PARTITION
    SELECT 
        s2.*,
        MIN(raw_subpartition) OVER (PARTITION BY NIF) AS nif_min_subpart
    FROM step2 s2
),
step4 AS (
    -- 调整同一NIF内的SUBPARTITION,保证连续且不跨分区
    SELECT 
        s3.*,
        nif_min_subpart + FLOOR((SUM(FILESIZE) OVER (PARTITION BY NIF ORDER BY ROWID) - 1) / 10) AS subpartition
    FROM step3 s3
),
step5 AS (
    -- 根据SUBPARTITION生成PARTITION:每8个子分区升一级
    SELECT 
        s4.*,
        FLOOR((subpartition - 1) / 8) + 1 AS partition
    FROM step4 s4
)
SELECT 
    NIF,
    FILE_,
    FILESIZE,
    PARTITION,
    SUBPARTITION
FROM step5
ORDER BY ROWID;

方案二:PL/SQL游标实现

通过游标遍历记录,手动维护累计值、子分区和分区的状态逻辑:

DECLARE
    CURSOR c_my_table IS 
        SELECT NIF, FILE_, FILESIZE FROM my_table ORDER BY ROWID;
    v_current_nif VARCHAR2(10);
    v_cumulative NUMBER := 0;
    v_subpartition NUMBER := 1;
    v_partition NUMBER := 1;
    v_nif_subpart_start NUMBER := 1;
BEGIN
    -- 创建临时表存储结果
    CREATE GLOBAL TEMPORARY TABLE temp_result (
        NIF VARCHAR2(10),
        FILE_ VARCHAR2(10),
        FILESIZE NUMBER,
        PARTITION NUMBER,
        SUBPARTITION NUMBER
    ) ON COMMIT PRESERVE ROWS;
    
    FOR rec IN c_my_table LOOP
        -- 切换NIF时,确保新NIF的子分区不跨PARTITION
        IF rec.NIF != v_current_nif THEN
            v_current_nif := rec.NIF;
            v_cumulative := 0;
            -- 计算当前NIF的起始子分区,保证其所有子分区在同一个PARTITION内
            WHILE FLOOR((v_subpartition - 1)/8) != FLOOR((v_subpartition + CEIL((SUM(rec.FILESIZE) OVER (PARTITION BY rec.NIF))/10) -1)/8) LOOP
                v_subpartition := v_subpartition + 1;
            END LOOP;
            v_nif_subpart_start := v_subpartition;
        END IF;
        
        v_cumulative := v_cumulative + rec.FILESIZE;
        -- 累计值达标则切换子分区,重置累计值
        IF v_cumulative >= 10 THEN
            v_subpartition := v_subpartition + 1;
            v_cumulative := v_cumulative - 10;
            -- 子分区满8个则升级PARTITION
            IF MOD(v_subpartition - 1, 8) = 0 THEN
                v_partition := v_partition + 1;
            END IF;
        END IF;
        
        -- 插入结果到临时表
        INSERT INTO temp_result VALUES (
            rec.NIF,
            rec.FILE_,
            rec.FILESIZE,
            v_partition,
            v_subpartition
        );
    END LOOP;
    
    -- 输出结果
    DBMS_OUTPUT.PUT_LINE('  NIF  FILE FILESIZE    PARTITION   SUBPARTITION');
    DBMS_OUTPUT.PUT_LINE('  ----------------------------------------------');
    FOR res_rec IN (SELECT * FROM temp_result ORDER BY ROWID) LOOP
        DBMS_OUTPUT.PUT_LINE(RPAD(' ' || res_rec.NIF, 6) || RPAD(res_rec.FILE_, 6) || RPAD(res_rec.FILESIZE, 10) || RPAD(res_rec.PARTITION, 14) || res_rec.SUBPARTITION);
    END LOOP;
    
    -- 清理临时表
    DROP TABLE temp_result;
EXCEPTION
    WHEN OTHERS THEN
        IF SQLCODE = -942 THEN
            NULL;
        ELSE
            RAISE;
        END IF;
END;
/

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:26:59