选择在其他记录列表中找不到的记录

Selecting records not found in other list of records

场景

玩家参加活动。如果他们要参加活动,他们应该提供信息。

待解决的问题

我想 select 尚未提供信息的玩家,如果他们计划参加特定活动。

你的目标

作为所用技术的初学者,非常感谢您对我在下面建议的解决方案进行改进的验证和建议。

解决方案

技术: python、postgreSQL 和 Pony ORM

Pony ORM 中的实体模型:

class Event(db.Entity):
    _table_ = "event"
    start = Required(date)
    players = Set("Attendance")


class Player(db.Entity):
    _table_ = "player"
    first_name = Optional(str)
    last_name = Required(str)
    phone_number = Required(str)
    email = Required(str)
    events = Set("Attendance")


class Attendance(db.Entity):
    _table_ = "attendance"
    event = Required(Event)
    player = Required(Player)
    status = Required(bool)
    PrimaryKey(event, player)

想法:

  1. 获取提供信息的玩家列表(如果他们参加活动)
  2. 获取不在 1 创建的列表中的玩家列表。

想法的当前实现:

players = select(p for p in Player if p not in select(p for p in Player
                 for a in Attendance if p == a.player and a.event == next_event))

可以重构您的查询以使其更简单。首先,我们可以将内部查询中 PlayerAttendance 的显式连接替换为通过属性访问的隐式连接:

select(p for p in Player if p not in select(p for p in Player
       for attendance in p.events if attendance.event == next_event))

为了进一步简化查询,我们可以通过编写表达式 p.events.event:

来使用 attribute lifting
select(p for p in Player if p not in select(
       p for p in Player if next_event in p.events.event))

p.events 表达式 returns 一组 Attendance 记录。在 Pony 中,当你有一个集合实例时,这个集合拥有它的项目的所有属性,当你访问这个属性时,你将得到一组对应项目属性的所有值。表达式 p.events.event 的值将是与特定玩家链接的所有 Event 个对象的集合。

简化查询的下一步是将生成器替换为 lambda。这样查询看起来会更短一些:

Player.select(lambda p: p not in Player.select(
    lambda p: next_event in p.events.event))

但如果我们意识到内部查询是不必要的并将查询重写为:

,则可以实现最大的简化
Player.select(lambda p: next_event not in p.events.event)

我认为这是使用 PonyORM 编写此查询的最简洁的方式