我的同事用一个我认为实际上应该失败的工作SQL使我感到困惑。
[IdentityUserRoles]
:列RoleId
,UserId
; [IdentityRoles]
:列Id
,Name
; 执行的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)中运行它
更新 使这个查询工作 - 没问题。问题是为什么它首先起作用并且没有抛出语法错误。
答案 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%的情况下)是使用相同的列名表示相同的属性。
另一件事是,作为一种做法,最好遵循连接,子查询等的别名,并在选择中引用具有这些别名的列名。这样可以避免任何此类意外的错误或问题。
希望有所帮助!