当前位置:网站首页>使用MULTISET来比较数据集的实例介绍
使用MULTISET来比较数据集的实例介绍
2022-07-30 19:33:00 【JAVAQXQ】
使用普通SQL可能更难解决的问题是这样的问题:
哪些电影与给定的电影X有相同的演员?
像往常一样,我们在这个例子中使用sakila数据库。用SQL(例如PostgreSQL,具体来说)解决这个问题的可能方式是什么?下面的查询给出了每部电影的演员概况:
SELECT film_id, array_agg(actor_id ORDER BY actor_id) actors FROM film_actor GROUP BY film_id 复制代码
它产生的结果是这样的:
|film_id|actors | |-------|----------------------------------| |1 |{1,10,20,30,40,53,108,162,188,198}| |2 |{19,85,90,160} | |3 |{2,19,24,64,123} | |4 |{41,81,88,147,162} | |5 |{51,59,103,181,200} | |6 |{21,23,62,108,137,169,197} | |... |... | 复制代码
请注意,在SQL中,数组的行为就像列表一样,也就是说,它们保持着自己的排序,所以明确地对数组进行排序对于能够相互比较演员是很重要的。现在,我们想从上面找到所有共享相同演员集的电影:
WITH t AS ( -- Previous query SELECT film_id, array_agg(actor_id ORDER BY actor_id) actors FROM film_actor GROUP BY film_id ) SELECT array_agg(film_id ORDER BY film_id) AS films, actors FROM t GROUP BY actors ORDER BY count(*) DESC, films 复制代码
结果就是现在:
|films |actors | |--------|----------------------------------| |{97,556}|{65} | |{1} |{1,10,20,30,40,53,108,162,188,198}| |{2} |{19,85,90,160} | |{3} |{2,19,24,64,123} | |{4} |{41,81,88,147,162} | |{5} |{51,59,103,181,200} | |{6} |{21,23,62,108,137,169,197} | |... |... | 复制代码
所以,我们可以看到,只有2部电影共享相同的演员集,这些电影是 FILM_ID IN (97, 556)
。(Sakila数据库有点无聊,因为数据集是生成的)。
使用MULTISET比较
虽然上面的内容已经相当酷了,但在这篇文章中,我想展示一下 jOOQ 3.15 MULTISET 支持的 一个鲜为人知的功能,即它们可以相互比较的事实。
而且正如SQL标准 MULTISET
的性质一样,排序是不相关的,所以我们不需要为这种比较添加任何明确的 ORDER BY
子句。事实上,这并不是100%的不相关。你 可以 为投影目的对 MULTISET
,所以排序将由jOOQ维护。但是当你在谓词中使用它们时,jOOQ将覆盖你的 ORDER BY
子句。
使用jOOQ,我们可以写:
ctx.select(FILM.FILM_ID, FILM.TITLE) .from(FILM) .where( multiset( select(FILM_ACTOR.ACTOR_ID) .from(FILM_ACTOR) .where(FILM_ACTOR.FILM_ID.eq(FILM.FILM_ID)) ).eq(multiset( select(FILM_ACTOR.ACTOR_ID) .from(FILM_ACTOR) .where(FILM_ACTOR.FILM_ID.eq(97L)) )) ) .orderBy(FILM_ID) .fetch(); 复制代码
这比前一种形式的查询效率低一些,因为它从两个子查询中访问 FILM_ACTOR
表,尽管其中只有一个是相关的。使用默认的 JSONB
仿真,可以生成以下查询:
SELECT film.film_id, film.title FROM film WHERE ( SELECT coalesce( jsonb_agg(jsonb_build_array(v0) ORDER BY t.v0), jsonb_build_array() ) FROM ( SELECT film_actor.actor_id AS v0 FROM film_actor WHERE film_actor.film_id = film.film_id ) AS t ) = ( SELECT coalesce( jsonb_agg(jsonb_build_array(v0) ORDER BY t.v0), jsonb_build_array() ) FROM ( SELECT film_actor.actor_id AS v0 FROM film_actor WHERE film_actor.film_id = 97 ) AS t ) ORDER BY film.film_id 复制代码
我承诺,对于 MULTISET
,不需要 ORDER BY
子句,对于jOOQ代码来说,这仍然是真实的。然而,在幕后,jOOQ必须按JSON数组的内容排序,以确保两个 MULTISET
的值是相同的,无论其顺序如何。
其结果是与前面的结果显示的两个ID相同:
+-------+--------------+ |film_id|title | +-------+--------------+ | 97|BRIDE INTRIGUE| | 556|MALTESE HOPE | +-------+--------------+ 复制代码
比较MULTISET_AGG,而不是
如果你喜欢使用连接和 GROUP BY
来生成电影的演员 MULTISET
,你也可以用jOOQ来做。这一次,我们使用的是
- 隐式连接来简化对
FILM.TITLE
的访问,从FILM_ACTOR
- 在
HAVING
子句中的一个MULTISET
谓词,使用MULTISET_AGG
下面是jOOQ的版本:
ctx.select(FILM_ACTOR.FILM_ID, FILM_ACTOR.film().TITLE) .from(FILM_ACTOR) .groupBy(FILM_ACTOR.FILM_ID, FILM_ACTOR.film().TITLE) .having(multisetAgg(FILM_ACTOR.ACTOR_ID).eq(multiset( select(FILM_ACTOR.ACTOR_ID) .from(FILM_ACTOR) .where(FILM_ACTOR.FILM_ID.eq(97L)) ))) .orderBy(FILM_ACTOR.FILM_ID) .fetch(); 复制代码
后退,生成的SQL看起来像这样:
SELECT film_actor.film_id, alias_75379701.title FROM film_actor JOIN film AS alias_75379701 ON film_actor.film_id = alias_75379701.film_id GROUP BY film_actor.film_id, alias_75379701.title HAVING jsonb_agg( jsonb_build_array(film_actor.actor_id) ORDER BY film_actor.actor_id ) = ( SELECT coalesce( jsonb_agg(jsonb_build_array(v0) ORDER BY t.v0), jsonb_build_array() ) FROM ( SELECT film_actor.actor_id AS v0 FROM film_actor WHERE film_actor.film_id = 97 ) AS t ) ORDER BY film_actor.film_id 复制代码
请注意隐式连接是如何自动展开的,而 HAVING
谓词再次使用了通常的 JSONB
仿真,用于 MULTISET
和 MULTISET_AGG
。
替代方法
在上面的例子中,我们比较了投射单列的 MULTISET
表达式,换句话说, Result<Record1<Long>>
嵌套集合类型。jOOQ将始终确保你的查询类型检查和生成的SQL是正确的。
使用 MULTISET
的一个替代方法是使用 ARRAY_AGG
和 ARRAY
(现在你必须再次明确 ORDER BY
)。用jOOQ:
ctx.select(FILM_ACTOR.FILM_ID, FILM_ACTOR.film().TITLE) .from(FILM_ACTOR) .groupBy(FILM_ACTOR.FILM_ID, FILM_ACTOR.film().TITLE) .having(arrayAgg(FILM_ACTOR.ACTOR_ID) .orderBy(FILM_ACTOR.ACTOR_ID).eq(array( select(FILM_ACTOR.ACTOR_ID) .from(FILM_ACTOR) .where(FILM_ACTOR.FILM_ID.eq(97L)) .orderBy(FILM_ACTOR.ACTOR_ID) ))) .orderBy(FILM_ACTOR.FILM_ID) .fetch(); 复制代码
使用SQL:
SELECT film_actor.film_id, film.title FROM film_actor JOIN film ON film_actor.film_id = film.film_id GROUP BY film_actor.film_id, film.title HAVING array_agg(film_actor.actor_id ORDER BY film_actor.actor_id) = ARRAY ( SELECT film_actor.actor_id FROM film_actor WHERE film_actor.film_id = 97 ORDER BY film_actor.actor_id ) ORDER BY film_actor.film_id 复制代码
边栏推荐
- 牛客刷题系列之进阶版(搜索旋转排序数组,链表内指定区间反转)
- golang日志库zerolog使用记录
- MySQL database - views and indexes
- How architects grow
- LeetCode 0952. Calculate Maximum Component Size by Common Factor: Mapping / Union Search
- MySQL大批量造数据
- Range.CopyFromRecordset method (Excel)
- Trial writing C language sanbang
- M3SDA:用于多源域自适应的矩匹配
- After MySQL grouping, take the largest piece of data [optimal solution]
猜你喜欢
How to build FTP server under win2003
第十七届“振兴杯”全国青年 职业技能大赛——计算机程序设计员(云计算平台与运维)参赛回顾与总结
SimpleOSS third-party library libcurl and engine libcurl error solution
The advanced version of the cattle brushing series (search for rotating sorted arrays, inversion of the specified range in the linked list)
Different lower_case_table_names settings for server (‘1‘) and data dictionary (‘0‘) 解决方案
【MindSpore】多卡训练保存权重问题
The advanced version of the Niu Ke brushing series (team competition, sorting subsequences, inverting strings, deleting common characters, repairing pastures)
MindSpore:【模型训练】【mindinsight】timeline的时间和实际用时相差很远
MySQL八股文背诵版
Win11如何更改默认下载路径?Win11更改默认下载路径的方法
随机推荐
MySQL Functions (Classic Collection)
Range.CopyFromRecordset method (Excel)
部分分类网络性能对比
centos7安装mysql8
MySQL sub-database sub-table
crontab中写go run不执行的问题
阿里面试这些微服务还不会?那还是别去了,基本等通知
VBA connects Access database and Excel
MySQL kills 10 questions, how many questions can you stick to?
Start background services across processes
VBA 连接Access数据库和Excle
MySQL mass production of data
How do radio waves transmit information?
Zabbix 5.0 监控教程(一)
Talking about Contrastive Learning (Contrastive Learning) the first bullet
.eslintrc.js for musicApp
Witness the magical awakening of the mini world in HUAWEI CLOUD
iPhone真是十三香?两代产品完全对比,或许上一代更值得买
ERROR 1045 (28000) Access denied for user ‘root‘@‘localhost‘解决方法
The advanced version of the Niu Ke brushing series (team competition, sorting subsequences, inverting strings, deleting common characters, repairing pastures)