多列主键最小值计算及特定账单ID销售数据查询技术问询
嘿,我来帮你梳理这两个问题的解决方案,都是实际业务里常用的思路:
一、多列联合主键的最小值计算方法
多列联合主键的最小值,核心逻辑就是按主键定义的顺序逐列比较,类似字典排序规则:先比第一列,第一列值相同再比第二列,以此类推。分两种常用场景来说:
场景1:获取全表中联合主键最小的记录
最直接的方式是按主键列排序后取首行,也可以用聚合函数组合匹配,两种方法都靠谱:-- 方法1:排序取首行(简洁直观) SELECT * FROM your_table ORDER BY col1, col2 LIMIT 1; -- 方法2:聚合函数匹配最小组合(适合复杂场景) SELECT * FROM your_table WHERE (col1, col2) = ( SELECT MIN(col1), MIN(col2) FROM your_table WHERE col1 = (SELECT MIN(col1) FROM your_table) );场景2:分组统计每组的最小联合主键
如果需要按某个字段分组,取每组内主键最小的记录,用窗口函数ROW_NUMBER()是最清晰的写法:SELECT t.* FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY group_col ORDER BY pk_col1, pk_col2) AS rn FROM your_table ) t WHERE t.rn = 1;
二、特定bill_id的sales数据查询方案(处理添加后移除的情况)
先理清楚业务逻辑:sales是原账单的商品记录,sales_plus是后续的添加/移除操作,它的联合主键是sales_id+status,所以同一个sales记录(对应一个商品)可能同时存在add和remove操作,也就是你说的“添加后又被移除”的情况。
核心思路
先筛选出所有确实经历了“添加→移除”流程的sales_id(要排除只有remove没有add的无效操作),然后查询目标账单的sales数据时,排除这些已被最终移除的商品。
具体SQL实现
-- 第一步:找出所有有效移除的sales_id(添加后再移除) WITH removed_sales AS ( SELECT sp.sales_id FROM sales_plus sp WHERE sp.status = 'remove' -- 确保该商品之前有过添加操作 AND EXISTS ( SELECT 1 FROM sales_plus sp_add WHERE sp_add.sales_id = sp.sales_id AND sp_add.status = 'add' -- 可选:确保移除操作在添加之后,符合时间逻辑 AND sp_add.time < sp.time ) ) -- 第二步:查询目标bill_id的商品,排除已被移除的 SELECT s.* FROM sales s WHERE s.bill_id = '你的目标bill_id' -- 替换成实际要查询的bill_id AND s.id NOT IN (SELECT sales_id FROM removed_sales);
扩展:如果需要标记商品最终状态(而非排除)
如果业务需求是保留所有商品记录,但标记哪些是已移除的,可以用下面的写法:
WITH sales_final_status AS ( SELECT sp.sales_id, -- 判断是否存在添加后再移除的操作 CASE WHEN EXISTS ( SELECT 1 FROM sales_plus sp2 WHERE sp2.sales_id = sp.sales_id AND sp2.status = 'remove' AND sp2.time > sp.time ) THEN 'removed' ELSE 'active' END AS final_status FROM sales_plus sp WHERE sp.status = 'add' UNION ALL -- 处理只有移除没有添加的无效操作 SELECT sp.sales_id, 'invalid_remove' AS final_status FROM sales_plus sp WHERE sp.status = 'remove' AND NOT EXISTS ( SELECT 1 FROM sales_plus sp2 WHERE sp2.sales_id = sp.sales_id AND sp2.status = 'add' ) ) SELECT s.*, -- 原商品没有后续操作的话,标记为original COALESCE(ss.final_status, 'original') AS final_status FROM sales s LEFT JOIN sales_final_status ss ON s.id = ss.sales_id WHERE s.bill_id = '你的目标bill_id';
关键说明
- 加入
sp_add.time < sp.time是为了符合业务逻辑:移除操作必须在添加之后,避免乱序的无效操作影响结果 - 用CTE(公共表表达式)拆分逻辑,让SQL更易读、易维护
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

