SELECT子句的词法和逻辑顺序
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
SQL 的 SELECT
子句具有词法顺序和逻辑顺序。SELECT
子句的词法顺序受到英语的启发。由于 SQL 语句是数据库的命令,因此用祈使语气表达语句是很自然的,例如“SELECT 这个和那个!”。
逻辑 SELECT 子句顺序
但是,SELECT
子句的逻辑顺序与语法不对应。事实上,逻辑顺序是这样的:
- FROM 子句:首先,定义并连接所有数据源
- WHERE 子句:然后,尽早过滤数据
- CONNECT BY 子句:然后,迭代或递归地遍历数据,以生成新的元组
- GROUP BY 子句:然后,数据被缩减为组,如果使用 像 ROLLUP()、CUBE()、GROUPING SETS() 这样的分组函数,则可能生成新的元组
- HAVING 子句:然后,基于聚合函数再次过滤数据
- WINDOW 子句:然后,评估窗口规范和窗口函数
- QUALIFY 子句:然后,基于窗口函数再次过滤数据
- SELECT 子句:只有现在,才评估投影。
- DISTINCT 子句:删除重复的投影行
-
UNION、INTERSECT 和 EXCEPT 子句:可选地,以上步骤对于几个
UNION
连接的子查询重复执行。除非是UNION ALL
子句,否则数据会进一步减少以删除重复项 - ORDER BY 子句:现在,所有剩余的元组都被排序
- LIMIT 子句:然后,为排序的元组创建一个分页视图
- FOR 子句:转换为 XML 或 JSON
- FOR UPDATE 子句:最后,应用悲观锁
SQL Server 文档也解释了这一点,但子句略有不同
-
FROM
-
ON
-
JOIN
-
WHERE
-
GROUP BY
-
WITH CUBE
或WITH ROLLUP
-
HAVING
-
SELECT
-
DISTINCT
-
ORDER BY
-
TOP
可以看出,数据库必须在逻辑上重新排序 SQL 语句,以便确定最佳执行计划。
替代语法:LINQ, SLICK
一些“更高层”的抽象,例如 C# 的 LINQ 或 Scala 的 Slick,试图将 SELECT
子句的词法顺序反转为看起来更接近逻辑顺序的顺序。将 SELECT
子句移动到末尾的明显优势在于,SELECT
语句返回的记录类型(即投影类型)可以在内部领域特定语言的目标环境中更轻松地重用。
一个 LINQ 例子
// LINQ-to-SQL looks somewhat similar to SQL // AS clause // FROM clause From p In db.Products // WHERE clause Where p.UnitsInStock <= p.ReorderLevel AndAlso Not p.Discontinued // SELECT clause Select p
一个 Slick 例子
// "for" is the "entry-point" to the DSL val q = for { // FROM clause WHERE clause c <- Coffees if c.supID === 101 // SELECT clause and projection to a tuple } yield (c.name, c.price)
虽然这乍一看是一个好的且符合习惯的想法,但 jOOQ 的观点是,这只会使翻译为更高级的 SQL 语句变得复杂,同时会降低那些习惯于编写 SQL 的用户的可读性。对于 Slick 尤其如此,它不仅更改了 SELECT
子句的顺序,而且还大量地将 SQL 子句与 Scala 语言“集成”在一起。
jOOQ 的设计看起来就像 SQL。因此,jOOQ DSL API 按照 SQL 的词法顺序建模。
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!