查询将查找与 user2 发布相同标记集的用户

问题描述 投票:0回答:1

我有一个表 ORDERS,其中包含“user”、“mark”和“mark_cnt”列。 我需要编写这样一个 sql 查询,它将输出那些与 user2 具有相同标记集的用户。他有 1 个 m1、2 个 m2 和 1 个 m4。所以,基本上,这意味着该集合必须与其他用户标记完全相交。

U1 有:m1、m2、m2、m3、m4、m4、m4
U2 有:m1、m2、m2、m4
U3 有:m1、m2、m2、m2、m3、m3、m3、m3、m3、m3、m3、m4、m4、m4、m5
U4 有:m1、m2、m4

我尝试使用此代码:

select user
from orders
where mark in  (
               select mark from orders where user='u2'
               )
group by user
having count(mark) = (select count(mark) from order where user='u2')

click here to see table image

正确答案一定是U1和U3

sql clickhouse dml
1个回答
0
投票

我使用问题中的数据和尽力解决方案创建了一个 DBFiddle。


我阅读问题的方式是,为了让用户 A 与用户 B 匹配,用户 A 的标记多重集必须是用户 B 多重集的子集。 U1 和 U3 配对满足此条件,但其他配对也满足此条件。例如,U4 和 U1 对。

字面解释是用户 A 的多重集必须完全等于用户 B 的多重集,但这不会产生任何答案。放宽该条件以排除根本不包含在其中一个多重集中的元素将产生 U1 和 U2 作为答案,这与建议的正确答案不同。

由于问题与预期答案相矛盾,这是一个“尽力而为”的答案,您应该澄清包含该行的实际情况。例如,您可以解释为什么 U1 和 U3 是“唯一”答案,或者答案中还有哪些其他对。我不符合在评论中询问的声誉:P

以下是查询的解释:

从显而易见的开始:我们想要
    SELECT
  1. 表中的
    orders
    用户名:
    
    
  2. select "user" from orders
让我们将每个订单与包含相同标记的所有其他订单进行匹配。使用带有条件的联接并添加表别名以消除歧义:
  1. select o1."user" from orders o1 inner join orders o2 on o1.mark = o2.mark
过滤掉来自同一用户的成对行:
  1. select o1."user" from orders o1 inner join orders o2 on ( o1."user" != o2."user" and o1.mark = o2.mark )
现在让我们通过比较计数来看看订单是否是子集。我们现在还将包含第二个用户名:
  1. select o1."user", o2."user", o2.mark_cnt >= o1.mark_cnt as "is_subset" from orders o1 inner join orders o2 on ( o1."user" != o2."user" and o1.mark = o2.mark )
现在我们只想保留所有行都是 
    is_subset
  1. 的用户对的语句。使用带有聚合函数的
    GROUP BY
    来计算每对所有行的逻辑
    AND
    
    
  2. select o1."user", o2."user" from orders o1 inner join orders o2 on ( o1."user" != o2."user" and o1.mark = o2.mark ) group by o1."user", o2."user" having bool_and( o2.mark_cnt >= o1.mark_cnt )
最后,请注意,
    INNER JOIN
  1. 变体将删除与用户 2 没有等效项的任何订单。相反,我们希望测试失败,因为这意味着其中一个标记不匹配。我们将使用
    LEFT JOIN
    来“优先考虑”用户 1 中的行。由于我们切换到外连接,我们还需要使用
    o2.mark_cnt
    来处理可能是
    NULL
    coalesce
    :
    
    
  2. select o1."user", o2."user" from orders o1 left join orders o2 on ( o1."user" != o2."user" and o2.mark = o1.mark ) group by o1."user", o2."user" having bool_and( coalesce(o2.mark_cnt, 0) >= o1.mark_cnt )
© www.soinside.com 2019 - 2024. All rights reserved.