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

使用GROUP BY去重遇ORA-00933错误:SQL命令未正确终止求助

ORA-00933错误排查与去重解决方案

这个错误在Oracle使用GROUP BY的时候太容易踩坑了,我帮你拆解下问题和解决办法:

为什么会触发ORA-00933?

Oracle对GROUP BY的语法要求非常严格:SELECT语句中所有没有使用聚合函数(比如SUM、COUNT)的列,必须全部出现在GROUP BY子句中。另外,也有可能是你把GROUP BY放在了错误的位置(比如ORDER BY之后),或者语法里有多余的符号,导致SQL命令无法正确解析。

从你的描述来看,大概率是只给GROUP BY加了部分列,没有覆盖SELECT里的所有非聚合字段,才触发了这个错误。

两种可行的去重方案

方案1:严格遵循Oracle GROUP BY规则去重

如果你确实需要通过GROUP BY合并完全相同的行(所有字段值都重复的情况),那必须把SELECT里的每一个非聚合列都加到GROUP BY里。另外建议把旧的隐式连接改成显式JOIN,可读性更强也不容易出错:

SELECT 
    TRIM(S90T1.fname) || ' ' || S90T1.lname "_CoWorker",
    L16T3.partno,
    L16T3.shortl62,
    L16T3.partrev,
    L16T3.ordno,
    L16T40.reascode || '(' || TRIM(E10T1.ma_desc) || ')' "_reascode",
    L16T3.datreg "_Date"
FROM L16T40
JOIN L16T3 ON L16T3.ordno = L16T40.ordno
JOIN S90T1 ON L16T3.logguser = S90T1.uname
JOIN E10T1 ON L16T40.reascode = E10T1.reascode
WHERE 
    L16T3.L16lcode = 45 
    AND L16T3.datreg > TO_DATE('2024-01-01', 'YYYY-MM-DD') -- 替换成你的实际日期条件
GROUP BY 
    TRIM(S90T1.fname) || ' ' || S90T1.lname,
    L16T3.partno,
    L16T3.shortl62,
    L16T3.partrev,
    L16T3.ordno,
    L16T40.reascode || '(' || TRIM(E10T1.ma_desc) || ')',
    L16T3.datreg;

小技巧:如果拼接后的列(比如_CoWorker)是由原始字段唯一决定的,你也可以在GROUP BY里用原始字段(比如S90T1.fname, S90T1.lname)代替拼接后的列,效果是一样的,还能减少计算量。

方案2:用窗口函数灵活去重(推荐)

如果你只是想去除_CoWorker的重复,而保留对应行的最新/最早记录(其他字段不需要完全相同),那GROUP BY就不太合适了,这时候用窗口函数ROW_NUMBER()会更灵活:

WITH ranked_data AS (
    SELECT 
        TRIM(S90T1.fname) || ' ' || S90T1.lname "_CoWorker",
        L16T3.partno,
        L16T3.shortl62,
        L16T3.partrev,
        L16T3.ordno,
        L16T40.reascode || '(' || TRIM(E10T1.ma_desc) || ')' "_reascode",
        L16T3.datreg "_Date",
        -- 按_CoWorker分组,每组内按日期倒序排名,最新的行排第1
        ROW_NUMBER() OVER (PARTITION BY TRIM(S90T1.fname) || ' ' || S90T1.lname ORDER BY L16T3.datreg DESC) rn
    FROM L16T40
    JOIN L16T3 ON L16T3.ordno = L16T40.ordno
    JOIN S90T1 ON L16T3.logguser = S90T1.uname
    JOIN E10T1 ON L16T40.reascode = E10T1.reascode
    WHERE 
        L16T3.L16lcode = 45 
        AND L16T3.datreg > TO_DATE('2024-01-01', 'YYYY-MM-DD') -- 替换成你的实际日期条件
)
-- 只取每组排名第一的行
SELECT "_CoWorker", partno, shortl62, partrev, ordno, "_reascode", "_Date"
FROM ranked_data
WHERE rn = 1;

这个方法可以精准控制去重逻辑,比如你想保留最早的记录,只需要把ORDER BY L16T3.datreg DESC改成ASC就行。

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

火山引擎 最新活动