mysql - 获取表A中的所有记录,如果满足表B的条件

标签 mysql select

我想获取每个奖金(bonus_records.uid - 唯一 ID)的最后更新(ma​​x(bonus_records.id))然后满足以下条件:

  1. 从未被指定玩家兑换过
  2. 已被指定玩家兑换但兑换次数少于redeem_count 超过
  3. 在上述时刻兑换并激活的奖金(是字段为 completedcanceled 为 0 的奖金)

附加信息:如果redeem_count等于0,则表示该赠金没有兑换限额

这是数据库的基本结构:

enter image description here

DB-FIDDLE

DB-FIDDLE v2 (With @Solarflare query)

DB-FIDDLE v3

我的查询失败:

SELECT MAX(br1.id) /* Get last update of bonus */,
    br1.uid,
    br1.name, 
    rb1.instance_id,
    rb1.player_id,
    br1.redeem_count,
    rb1.executed,
    rb1.completed,
    rb1.canceled
FROM 
    bonus_records br1
LEFT JOIN
    redeemed_bonuses rb1 ON 
    rb1.bonus_id = br1.id
WHERE 
    (rb1.player_id IS NULL) OR /* never redeemed */
    (rb1.player_id = 1 AND /* if redeemed then */
        (
            br1.redeem_count > ( /* total count of X redemed bonus is less then redeem_count but redeem_count <> 0 */
                SELECT COUNT(*)
                FROM redeemed_bonuses rb2
                INNER JOIN bonus_records br2 ON rb2.bonus_id = br2.id
                WHERE br2.uid = br1.uid AND rb2.completed = 0 AND rb2.canceled = 0
            ) OR
            br1.redeem_count = 0 /* redeem_count = 0 means that there is no established limit of redeem  */
        )
    )
GROUP BY 
    br1.uid

预期结果:

如果我有这个奖励列表:

enter image description here

和这个兑换的奖金列表:

enter image description here

那么 player_id = 1 的预期结果奖励列表将是:

enter image description here

最佳答案

您的查询/逻辑中存在一些问题:

  • select max(id), name, ... group by uid为您提供具有最大 id 的行。它将为您提供最大 ID 以及该组中任何 行的值。如果每组只有一行(例如,如果 uid 是唯一的/主键),那可能就是您要查找的行,否则无法确定(并且对于 MySQL 5.7 将失败),请参阅 MySQL Handling of GROUP BY以及关于 stackoverflow 关于 sql_mode=only_full_group_by 的错误消息的任何问题.

  • left join ... ON bonus_id = id where rb1.player_id IS NULL 如果有 any 玩家兑换了此 bonusid,则该值为 false。如果您将 playerid 包含在 on 条件中,则如果玩家不会为给定的 uid 兑换所有不同的 id,则为真(这可能是不可能的)。

  • 自从您通过rb1.bonus_id = br1.id加入并将您的条件应用于此id(但不是 uid):如果有一些旧条目具有更大的 redeem_count,即使有一个最新的 id 具有较低的 redeem_count,它也会评估为 true >(这不会成为 group by 的一部分,因为您将其过滤掉了)。

  • 相反,您可能需要在 left join 之后应用过滤器,例如使用 group by ... having ...select ...来自(选择...分组依据...)其中...

话虽如此,我不会修复您的查询(尽管它可能是可以挽救的),但会为您写一个具有新结构的新查询。

将其分解为多个步骤,首先,获取所有有效奖金的列表:

select * from bonus_records br
where not exists 
  (select 1 from bonus_records br1
   where br1.uid = br.uid and br1.id > br.id);

下一步是检查特定玩家兑换特定 uid 的频率(uid 信息通过检查 bonus_records 表获得):

select br.uid, count(*) 
from redeemed_bonuses rb
join bonus_records br on br.id = rb.bonus_id
where rb.player_id = 1
   and not (rb.completed = 0 and rb.canceled = 0) 
group by br.uid;

条件not (rb.completed = 0 and rb.canceled = 0)根据评论修改为符合要求。

现在加入这两个并应用您关于实际计数低于 redeem_count 的条件:

select pb.*, rd.actual_count from 
  (select * from bonus_records br
   where not exists 
     (select 1 from bonus_records br1
      where br1.uid = br.uid and br1.id > br.id)
  ) pb -- active potential bonuses
left join  
  (select br.uid, count(*) as actual_count 
   from redeemed_bonuses rb
   join bonus_records br on br.id = rb.bonus_id
   where rb.player_id = 1
      and not (rb.completed = 0 and rb.canceled = 0) 
   group by br.uid
  ) rd -- redeemed bonuses by that user
on pb.uid = rd.uid 
where rd.actual_count is null            -- uid never redeemed (left join empty)
   or rd.actual_count < pb.redeem_count  -- still some remaining
   or pb.redeem_count = 0                -- unlimited bonus

关于mysql - 获取表A中的所有记录,如果满足表B的条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56117372/

相关文章:

javascript - 当鼠标悬停在列表中的每个选择选项上时做一些事情(javascript)

MySQL 获取特定用户的结果

php - Codeigniter 下拉值不显示

php - 创建一个 php 脚本来使用 Mysql 数据库显示随机图像

mysql - 添加两列的简单 SQL 测试

mysql - 计算 MySQL 列中子字符串的出现次数

php - 选择今天的日期

mysql - 在 MySQL 中创建的 VIEW 使用 SELECT 给出错误的输出

MySQL Select 查询无法获取连续每一天的 id

javascript - JSON 到输入选择的选项