为什么这个SQL有效?

时间:2014-09-08 10:43:22

标签: sql sql-server sql-server-2012

我的同事用一个我认为实际上应该失败的工作SQL使我感到困惑。

  • [IdentityUserRoles]:列RoleIdUserId;
  • [IdentityRoles]:列IdName;

执行的SQL有效:

Delete from IdentityUserRoles where RoleId in ( 
   Select RoleId 
   FROM [dbo].[IdentityRoles] 
   where Name in ('TeamManager','Manager')
)

它首先看起来合法,但如果仔细查看子查询,表IdentityRoles没有RoleId列,则应该是Id

所以如果我单独运行子查询:

Select RoleId 
FROM [dbo].[IdentityRoles] 
where Name in ('TeamManager','Manager')

我收到错误消息:

  

Msg 207,Level 16,State 1,Line 1
  列名称“RoleId”无效。

这是预期的,因为列RoleId确实不存在。

问题是,如果子查询包含语法错误,为什么父查询会继续执行?

我在SQL Server 2012 Express Edition(v11.0.5058.0)中运行它

更新 使这个查询工作 - 没问题。问题是为什么它首先起作用并且没有抛出语法错误。

1 个答案:

答案 0 :(得分:5)

这里的SQL Server没有任何问题。这是预期的行为!

在子查询中错误地指定RoleId导致SQL Server认为它是相关的子查询。

SQL Server评估它的方式是,它首先在IdentityRoles中搜索RoleId,但在那里找不到它,所以它在IdentityUserRoles表中搜索。在那里发现了!所以这是一个有效的查询。

但是,如果您期望自包含子查询的行为不同 ...添加如下的别名。

Delete from IdentityUserRoles where RoleId in 
 ( 
   Select r.RoleId FROM [dbo].[IdentityRoles] r where Name in ('TeamManager','Manager')
 )

上述查询将失败,因为SQL Server将在IdentityRoles表中显式搜索该列。

但是,如果遵循一些最佳做法,则不会出现这种无意的错误。最佳实践(99%的情况下)是使用相同的列名表示相同的属性。

另一件事是,作为一种做法,最好遵循连接,子查询等的别名,并在选择中引用具有这些别名的列名。这样可以避免任何此类意外的错误或问题。

希望有所帮助!