SQL查询的执行顺序

我对这个查询的执行顺序感到困惑,请解释一下。 我很困惑当应用连接时,函数被调用,一个新的列添加与案例和添加序列号。 请解释所有这些的执行顺序。

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没有执行的顺序。 是一种声明性语言。 优化器可以自由select任何合适的顺序来产生最佳的执行时间。 鉴于任何SQL查询,基本上不可能有人假装它知道执行顺序。 如果添加有关所涉及的模式(确切的表和索引定义)和估计的基数(数据的大小和密钥的select性)的详细信息,那么可以猜测可能的执行顺序。

最终,唯一正确的“顺序”是描述实际执行计划的顺序。 请参阅使用SQL Server事件探查器事件类和显示graphics执行计划显示执行计划(SQL Server Management Studio) 。

一个完全不同的事情是,查询,子查询和expression式如何将自己投射到“有效性”中。 例如,如果你在SELECT投影列表中有一个别名expression式,你可以在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#中一样,这段代码也不会编译,因为variablesc是在定义之前使用的,所以上面的SELECT将不能正确编译,因为别名c在实际定义中被引用的较低。

不幸的是,与众所周知的C / C#语言分析规则不同,查询树如何构build的SQL规则在某种程度上是很深奥的。 在单个SQL语句处理中有一个简短的提及,但详细讨论了它们是如何创build的,以及哪些顺序是有效的,哪些不是,我不知道任何来源。 我并不是说没有很好的资源,我相信一些很好的SQL书籍涵盖了这个主题。

请注意,语法树顺序与SQL文本的可视顺序不匹配。 例如,ORDER BY子句通常是SQL文本中的最后一个,但作为一个语法树,它位于其他所有东西之上(它对SELECT的输出进行sorting,所以它位于SELECTed列之上,可以这么说),因此有效引用别名:

 SELECT a+b as c FROM t ORDER BY c; 

更新

其实有这样的: SELECT语句的逻辑处理顺序

以下步骤显示了SELECT语句的逻辑处理顺序或绑定顺序。 这个顺序决定了在一个步骤中定义的对象何时在随后的步骤中可用于子句。 例如,如果查询处理器可以绑定到(访问)FROM子句中定义的表或视图,则这些对象及其列可用于所有后续步骤。 相反,因为SELECT子句是第8步,所以在子句中定义的任何列别名或派生列都不能被前面的子句引用。 但是,它们可以被后续的子句(如ORDER BY子句)引用。 请注意,语句的实际物理执行是由查询处理器决定的,并且顺序可能与此列表不同。

  1. join
  2. 哪里
  3. 通过…分组
  4. WITH CUBE或WITH ROLLUP
  5. HAVING
  6. select
  7. 不同
  8. ORDER BY
  9. 最佳

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

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

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

这意味着并不是所有的陈述都会按预期执行。 特别值得注意的是布尔expression式,它可能不是按照从左到右的顺序来计算的。 例如,下面的代码不能保证在没有除零错误的情况下执行:

 SELECT 'null' WHERE 1 = 1 OR 1 / 0 = 0 

这样做的原因是查询优化器select最好(最有效)的方式来执行语句。 这意味着,例如,可以在应用转换谓词之前加载和过滤值,从而导致错误。 查看上面的第二个链接的例子

看: 在这里和这里 。

“执行顺序”可能是SQL查询的一个不好的心理模型。 很难真正写出一个实际上依赖于执行顺序的查询(这是一件好事)。 相反,你应该想到所有的连接和where子句同时发生(几乎像一个模板)

这就是说,你可以运行显示执行计划 ,应该让你洞察它。

但是,由于不清楚为什么你想知道执行的顺序,我猜你试图为这个查询得到一个心理模型,所以你可以用某种方式修复它。 这就是我将如何“翻译”你的查询,虽然我已经做了很好的这种分析有一些灰色地带,它是多么的精确。

从和在哪里条款

  • 给我所有的Event Participants行。 from [3rdi_EventParticipants

  • 同样给我所有的事件注册行, inner join 3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId上的事件参与者行匹配inner join 3rdi_EventSignup] as ES on EP.SignUpId = ES.SignUpId

  • 但仅限事件13 EP.EventId = 13

  • 并且只有当用户标识在用户angular色表中有一个logging,其中angular色ID不在1,2,19,20,21,22中的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))
    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))

select条款

  • 对于每一行给我一个唯一的ID Row_number() OVER(ORDER BY (SELECT 1)) AS 'Serial Number',

  • 参与者名字EP.FirstName

  • 参与者姓氏Ep.LastName

  • 预订angular色名称GetBookingRoleName

  • 查看事件date,找出第一个eventDate,其中EventId = 13,你可以(select top 1 convert(varchar(10),eventDate,103)from [3rdi_EventDates] where EventId=13) as EventDate

  • 最后翻译类别中的GetBookingRoleName。 我没有这个表,所以我会手动映射(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
    (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

所以这里有几个笔记。 当您selectTOP时,您没有任何东西。 你可能应该有那个na命令。 例如,你也可以简单地把它放在你的从句中

 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