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 的词法顺序建模。
反馈
您对此页面有任何反馈吗? 我们很乐意听取您的意见!