Sql server SQL查询的执行顺序

Sql server SQL查询的执行顺序,sql-server,Sql Server,我对这个查询的执行顺序感到困惑,请解释一下。 我对何时应用连接、何时调用函数、何时随案例添加新列以及何时添加序列号感到困惑。请解释这一切的执行顺序 select Row_number() OVER(ORDER BY (SELECT 1)) AS 'Serial Number', EP.FirstName,Ep.LastName,[dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole) as RoleName, (select

我对这个查询的执行顺序感到困惑,请解释一下。 我对何时应用连接、何时调用函数、何时随案例添加新列以及何时添加序列号感到困惑。请解释这一切的执行顺序

select Row_number() OVER(ORDER BY (SELECT 1))  AS 'Serial Number', 
    EP.FirstName,Ep.LastName,[dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole) as RoleName,  
    (select top 1 convert(varchar(10),eventDate,103)from [3rdi_EventDates] where EventId=13) as EventDate,
    (CASE [dbo].[GetBookingRoleName](ES.UserId,EP.BookingRole)  
            WHEN    '90 Day Client' THEN 'DC'
            WHEN    'Association Client'  THEN  'DC'
            WHEN    'Autism Whisperer'    THEN  'DC'
            WHEN    'CampII'             THEN   'AD' 
            WHEN    'Captain'              THEN 'AD' 
            WHEN    'Chiropractic Assistant' THEN 'AD'
            WHEN    'Coaches'               THEN 'AD'
            END) as Category from [3rdi_EventParticipants] as EP  
    inner join [3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId  
    where EP.EventId = 13
    and userid in (  
    select distinct userid from userroles  
    --where roleid not in(6,7,61,64) and roleid not in(1,2))  
    where roleid not in(19, 20, 21, 22) and roleid not in(1,2))
这是从上述查询中调用的函数

CREATE function [dbo].[GetBookingRoleName]  
(  
 @UserId as integer,
 @BookingId as integer
)  
RETURNS varchar(20)  
as  
begin  
declare @RoleName varchar(20)  

if @BookingId = -1
Select Top 1 @RoleName=R.RoleName From UserRoles UR inner join Roles R on UR.RoleId=R.RoleId Where UR.UserId=@UserId and R.RoleId not in(1,2)  
else
Select @RoleName= RoleName From Roles where RoleId = @BookingId

return @RoleName  
end

查询通常按照SQL Server的以下顺序进行处理。我不知道其他RDBMS是否这样做

FROM [MyTable]
    ON [MyCondition]
  JOIN [MyJoinedTable]
 WHERE [...]
 GROUP BY [...]
HAVING [...]
SELECT [...]
 ORDER BY [...]

SQL没有执行顺序。是一种声明性语言。优化器可以自由选择它认为合适的任何顺序,以产生最佳执行时间。给定任何SQL查询,任何人都不可能假装知道执行顺序。如果您添加有关模式的详细信息,包括精确的表和索引定义以及估计的数据基数大小和键的选择性,那么您可以猜测可能的执行顺序

最终,唯一正确的“顺序”是实际执行计划中描述的顺序。见和

但另一件完全不同的事情是,查询、子查询和表达式如何将自己投射到“有效性”中。例如,如果在“选择投影”列表中有一个别名表达式,可以在WHERE子句中使用别名吗?像这样:

SELECT a+b as c
FROM t
WHERE c=...;
在where子句中使用c别名有效吗?答案是否定的。查询形成一个语法树,树的较低分支不能引用树中较高定义的内容。这不一定是“执行”的顺序,更多的是语法分析问题。这相当于用C编写此代码:

void Select (int a, int b)
{
   if (c = ...) then {...}
   int c = a+b;
}
正如在C中,由于变量C在定义之前就已使用,因此此代码不会编译一样,上面的SELECT也不会正确编译,因为别名C在树中的引用位置低于实际定义的位置

不幸的是,与众所周知的C/C语言解析规则不同,如何构建查询树的SQL规则有些深奥。在中有一个简短的提及,但详细讨论了它们是如何创建的,什么顺序是有效的,什么不是,我不知道任何来源。我不是说没有好的源代码,我相信一些好的SQL书籍都涵盖了这个主题

请注意,语法树顺序与SQL文本的可视顺序不匹配。例如,ORDER BY子句通常是SQL文本中的最后一个,但作为语法树,它位于对SELECT输出进行排序的所有内容之上,因此可以说它位于选定列之上,因此可以有效地引用c别名:

更新

其实是这样的:

以下步骤显示了逻辑关系 处理订单或绑定订单, 对于SELECT语句。此订单 确定在中定义对象的时间 一个步骤可供用户使用 后续步骤中的子句。对于 例如,如果查询处理器可以 绑定以访问表或视图 在FROM子句中定义,这些 创建对象及其列 可用于所有后续步骤。 相反,因为SELECT子句 是步骤8,任何列别名或 该子句中定义的派生列 不能被前面的引用 条款。然而,它们可以是 由后续条款引用,如 如ORDERBY条款所示。请注意 项目的实际实际执行情况 语句由查询确定 处理器和订单可能会有所不同 这张单子

从…起 在…上 参加 哪里 分组 使用多维数据集还是使用汇总 有 选择 不同的 订购人 顶部
对于SQL查询来说,执行顺序可能是一个糟糕的心理模型。很难真正编写一个依赖于执行顺序的查询,这是一件好事。相反,您应该将所有join和where子句看作是一个模板,几乎同时发生

也就是说,您可以运行display,这会让您深入了解它

但是,由于不清楚您为什么想要知道执行顺序,我猜您正在尝试获取此查询的心智模型,以便以某种方式修复它。这就是我将如何翻译您的查询,尽管我对这种分析做得很好,但它的精确性存在一些灰色区域

FROM和WHERE子句

给我所有的活动参与者行。来自[3rdi_事件参与者

另外,请提供与SignUpID内部连接3rdi_EventSignup]上的事件参与者行匹配的所有事件注册行,作为EP.SignUpID=ES.SignUpID上的ES

但仅适用于事件13 EP.EventId=13

并且仅当用户id在用户角色表中有一条记录,其中角色id不在1,2,19,20,21,22中时 中的用户ID 从userroles中选择distinct userid -其中roleid不在6,7,61,64中,roleid不在1,2中 其中roleid不是在19,20,21,22,roleid不是在1,2

SELECT子句

对于每一行,给我一个唯一的ID 通过选择1作为“序列号”对行号进行超额订购

p 参与者姓名EP.FirstName

参与者姓Ep.LastName

预订角色名称GetBookingRoleName

查看事件日期,找出您找到的EventId=13的第一个eventDate 从[3rdi_EventDates]中选择前1名convertvarchar10、eventDate、103,其中EventId=13作为eventDate

最后翻译类别中的GetBookingRoleName。我没有用于此的表,因此我将手动将其映射为CASE[dbo].[GetBookingRoleName]ES.UserId,EP.BookingRole 当“90天客户”时,则为“DC” 当“关联客户端”时,则为“DC” 当“孤独症耳语者”然后是“DC” 当“CampII”然后是“AD” 当“船长”和“广告” 当“脊骨疗法助理”时,则为“广告” 当“教练”和“广告” 以类别结束

这里有几条注释。选择TOP时,您不会按任何方式订购。你应该在那里订一份。你也可以很容易地把它放在from子句中

from [3rdi_EventParticipants] as EP  
    inner join [3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId,   
       (select top 1 convert(varchar(10),eventDate,103)
       from [3rdi_EventDates] where EventId=13
       Order by eventDate) dates

SQL是一种声明性语言,这意味着它告诉SQL引擎做什么,而不是如何做。这与命令式语言(如C)形成了对比,在C语言中,如何做某件事是明确的

这意味着并非所有语句都将按预期执行。特别要注意的是布尔表达式,它可能不会像所写的那样从左向右求值。例如,不能保证执行以下代码时不会出现除零错误:

SELECT 'null' WHERE 1 = 1 OR 1 / 0 = 0
原因是查询优化器选择了执行语句的最佳、最有效的方式。这意味着,例如,在应用转换谓词之前,可能会加载并过滤一个值,从而导致错误。有关示例,请参见上面的第二个链接

请参阅:和。

对查询文本的评估有一个逻辑顺序,但数据库引擎可以根据最佳顺序选择执行查询组件的顺序。下面列出了逻辑文本解析顺序。例如,这就是为什么不能在WHERE子句中使用别名from SELECT子句。就查询解析过程而言,别名还不存在

在哪里

分组

立方体|上卷

拥有

挑选

明显的

订购人


有关这方面的详细信息,请参阅。

SQL查询不是强制性的,而是声明性的,因此您不知道先执行哪个语句,但由于SQL是由SQL查询引擎计算的,因此大多数SQL引擎都遵循类似的过程来获得结果。您可能需要了解查询引擎的内部工作方式,才能了解一些SQL执行行为

Julia Evens有一篇很好的帖子解释了这一点,值得一看:


脱离主题,但您可能会更好地抛弃该UDF并使逻辑内联。但是在我上面的查询中,何时调用我的函数?在找到之前的联接结果后,如果在此之前,则参数值从何处获取,也在执行时,从[3rdi_EventDates]中选择前1个convertvarchar10、eventDate、103from[3rdi_EventDates],其中EventId=13,当一个新列的情况被执行时,唯一能找到答案的方法就是查看实际的执行计划。互联网上有太多的答案了/所以说SQL优化器做到了这是不可思议的-没有人知道给定的查询将如何执行。但正如你在下面意识到的,这不是真的!是的,优化器执行随机操作-但显然子句有一些执行顺序。否则,你怎么可能依赖于一个查询呢?请将您的更新移到顶部,以便寻找答案的人不会在顶部看到您的错误答案,然后离开该线程…您可以更新此答案以使社区更清楚吗?目前,用户必须阅读大量内容,然后在底部告诉您,这些内容无论如何都不完全正确。我同意,这不是一个好主意!简短而甜蜜的解释。我对这个答案投赞成票。是的,标记为正确的答案有点误导。如果它引用了权威来源,可能会获得更多的赞成票
SELECT 'null' WHERE 1 = 1 OR 1 / 0 = 0