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

Asp.net 6 MVC中Oracle存储过程返回JSON对象时DISTINCT失效导致WBS重复的问题求助

解决Oracle存储过程中DISTINCT无法去除WBS重复数据的问题

嘿,我看你在Asp.net 6 MVC环境下调用这个Oracle存储过程时,遇到了DISTINCT失效、WBS字段重复的麻烦。先帮你拆解下问题根源,再给几个实用的解决思路:

问题根源分析

你现在CTE里的DISTINCT L.WBS_LEVEL_ID其实没起到实际作用——这个CTE只是单独提取了唯一的WBS_LEVEL_ID,但后续的JOIN操作(尤其是和BASELINE_RPT B、BCP BC的关联)会把数据扩展开:如果一个WBS对应多个基线版本(B.REV_NUMBER不同),或者一个基线对应多条BCP记录,最终结果就会出现多条相同WBS的记录,CTE的DISTINCT根本管不到后续关联后的重复。

另外注意到你的存储过程里没用到输入参数in_WBS_LEVEL_ID、in_FISCAL_YEAR、in_FISCAL_MONTH,这可能也是导致数据冗余、重复增多的原因,记得加上参数过滤!

可行的解决思路

思路1:用窗口函数筛选每个WBS的最新版本

从你最后按B.REV_NUMBER DESC排序的逻辑来看,推测你大概率只需要每个WBS的最新基线版本。这种情况下,用ROW_NUMBER()窗口函数给每个WBS的记录按版本号倒序排序,只保留行号为1的记录就能精准去重:

修改后的存储过程代码示例:

PROCEDURE GET_BASELINE_RPT (in_WBS_LEVEL_ID IN NUMBER, in_FISCAL_YEAR IN VARCHAR2, in_FISCAL_MONTH IN VARCHAR2, RET OUT CLOB) AS 
BEGIN 
SELECT JSON_ARRAYAGG ( 
    JSON_OBJECT ( 
        'WBS' VALUE t.WBS_LEVEL_NAME, 
        'Title' VALUE t.DESCRIPTION, 
        'Rev' VALUE t.REV_NUMBER, 
        'ScopeStatus' VALUE t.STATUS, 
        'BCP' VALUE CASE WHEN t.FISCAL_YEAR = 0 THEN '' ELSE SUBSTR(t.FISCAL_YEAR,3,2)||'-'||LPAD(t.BCP_FISCAL_ID, 3, '0') END, 
        'BCPApprovalDate' VALUE t.APPROVAL_DATE, 
        'Manager' VALUE t.NICK_NAME, 
        'ProjectControlManager' VALUE t.NICK_NAME_2, 
        'ProjectControlEngineer' VALUE t.NICK_NAME_3, 
        'FiscalYear' VALUE t.FISCAL_YEAR_W, 
        'FiscalMonth' VALUE t.FISCAL_MONTH_W, 
        'WBSNumber' VALUE t.WBS_LEVEL_ID 
    ) RETURNING CLOB
) INTO RET 
FROM (
    SELECT 
        L.WBS_LEVEL_NAME, W.DESCRIPTION, B.REV_NUMBER, W.STATUS,
        BC.FISCAL_YEAR, BC.BCP_FISCAL_ID, BC.APPROVAL_DATE,
        P1.NICK_NAME, P2.NICK_NAME AS NICK_NAME_2, P3.NICK_NAME AS NICK_NAME_3,
        W.FISCAL_YEAR AS FISCAL_YEAR_W, W.FISCAL_MONTH AS FISCAL_MONTH_W, L.WBS_LEVEL_ID,
        -- 按WBS分组,版本号倒序,标记最新版本为行号1
        ROW_NUMBER() OVER (PARTITION BY L.WBS_LEVEL_ID ORDER BY B.REV_NUMBER DESC) AS rn
    FROM WBS_LEVEL L 
    LEFT OUTER JOIN BASELINE_RPT B ON L.WBS_LEVEL_ID = B.WBS_LEVEL_ID 
    JOIN BCP BC ON BC.BCP_ID = B.BCP_ID 
    LEFT OUTER JOIN WBS_TREE_MOD W ON L.WBS_LEVEL_ID = W.WBS_LEVEL_ID 
    LEFT OUTER JOIN VW_SITEPEOPLE P1 ON W.WBS_MANAGER_SNUMBER = P1.SNUMBER 
    LEFT OUTER JOIN VW_SITEPEOPLE P2 ON W.PCM_SNUMBER = P2.SNUMBER 
    LEFT OUTER JOIN VW_SITEPEOPLE P3 ON W.PCE_SNUMBER = P3.SNUMBER 
    -- 加上输入参数过滤,减少冗余数据
    WHERE L.WBS_LEVEL_ID = in_WBS_LEVEL_ID 
      AND W.FISCAL_YEAR = in_FISCAL_YEAR 
      AND W.FISCAL_MONTH = in_FISCAL_MONTH
) t
WHERE t.rn = 1 -- 只保留每个WBS的最新版本记录
ORDER BY t.WBS_LEVEL_NAME; 
END GET_BASELINE_RPT;

思路2:在最终查询中使用DISTINCT(仅全字段重复时有效)

如果你的重复是因为关联后所有字段完全一致(比如同一个WBS、同一个版本、同一个BCP等),可以把DISTINCT加到子查询里:

SELECT JSON_ARRAYAGG ( 
    JSON_OBJECT (...) RETURNING CLOB
) INTO RET 
FROM (
    SELECT DISTINCT -- 这里加DISTINCT去重全字段重复的记录
        L.WBS_LEVEL_NAME, W.DESCRIPTION, B.REV_NUMBER, W.STATUS,
        BC.FISCAL_YEAR, BC.BCP_FISCAL_ID, BC.APPROVAL_DATE,
        P1.NICK_NAME, P2.NICK_NAME, P3.NICK_NAME,
        W.FISCAL_YEAR, W.FISCAL_MONTH, L.WBS_LEVEL_ID
    FROM WBS_LEVEL L 
    -- 原关联语句+参数过滤
) t
ORDER BY t.WBS_LEVEL_NAME, t.REV_NUMBER DESC;

不过这种情况比较少见,因为如果存在不同的REV_NUMBER,DISTINCT会保留不同版本的记录,WBS仍会重复。

思路3:先排查重复的具体来源

如果不确定是哪个表导致的重复,可以先单独运行不带JSON的查询,定位重复的根源:

SELECT 
    L.WBS_LEVEL_NAME, B.REV_NUMBER, BC.BCP_ID, COUNT(*) AS duplicate_count
FROM WBS_LEVEL L 
LEFT OUTER JOIN BASELINE_RPT B ON L.WBS_LEVEL_ID = B.WBS_LEVEL_ID 
JOIN BCP BC ON BC.BCP_ID = B.BCP_ID 
LEFT OUTER JOIN WBS_TREE_MOD W ON L.WBS_LEVEL_ID = W.WBS_LEVEL_ID 
WHERE L.WBS_LEVEL_ID = in_WBS_LEVEL_ID 
  AND W.FISCAL_YEAR = in_FISCAL_YEAR 
  AND W.FISCAL_MONTH = in_FISCAL_MONTH
GROUP BY L.WBS_LEVEL_NAME, B.REV_NUMBER, BC.BCP_ID
HAVING COUNT(*) > 1;

通过这个查询可以看到是哪些字段组合(比如WBS+版本+BCP)导致了重复,再针对性调整关联条件或过滤逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 21:29:07