Data Engineer · DE / SQL

Meta 邀请关系SQL:会员与邀请人的预订差

自连接会员及直接邀请人,比较活跃预订副本数的最大绝对差,处理零预订。

题目重点:自连接会员及直接邀请人,比较活跃预订副本数的最大绝对差,处理零预订。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练member一行会员、inviter_id指直接邀请人;reservation active distinct copy计预订数量。题目未给schema与计数细则,这些是明示练习约定。
  • 无有效邀请pair返回NULL而非0;非活跃预订排除。是直接邀请关系,不沿祖先链比较。

解题路线

  1. 先按member聚合COUNT DISTINCT copy,过滤active。两侧预订原始行不能直接join,否则member m条×inviter n条产生笛卡尔放大。
  2. member m JOIN member inviter建立两种角色,自连接条件inviter.id=m.inviter_id;再LEFT JOIN预聚合counts两次,各侧COALESCE0。没有预订的合法会员仍参加差值。
  3. MAX(ABS(memberCount−inviterCount))才是largest absolute difference;不能只MAX有符号差,邀请人更多时负值的幅度可能最大。
  4. 不存在/NULL inviter不会形成pair,不用凭空创建匿名邀请人count0。如果数据有循环,直接pair仍可计算但业务合法性需另查。
  5. 输出若需达到max的pair,不在聚合里随便选memberId;先计算每pair差,再按政策取最大或所有tie。当前只返回标量。

手动走一遍

m预订1、inviter预订5,差4;另一pair 4与2差2,最大4。两侧均无active预订差0仍合法;只有无inviter会员时无pair结果NULL。

SQL 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

-- Training: member(member_id PK,inviter_id nullable), reservation(member_id,copy_id,status).
-- Active distinct reserved copies per member, zero when no active reservations.
-- Compare member to their direct inviter; no valid pairs -> NULL.
WITH counts AS (
 SELECT member_id,COUNT(DISTINCT copy_id) AS reserved
 FROM reservation WHERE status='active' GROUP BY member_id
)
SELECT MAX(ABS(COALESCE(a.reserved,0)-COALESCE(b.reserved,0))) AS max_reserved_difference
FROM member m JOIN member inviter ON inviter.member_id=m.inviter_id
LEFT JOIN counts a ON a.member_id=m.member_id
LEFT JOIN counts b ON b.member_id=inviter.member_id;

复杂度

R预订聚合到M会员,再会员自连接及两次counts join,通常hash O(R+M),COUNT DISTINCT按具体计划需去重内存/排序。字段别名清楚能避免两侧角色条件写反。

易错点与追问

容易失分的边界

  • 原始reservations直接两边join导致乘行。
  • 漏ABS使邀请人比成员多的差被忽略。
  • counts INNER JOIN丢零预订会员。

继续深挖

  • 预订数定义为不同书名而非副本时,COUNT对象如何改?
  • 需要整条邀请链的最大差,为什么必须递归/路径定义而不是同一自连接?
✓已复制微信号!