在Django中筛选Code唯一值并保留最新添加记录的解决方案
按Code去重并保留最新记录的解决方案
需求说明
现有数据表包含id、code、name、status、user_id字段,需按code字段去重,且保留每个code对应的最新添加记录。
原始数据
id Code name status last added 1 23-07-00001 red 1 2023-07-11 02:48:41.025713 2 23-07-00002 orange 2 2023-07-11 02:48:41.025713 3 23-07-00003 blue 3 2023-07-12 05:18:47.534430 4 23-07-00002 orange 4 2023-07-12 05:24:40.485039
期望结果
1 23-07-00001 red 1 2023-07-11 02:48:41.025713 3 23-07-00003 blue 3 2023-07-12 05:18:47.534430 4 23-07-00002 orange 4 2023-07-12 05:24:40.485039
尝试过的无效代码
item_data = TevIncoming.objects.filter(status__in=retrieve).select_related().values_list('code', flat=True).distinct().order_by('-incoming_in').reverse()
注:这段代码仅返回去重后的code值,且distinct与order_by结合时会受排序字段影响,无法直接获取完整的最新记录。
解决方案
Django原生方案
方法1:子查询获取最新记录ID(推荐)
通过子查询定位每个code对应的最新记录ID,再筛选出这些记录,准确性最高:
from django.db.models import Subquery, OuterRef # 子查询:获取每个code的最新记录ID(按incoming_in倒序取第一条) latest_record_ids = TevIncoming.objects.filter( status__in=retrieve, code=OuterRef('code') ).order_by('-incoming_in').values('id')[:1] # 筛选出所有最新记录 item_data = TevIncoming.objects.filter( status__in=retrieve, id__in=Subquery(latest_record_ids) ).select_related()
方法2:先获取最新时间再关联查询
先统计每个code的最新添加时间,再匹配对应的记录:
from django.db.models import Max # 统计每个code的最新incoming_in时间 latest_times = TevIncoming.objects.filter(status__in=retrieve) \ .values('code') \ .annotate(latest_in=Max('incoming_in')) # 匹配时间和code,获取完整记录 item_data = TevIncoming.objects.filter( status__in=retrieve, code__in=latest_times.values('code'), incoming_in__in=latest_times.values('latest_in') ).select_related()
注:若存在同一code多条记录添加时间完全相同的情况,此方法会返回多条,需根据业务补充筛选逻辑(如取最大id)。
SQL原生方案
方法1:窗口函数(推荐,支持PostgreSQL、MySQL 8.0+、SQL Server等)
用ROW_NUMBER()窗口函数按code分组并排序,取每组第一条:
SELECT id, code, name, status, last_added FROM ( SELECT id, code, name, status, last_added, -- 按code分组,按添加时间倒序编号 ROW_NUMBER() OVER (PARTITION BY code ORDER BY last_added DESC) AS row_num FROM tev_incoming WHERE status IN (1,2,3,4) -- 替换为你的retrieve列表值 ) AS sub_query WHERE row_num = 1;
方法2:关联查询(兼容老版本数据库)
先分组获取每个code的最新时间,再关联原表获取记录:
SELECT t1.* FROM tev_incoming t1 INNER JOIN ( SELECT code, MAX(last_added) AS latest_time FROM tev_incoming WHERE status IN (1,2,3,4) -- 替换为你的status值 GROUP BY code ) t2 ON t1.code = t2.code AND t1.last_added = t2.latest_time WHERE t1.status IN (1,2,3,4);
注:若同一code存在相同最新时间的记录,此方法会返回多条,可添加AND t1.id = (SELECT MAX(id) FROM tev_incoming WHERE code = t2.code AND last_added = t2.latest_time)来取最大ID的记录。
内容的提问来源于stack exchange,提问作者marivic valdehueza
相关产品推荐
相关产品推荐

