
虽然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
-
-
- 复制代码
注意,人们通常把上述语法称为 "隐式连接",而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之上的便利,而不是替代。
当你有一个旧的代码库,你希望升级并将所有的查询转换为使用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
-
-
- 复制代码
玩一玩,告诉我们你的想法!
学习的节奏慢一点效果才能更好!希望这篇文章对各位有所帮助!共勉。