当前位置:网站首页>使用jOOQ将Oracle风格的隐式连接自动转换为ANSI JOIN
使用jOOQ将Oracle风格的隐式连接自动转换为ANSI JOIN
2022-08-02 00:05:00 【YYniannian】
虽然jOOQ主要被用作Java中嵌入动态SQL的内部SQL DSL,它提供了市场上最好的解决方案,但jOOQ也越来越多地被用于其次要功能之一。在jOOQ 3.9中引入的解析器主要是为了能够解析DDL语句,例如为代码生成目的对你的模式进行逆向工程,我们已经增加了越来越多的功能和SQL转换能力,使解析器能够作为一个独立的产品,通过命令行界面、我们的网站或通过普通的jOOQ API来使用。 在jOOQ 3.14中增加的一个功能,主要是对那些使用jOOQ作为分析器的人有用,就是将旧的Oracle风格的隐式连接转换为ANSI JOIN的能力。
为什么要避免 "隐式连接"?
大多数RDBMS供应商都支持旧的Oracle风格的隐式连接语法,并进行了适当的优化。在过去,在SQL-92之前,这就是我们用于内部连接表的方式,例如,在查询Sakila数据库时。
SELECT *
FROM actor a, film_actor fa, film f
WHERE a.actor_id = fa.actor_id
AND fa.film_id = f.film_id
复制代码
诚然,这个语法是很直观的。只要声明所有你想获取数据的表,然后确保只通过过滤匹配的主键/外键值来保留适当的数据。 当然,这可能会出大错。由于许多明显的原因,例如,当你在添加一个表之后忘记了一个连接谓词。如果查询是复杂的,这可能是很难调试的。解决方案是ANSI JOIN。从SQL-92开始(差不多30年了!),这就是我们在大多数RDBMS中的连接方式。
SELECT *
FROM actor a
JOIN film_actor fa ON a.actor_id = fa.actor_id
JOIN film f ON fa.film_id = f.film_id
复制代码
虽然仍然有可能定义错误的连接谓词,但至少不再有可能忘记一个谓词,因为这在语法上是不正确的(除了MySQL,遗憾的是,在那里,ON子句是可选的)。
SELECT *
FROM actor a
JOIN film_actor fa -- Syntax error
JOIN film f -- Syntax error
复制代码
jOOQ的隐式JOIN
注意,人们通常把上述语法称为 "隐式连接",而JPQL和jOOQ回收了另一种"隐式连接 "的术语,它是基于外键路径的,甚至比ANSI SQL语法更不容易出错。使用jOOQ,上述查询可以写成如下。
ctx.select(
FILM_ACTOR.actor().asterisk(),
FILM_ACTOR.asterisk(),
FILM_ACTOR.film().asterisk())
.from(FILM_ACTOR)
.fetch();
复制代码
仅仅在查询中存在这些to-one的关系路径,就会隐含地将适当的LEFT JOIN
或INNER JOIN
添加到FROM
子句中。这只是在普通ANSI JOIN之上的便利,而不是替代。
改造Oracle的隐式连接
当你有一个旧的代码库,你希望升级并将所有的查询转换为使用ANSI JOIN时,请使用jOOQ来实现。你可以使用jOOQ的编程功能(如前所述),或免费网站www.jooq.org/translate。在网站上,只需选择 "Oracle风格到ANSI JOIN "选项,在左边放置以下SQL:输入
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM
actor a,
film_actor fa,
film f,
film_category fc,
category c
WHERE a.actor_id = fa.actor_id
AND fa.film_id = f.film_id
AND fc.category_id = c.category_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
输出
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM actor a
JOIN film_actor fa
ON a.actor_id = fa.actor_id
JOIN film f
ON fa.film_id = f.film_id
CROSS JOIN (
film_category fc
JOIN category c
ON fc.category_id = c.category_id
)
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
然后......呼啦啦。输出正确地显示了结果,不需要的CROSS JOIN,因为其中一个连接谓词丢失了:是的,这个工具已经帮了大忙!让我们来修正输入的查询。让我们来修正输入的查询:修正输入
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM
actor a,
film_actor fa,
film f,
film_category fc,
category c
WHERE a.actor_id = fa.actor_id
AND fa.film_id = f.film_id
AND f.film_id = fc.film_id -- This was missing
AND fc.category_id = c.category_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
固定输出
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM actor a
JOIN film_actor fa
ON a.actor_id = fa.actor_id
JOIN film f
ON fa.film_id = f.film_id
JOIN film_category fc
ON f.film_id = fc.film_id
JOIN category c
ON fc.category_id = c.category_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
如果你使用Oracle的神秘的外层连接语法(+)
(或者SQL Server的*=
,它已经有一段时间不被支持了),这也是可行的。你可能有这样的输入:输入
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM
actor a,
film_actor fa,
film f,
film_category fc,
category c
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
AND f.film_id = fc.film_id(+)
AND fc.category_id(+) = c.category_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
产生这样的输出
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM actor a
LEFT OUTER JOIN film_actor fa
ON a.actor_id = fa.actor_id
LEFT OUTER JOIN film f
ON fa.film_id = f.film_id
LEFT OUTER JOIN (
film_category fc
RIGHT OUTER JOIN category c
ON fc.category_id = c.category_id
)
ON f.film_id = fc.film_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
呃,哇。又来了!其中一个(+)
符号在错误的一边,这就是为什么我们得到这个RIGHT OUTER JOIN
。这个工具再次表明,旧的语法是很容易出错的。让我们来修正它。修正输入
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM
actor a,
film_actor fa,
film f,
film_category fc,
category c
WHERE a.actor_id = fa.actor_id(+)
AND fa.film_id = f.film_id(+)
AND f.film_id = fc.film_id(+)
AND fc.category_id = c.category_id(+)
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
固定输出
SELECT
a.first_name,
a.last_name,
count(c.category_id)
FROM actor a
LEFT OUTER JOIN film_actor fa
ON a.actor_id = fa.actor_id
LEFT OUTER JOIN film f
ON fa.film_id = f.film_id
LEFT OUTER JOIN film_category fc
ON f.film_id = fc.film_id
LEFT OUTER JOIN category c
ON fc.category_id = c.category_id
GROUP BY
a.actor_id,
a.first_name,
a.last_name
复制代码
总结
玩一玩,告诉我们你的想法!
学习的节奏慢一点效果才能更好!希望这篇文章对各位有所帮助!共勉。
边栏推荐
- JSP如何使用page指令让JSP文件支持中文编码呢?
- 利用“栈”快速计算——逆波兰表达式
- Is TCP reliable?Why?
- Statement执行update语句
- What is the function of the JSP Taglib directive?
- 146. LRU 缓存
- security session concurrency management
- SphereEx Miao Liyao: Database Mesh R&D Practice under Cloud Native Architecture
- CRS management and maintenance
- 微软电脑管家V2.1公测版正式发布
猜你喜欢
SphereEx Miao Liyao: Database Mesh R&D Practice under Cloud Native Architecture
security CSRF Vulnerability Protection
协作乐高 All In One:DAO工具大全
Short video seo search optimization main content
How to reinstall Win11?One-click method to reinstall Win11
NFT工具合集
How to design a circular queue?Come and learn~
中缀转后缀、前缀表达式快速解决办法
Short video SEO search operation customer acquisition system function introduction
PHP从txt文件中读取数据的方法
随机推荐
Win11内存管理错误怎么办?
一篇永久摆脱Mysql时区错误问题,idea数据库可视化插件配置
GetHashCode方法与=
为什么要使用MQ消息中间件?这几个问题必须拿下
GIF making - very simple one-click animation tool
Async/await principle and execution sequence analysis
async/await 原理及执行顺序分析
基于相关性变量筛选偏最小二乘回归的多维相关时间序列建模方法
Graphical LeetCode - 1161. Maximum Sum of In-Layer Elements (Difficulty: Moderate)
JSP built-in object out object function introduction
Short video SEO search operation customer acquisition system function introduction
控制电机的几种控制电路原理图
An interesting project--Folder comparison tool (1)
玩转NFT夏季:这份工具宝典值得收藏
LeetCode_322_零钱兑换
TCP 可靠吗?为什么?
面试必问的HashCode技术内幕
工业信息物理系统攻击检测增强模型
JSP Taglib指令具有什么功能呢?
[Solution] Emqx startup under win10 reports Unable to load emulator DLL, node.db_role = EMQX_NODE__DB_ROLE = core