确定值列表是否完全满足一对多关系的最有效方法(MySQL)

l3u*_*fly 5 php mysql database relational-database

我和房间之间有一对多的关系:

Room | User
1    | 1
1    | 2
1    | 4
2    | 1
2    | 2
2    | 3
2    | 5
3    | 1
3    | 3
Run Code Online (Sandbox Code Playgroud)

给定一个用户列表,例如1,3,确定哪个房间完全/完全由他们填充的最有效方法是什么?所以在这种情况下,它应该返回3号房间,因为虽然它们都在2号房间,但是2号房间也有其他居住者,这不是一个"完美"的契合.

我可以想到几个解决方案,但我不确定效率.例如,我可以按用户(按升序排序)分组连接组,这将为我提供逗号分隔的字符串,如"1,2,4","1,2,3,5"和"1, 3" .然后我可以命令我的输入列表升序并寻找与"1,3"的完美匹配.

或者我可以计算一个房间中的用户总数并包含用户1和3.然后,我将选择具有等于2的用户数的房间.

注意我想要最有效的方式,或者至少可以扩展到数百万用户和房间.每个房间将有大约25个用户.我想要考虑的另一件事是如何将此列表传递给数据库.我应该通过连接AND userid = 1 AND userid = 3 AND userid = 5等构建查询吗?或者有没有办法将值作为数组传递给存储过程?

任何帮助,将不胜感激.

Per*_*DBA 2

例如,我可以对按房间分组的用户(按升序排列)进行组连接,这将为我提供逗号分隔的字符串,例如“1,2,4”、“1,2,3,5”和“1, 3”。然后我可以对输入列表进行升序排序并寻找与“1,3”的完美匹配。

首先,提一句建议,提高你作为开发人员的功能水平。不要再用 CSV 来思考数据和解决方案。它限制您使用电子表格术语进行思考,并阻止您使用关系数据术语进行思考。你不需要构造字符串,然后匹配字符串,当数据在数据库中时,你可以在那里匹配它。

解决方案

那么,用关系数据术语来说,您到底想要什么?您希望房间中与您的参数用户列表匹配的用户数量最多。那是对的吗 ?如果是这样,代码就很简单了。

你还没有给表。我假设前两个是room, user, room_user,致命的,第三个是复合键。ids我可以给你 SQL 解决方案,你必须弄清楚如何在非 SQL 中做到这一点。

我要考虑的另一件事是如何将此列表传递到数据库。我应该通过连接 AND userid = 1 AND userid = 3 AND userid = 5 等来构造查询吗?或者有没有办法将值作为数组传递到存储过程中?

  1. 要将列表传递给存储过程,因为它需要一个调用参数,其长度是可变的,所以您必须创建一个 CSV 用户列表。让我们调用该 parm @user_list. (注意,这不是考虑数据,而是将列表传递给单个 parm 中的过程,因为否则您无法将未知数量的已识别用户传递给过程。)

  2. 由于您在客户端上构建了@user_list,因此您也可以@user_count在客户端上计算(列表中的成员数量),并将其传递给过程。

就像是:

CREATE PROC room_user_match_sp (
    @user_list    CHAR(255),
    @user_count   INT
    ...
    )
AS
    -- validate parms, etc
    ...
SELECT  room_id,
        match_count,
        match_count / @user_count * 100 AS match_pct
    FROM  (
        SELECT  room_id,
                COUNT(user_id) AS match_count -- no of users matched
            FROM room_user
            WHERE user_id IN ( @user_list )
            GROUP BY room_id                  -- get one row per room
            ) AS match_room                   -- has any matched users
    WHERE match_count = MAX( match_count )    -- remove this while testing
Run Code Online (Sandbox Code Playgroud)

目前尚不清楚,如果您只想完整匹配。在这种情况下,请使用:

    WHERE match_count = @user_count
Run Code Online (Sandbox Code Playgroud)

期待

您要求基于过程的解决方案,所以我已经给出了。是的,这是最快的。但请记住,对于这种需求和解决方案,您可以在客户端构建 SQL 字符串,并以通常的方式在“服务器”上执行它,而不需要使用过程。这里的过程更快,只是因为代码被编译并且该步骤被删除,而不是每次客户端使用 SQL 字符串调用“服务器”时执行该步骤。

我在这里要表达的观点是,使用合理的关系形式的数据,您可以使用单个SELECT语句获得您正在寻求的结果,您不必混乱工作表或临时表或中间步骤,这需要一个过程 在这里,过程不是必需的,您出于性能原因而实现过程。

我之所以指出这一点,是因为从你的问题中可以清楚地看出,你对解决方案的期望是“哎呀,我无法直接得到结果,我先处理数据,我准备好并愿意这样做”。仅当数据不是关系数据时才需要此类中间工作步骤。