Press "Enter" to skip to content

在不同数据库中SQL执行顺序的变化

为什么在SQL Server中无法按序列位置进行分组,而在其他数据库中可以

Transact-SQL vs MySQL execution order (image by author)

在经常与MySQL和PostgreSQL等开源数据库一起工作后,我最近有机会参与了一个SQL Server项目,并发现了SQL场景中一个微妙但重要的差异。我发现在SQL Server中,我无法按序列位置(GROUP BY 1, 2, 3…)进行分组,而这是我在其他数据库中经常使用的功能,尤其用于快速测试。

这一发现引发了我对两个数据库系统的几个细微差异的探索,特别是SQL执行顺序,这将是本文的重点。

为什么这很重要?在使用数据库系统时,了解微妙的差异可以极大地影响您的工作流程并提高您的工作效率。它可以节省您大量的疑难解答时间。此外,了解不同数据库的SQL执行顺序,可以根据您的工作系统制定更优化的SQL查询

在本文中,我们将研究一种主要用例中发生的此行为 – GROUP BY – 并探讨其原因。然而,这一见解可以应用于HAVING、WHERE或任何其他SQL命令子句。

让我们开始

让我们在下面的查询示例中看看这个例子。尽管在MySQL中有效,但在SQL Server中无法运行:

SELECT    DATEPART(year, day) AS order_date,    SUM(cost) as costFROM cleanGROUP BY 1;

如果您运行此查询,可能会收到以下错误:

Each GROUP BY expression must contain at least one column that is not an outer reference.

然而,将GROUP BY序列参考更换为显式表达式后,此修订查询将有效。您还会注意到可以在ORDER BY子句中引用序列位置,这让我感到奇怪:

SELECT    datepart(year, day),    sum(cost) as costfrom cleanGROUP BY datepart(year, day)ORDER BY 1;

在SQL Server中,我很快了解到我必须在GROUP BY子句中使用显式列名或表达式。这被认为是最佳实践,因为这使得代码更容易理解。然而,我对为什么这种行为在不同数据库之间有所不同很好奇。此外,我发现SQL Server中的ORDER BY子句与序列位置一起使用,进一步激发了我的好奇心。

探索SELECT语句的执行顺序

为了找到答案,让我们比较SQL Server与其他数据库的SELECT语句执行/处理顺序。需要注意的是,在SQL数据库中,查询的每个部分都是按顺序执行的,并且此顺序与编写顺序不同。

例如,在SQL Server中,我们可以从下面的图像和Microsoft文档中看到,FROM子句是首先要评估的命令。此外,在GROUP BY子句之后运行SELECT子句。这就是为什么在我们的第一个示例中,无法在GROUP BY子句中引用列的位置或别名的原因!

然而,我们可以在ORDER BY子句中自由地引用序列位置和/或别名,因为它是在SELECT子句之后评估的。SELECT子句告诉数据库返回哪些列,因此此时位置已知。很酷,对吧?

SQL Server执行顺序

SQL Server SELECT statement processing order (Image by author)

MySQL

然而,在MySQL中,我发现很难找到明确说明SQL查询执行顺序的文档。执行顺序似乎取决于查询的内容以及查询优化器定义的最佳路径。

但是从我们在MySQL文档中看到的,线索告诉我们执行顺序可能是这样的,即SELECT子句在GROUP BY子句之前进行求值

对于GROUP BY或HAVING子句,在搜索select_expr值之前,它首先搜索FROM子句。(对于GROUP BY和HAVING,这与使用相同规则作为ORDER BY的MySQL 5.0之前的行为不同。)

GoogleSQL

如果我们还看一下GoogleSQL(以前的标准SQL)文档,这是Google BigQuery中使用的语法,您将会看到与SQL Server中执行查询的方式有类似的偏差:

GROUP BY和ORDER BY也可以引用第三组:整数字面值,它们是指SELECT列表中的项目。整数1是指SELECT列表中的第一个项目,2是指第二个项目,依此类推。

正如您所见,这种行为在SQL Server中不受支持。Google的文档还提到GROUP BY、ORDER BY和HAVING可以引用SELECT列表中的别名。

通过这一切,我们可以得出一个高概率的结论,即这些其他数据库的执行顺序遵循类似下图的路径:

MySQL,PostgreSQL和BigQuery的可能执行顺序

MySQL SELECT statement execution order (Image by author)

结论

这是一篇简短的文章,我们通过观察行为和文档,研究了MySQL、GoogleSQL和其他数据库SQL语法与SQL Server不同的执行顺序。SQL Server强调在GROUP BY子句中的显式性,以提高代码清晰度,而MySQL的执行顺序明确在GROUP BY子句之前对SELECT子句进行求值,允许我们引用其中的序数位置。

欢迎分享您对这个主题的想法,并期待下一篇文章。

您可以成为VoAGI会员来支持我并享受更多类似的故事。

参考资料

Leave a Reply

Your email address will not be published. Required fields are marked *