实现一个数组中所有元素必须匹配的子句的最简单和最快的方法是什么?在使用IN时不仅仅是一个子句?毕竟它应该像
mongodb’s $all一样。
思考session_users是conversation_id和user_id之间的连接表的组对话我有这样的想法:
WHERE (conversations_users.user_id ALL IN (1,2))
更新16.07.12
添加有关模式和大小写的更多信息:
>连接表很简单:
Table "public.conversations_users" Column | Type | Modifiers | Storage | Description -----------------+---------+-----------+---------+------------- conversation_id | integer | | plain | user_id | integer | | plain |
一个对话有很多用户,一个用户属于很多对话。为了找到对话中的所有用户,我正在使用此连接表。
>最后我试图找出一个轨道范围上的红宝石,发现我是一个谈话,取决于它的参与者 – 例如:
scope :between,->(*users) { joins(:users).where('conversations_users.user_id all in (?)',users.map(&:id)) }
更新23.07.12
我的问题是找到一个完全匹配的人。因此:
(1,2,3)之间的对话将不匹配,如果查询(1,2)
假设连接表遵循良好的实践,并且具有定义的唯一复合键,即防止重复行的约束,则类似于以下简单查询应该做的事情。
select conversation_id from conversations_users where user_id in (1,2) group by conversation_id having count(*) = 2
请注意,最后的数字2是user_ids列表的长度。如果user_id列表改变长度,那显然需要改变。如果您不能假设您的连接表不包含重复项,则将“count(*)”更改为“count(distinct user_id)”,可能会导致性能降低。
此查询查找包含所有指定用户的所有会话,即使会话也包含其他用户。
如果您只想要与指定的用户组进行对话,一种方法是在where子句中使用嵌套子查询,如下所示。注意,第一行和最后一行与原始查询相同,只有中间的两行是新的。
select conversation_id from conversations_users where user_id in (1,2) and conversation_id not in (select conversation_id from conversation_users where user_id not in (1,2)) group by conversation_id having count(*) = 2
同样,如果数据库支持,您可以使用设置的差异运算符。以下是Oracle语法中的一个示例。 (对于Postgres或DB2,将关键字“minus”更改为“except”。)
select conversation_id from conversations_users where user_id in (1,2) group by conversation_id having count(*) = 2 minus select conversation_id from conversation_users where user_id not in (1,2)
一个好的查询优化器应该相同地处理最后两个变体,但请确保与您的特定数据库进行检查。例如,Oracle 11GR2查询计划在应用减号运算符之前对两组会话ID进行排序,但跳过最后一个查询的排序步骤。因此,查询计划可能会更快,这取决于多个因素,如行数,内核,缓存,索引等。