如何编写SQL去除已完成/取消订单的其余无关状态行
解决方案
核心逻辑是先给不同订单状态设置业务优先级,终态(完成、取消)优先级高于所有中间状态和初始状态,每个订单仅保留优先级最高的一条状态记录即可。
首先明确已知的状态优先级规则:
- 优先级1(最高):0485(订单完成),你可以把取消对应的状态码也补充到这一档
- 优先级2:所有中间流转状态(比如示例里的0016、0028、0215等)
- 优先级3(最低):0002(订单创建)
写法1:窗口函数实现(适配支持窗口函数的数据库,比如MySQL8.0+、PostgreSQL、SQL Server等)
这种写法逻辑清晰,执行效率也更高:
SELECT OrderNumber, OrderStatus FROM ( SELECT A.OrderNumber, C.OrderStatus, -- 按业务规则给状态打优先级,同一个订单里优先级数值越小排越靠前 ROW_NUMBER() OVER ( PARTITION BY A.OrderNumber ORDER BY CASE C.OrderStatus WHEN '0485' THEN 1 -- 完成优先级最高,有取消状态也可以加一行 WHEN '取消状态码' THEN 1 WHEN '0002' THEN 3 ELSE 2 -- 其他中间状态统一归为第二优先级,不用逐个枚举 END ASC ) AS rn FROM A INNER JOIN B ON B.OrderNo = A.OrderNo INNER JOIN C ON C.OrderStatus = B.OrderStat ) t WHERE rn = 1; -- 每个订单只取优先级最高的1条记录
用你给的示例数据测试的话,最终输出结果就是订单180仅保留0485完成状态的记录,订单560没有终态,会保留全部三条状态记录,完全符合需求。
写法2:子查询实现(适配低版本不支持窗口函数的数据库,比如MySQL5.x)
如果你用的数据库不支持窗口函数,可以用这种写法,也可以直接套进你原来的SQL结构里:
SELECT A.OrderNumber, C.OrderStatus FROM A INNER JOIN B ON B.OrderNo = A.OrderNo INNER JOIN C ON C.OrderStatus = B.OrderStat WHERE -- 条件1:当前记录本身就是完成/取消的终态 C.OrderStatus IN ('0485', '你的取消状态码') -- 条件2:当前订单本身就没有终态,保留所有状态记录 OR A.OrderNumber NOT IN ( SELECT DISTINCT B2.OrderNo FROM B B2 INNER JOIN C C2 ON C2.OrderStatus = B2.OrderStat WHERE C2.OrderStatus IN ('0485', '你的取消状态码') );
内容的提问来源于stack exchange,提问作者hekean1339
相关产品推荐
相关产品推荐

