SQL如何实现仅保留同一登录账号首次的盈亏值,重复记录置0
方案实现说明
该需求完全可以通过SQL实现,核心逻辑是先定位每个login的首次出现记录,仅保留这类记录的profit/loss(盈亏)原值,其余非首次记录的盈亏字段统一设置为0。
前置说明:要判定“首次出现”的规则,必须依托一个能标识记录先后顺序的字段,比如表的自增主键
id、交易时间字段trade_time,没有这类时序/唯一标识字段的话,无法准确定位同一login的最早出现记录。
场景1:仅查询时动态返回调整后的值,不修改原表数据
如果不需要改动原表存储的原始盈亏值,只需要在查询结果里呈现调整后的效果,可以根据所用数据库的版本选择对应实现方式。
支持窗口函数的数据库(MySQL 8.0+、PostgreSQL、SQL Server等)
用ROW_NUMBER()按login分区、按顺序字段排序给每条记录编序号,序号为1的就是首次出现的记录:
SELECT login, CASE -- 首次出现记录保留原盈亏,其余返回0 WHEN ROW_NUMBER() OVER (PARTITION BY login ORDER BY id ASC) = 1 THEN `profit/loss` ELSE 0 END AS adjusted_profit_loss -- 其余需要返回的表字段按需追加,例如下方的*代表返回全表字段 ,* FROM your_table_name;
不支持窗口函数的低版本数据库(比如MySQL 5.x)
用子查询先统计每个login最早的记录ID,再关联判断是否为首次记录:
SELECT t.login, IF(t.id = login_first.min_id, t.`profit/loss`, 0) AS adjusted_profit_loss -- 其余需要返回的表字段按需追加 ,t.* FROM your_table_name t INNER JOIN ( -- 按login分组取最早的记录ID SELECT login, MIN(id) AS min_id FROM your_table_name GROUP BY login ) login_first ON t.login = login_first.login;
场景2:直接更新原表,将非首次记录的盈亏持久化为0
如果需要直接修改表内存储的数据,把所有非首次出现的记录盈亏永久改成0,可以执行UPDATE语句完成。
注意:执行更新操作前建议先开启事务校验影响的记录范围,确认无误后再提交,避免误操作覆盖原始数据。
支持窗口函数的数据库
UPDATE your_table_name SET `profit/loss` = 0 WHERE id IN ( -- 套一层子查询规避更新时同表查询的数据库限制 SELECT id FROM ( SELECT id FROM your_table_name -- 分区后编号大于1的都是非首次记录 WHERE ROW_NUMBER() OVER (PARTITION BY login ORDER BY id ASC) > 1 ) AS non_first_record );
低版本MySQL等不支持窗口函数的数据库
UPDATE your_table_name t INNER JOIN ( SELECT login, MIN(id) AS min_id FROM your_table_name GROUP BY login ) login_first ON t.login = login_first.login -- 非首次的记录统一把盈亏设为0 SET t.`profit/loss` = 0 WHERE t.id <> login_first.min_id;
适配说明
- 如果业务上的“首次出现”不是按自增ID判定,而是按交易时间、下单时间等业务字段排序,只需要把代码里
ORDER BY id ASC替换为对应排序规则即可,比如ORDER BY trade_time ASC。 - 如果同一login同一时间可能存在多条记录,可以在ORDER BY后追加次级排序字段,避免首次记录判定随机。
- 上述逻辑完全覆盖需求场景:不管非首次记录原盈亏值是275还是300,只要不属于该login的首次记录,都会被设置为0,仅保留第一次的盈亏值。
内容的提问来源于stack exchange,提问作者Lukasz
相关产品推荐
相关产品推荐

