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

MySQL中如何求和并标记最接近月度最高津贴限额的对应数据行

这个需求本质是分组求解0-1背包问题,每个kids_id+date为独立分组,分组的背包容量为monthly_max_allowance,物品为分组内的每条津贴记录,重量与价值均为allowance,目标是找到总价值不超过容量的最大值对应物品集合。根据数据规模和精度要求可以选以下两种方案:

方案1:贪心算法(适配大数据量,SQL可直接实现,性能最优)

如果业务允许优先选择金额更高的津贴记录凑额度(你提供的示例数据完全符合该规则的输出结果),可以直接用窗口函数累加实现,时间复杂度为O(n log n),支持千万级数据批量运行:

验证查询SQL

WITH ranked_records AS (
    SELECT 
        *,
        -- 同分组内按金额降序排序,金额相同则按转账日期升序优先选更早的记录
        SUM(allowance) OVER (
            PARTITION BY kids_id, date 
            ORDER BY allowance DESC, money_transfer_date ASC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) AS running_total
    FROM 你的表名
)
SELECT 
    kids_id, date, allowance, money_transfer_date, monthly_max_allowance,
    CASE WHEN running_total <= monthly_max_allowance THEN 1 ELSE 0 END AS calculated_to_keep
FROM ranked_records;

表更新SQL

UPDATE 你的表名 t1
JOIN (
    SELECT 
        kids_id, date, money_transfer_date,
        CASE WHEN SUM(allowance) OVER (
            PARTITION BY kids_id, date 
            ORDER BY allowance DESC, money_transfer_date ASC
            ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        ) <= monthly_max_allowance THEN 1 ELSE 0 END AS new_to_keep
    FROM 你的表名
) t2 ON t1.kids_id = t2.kids_id 
    AND t1.date = t2.date 
    AND t1.money_transfer_date = t2.money_transfer_date
SET t1.to_keep = t2.new_to_keep;

方案2:动态规划精确解(适用于单分组记录数≤15的场景,结果100%符合要求)

如果必须枚举所有组合得到完全精确的最优解,纯SQL无法高效处理组合爆炸问题,建议用外部脚本批量处理,以下是Python实现示例:

import pandas as pd
import pymysql

# 数据库连接配置
conn = pymysql.connect(
    host="你的数据库地址",
    user="用户名",
    password="密码",
    database="库名"
)
cursor = conn.cursor()

# 先重置所有to_keep为0
cursor.execute("UPDATE 你的表名 SET to_keep = 0")
conn.commit()

# 获取所有独立分组
groups = pd.read_sql("SELECT DISTINCT kids_id, date, monthly_max_allowance FROM 你的表名", conn)

for _, group in groups.iterrows():
    kid_id = group['kids_id']
    stat_date = group['date']
    max_allowance = group['monthly_max_allowance']
    # 获取当前分组所有记录
    records = pd.read_sql(
        f"SELECT id, allowance FROM 你的表名 WHERE kids_id = {kid_id} AND date = {stat_date}", 
        conn
    )
    n = len(records)
    if n == 0:
        continue
    # 0-1背包动态规划
    dp = [0] * (max_allowance + 1)
    # 记录最优组合的id列表
    best_ids = [[] for _ in range(max_allowance + 1)]
    
    for idx, row in records.iterrows():
        allow = row['allowance']
        rec_id = row['id']
        # 倒序遍历避免重复选
        for j in range(max_allowance, allow - 1, -1):
            if dp[j - allow] + allow > dp[j]:
                dp[j] = dp[j - allow] + allow
                best_ids[j] = best_ids[j - allow] + [rec_id]
    # 找到最大的不超过限额的总和
    max_sum = max(dp)
    target_ids = best_ids[dp.index(max_sum)]
    if target_ids:
        # 批量更新标记
        id_str = ','.join(map(str, target_ids))
        cursor.execute(f"UPDATE 你的表名 SET to_keep = 1 WHERE id IN ({id_str})")
        conn.commit()

cursor.close()
conn.close()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:36:03