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

如何用MySQL或关系代数查询完全共游地点的用户对?

嘿,我来帮你搞定这个找出满足地点访问包含关系的用户对的问题!

首先先把你的样本访问记录整理成清晰的表格:

NamePlace
AshNew york
BobNew york
AshChicago
BobChicago
CarlChicago
CarlDetroit
DanDetroit

咱们的需求是:找出其中一人访问的所有地点,另一人全部都访问过的用户对,比如示例里的Ash和Bob,他俩的访问地点完全重合,互相满足包含关系。

下面给你两种MySQL的实现方案,按需选择:

方案一:用排除法验证包含关系(兼容所有MySQL版本)

这种方法不依赖特殊函数,兼容性更好:

SELECT DISTINCT
    a.name AS user1,
    b.name AS user2
FROM
    visit_records a
JOIN
    visit_records b ON a.name <> b.name
WHERE
    NOT EXISTS (
        -- 检查用户a有没有用户b没去过的地点
        SELECT 1
        FROM visit_records c
        WHERE c.name = a.name
        AND NOT EXISTS (
            SELECT 1
            FROM visit_records d
            WHERE d.name = b.name
            AND d.place = c.place
        )
    )
ORDER BY user1, user2;

方案二:用聚合+JSON函数(MySQL 5.7+适用)

如果你的MySQL版本支持JSON函数,这种写法更简洁直观:

WITH user_places AS (
    -- 先把每个用户的访问地点聚合成JSON数组
    SELECT
        name,
        JSON_ARRAYAGG(place) AS places
    FROM visit_records
    GROUP BY name
)
SELECT
    a.name AS user1,
    b.name AS user2
FROM user_places a
JOIN user_places b ON a.name <> b.name
-- 直接判断a的地点数组是否是b的子集
WHERE JSON_CONTAINS(b.places, a.places)
ORDER BY user1, user2;

逻辑说明

  • 方案一:核心是反向验证——如果找不到用户A有但用户B没去过的地点,就说明A的所有地点都被B覆盖了。用DISTINCT是为了避免重复的用户对(比如(Ash,Bob)和(Bob,Ash)都会被查出来),要是你只需要单向的对,把a.name <> b.name改成a.name < b.name就行。
  • 方案二:先把每个用户的地点打包成数组,再用JSON_CONTAINS直接判断子集关系,代码更易懂,但需要MySQL 5.7及以上版本支持。

结果测试

用你的样本数据跑上面的查询,会得到:

user2
Bob
Ash

如果改成单向的条件,就只会得到Ash | Bob这一对。

内容的提问来源于stack exchange,提问作者Alice Smith

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:20:48