You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django+PostgreSQL如何查询用户重复激活日期记录并停用多余旧记录

解决方案

方案1:Django ORM 实现(无原生SQL,适配性好)

利用Django的子查询功能,仅需两次数据库查询即可完成所有更新,完全避免Python层遍历:

from django.db.models import OuterRef, Subquery

# 1. 构造子查询:匹配每个user_id+sp_date分组下最新的激活记录ID
latest_active = DateClass.objects.filter(
    is_active=True,
    user_id=OuterRef("user_id"),
    sp_date=OuterRef("sp_date")
# 按主键倒序取第一条,有created_at字段建议替换为order_by("-created_at")
).order_by("-id").values("id")[:1]

# 可选:执行前先统计需要更新的记录数,验证逻辑正确性
# update_count = DateClass.objects.filter(is_active=True).exclude(id=Subquery(latest_active)).count()
# print(f"待更新重复记录数:{update_count}")

# 2. 批量更新所有重复的旧激活记录
DateClass.objects.filter(is_active=True).exclude(id=Subquery(latest_active)).update(is_active=False)

方案2:PostgreSQL 原生SQL实现(性能最优,适合大数据量场景)

直接用PostgreSQL的窗口函数,单次SQL即可完成操作,性能比ORM方案更高:

WITH ranked_active_records AS (
    SELECT
        id,
        -- 按user_id、sp_date分组,按插入顺序倒排(id自增可用id倒序,有created_at优先用created_at)
        ROW_NUMBER() OVER (PARTITION BY user_id, sp_date ORDER BY id DESC) AS row_num
    FROM 你实际的表名 -- 替换为DateClass对应的数据库表名,默认格式为`你的app名_dateclass`
    WHERE is_active = TRUE
)
UPDATE 你实际的表名
SET is_active = FALSE
WHERE id IN (SELECT id FROM ranked_active_records WHERE row_num > 1);

注意事项

  • 如果你模型中有created_at之类的创建时间字段,建议排序时优先用创建时间字段,比自增ID判断新旧更准确
  • 首次执行前建议先跑统计逻辑确认待更新的记录数符合预期,避免误操作
  • 两种方案的时间复杂度均为O(n),仅和表内总数据量相关,远优于原遍历方案的O(n²)级复杂度

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 01:06:04