我正在阅读 70-461 TSQL 培训书,关于存储过程的部分是这样说的:
Proc1 中声明的变量和 Proc1 的参数对于 Proc1 调用的任何过程都是不可见的
但是在同一本书中是这个示例代码:
CREATE PROCEDURE Sales.ListCustomerByAddress
(@address AS NVARCHAR(60))
AS
DECLARE @SQLString AS NVARCHAR(4000);
SET @SQLString = '
SELECT companyname, contactname
FROM Sales.Customers WHERE address = @address';
EXECUTE sp_executesql
@statement = @SQLString,
@params = N'@address NVARCHAR(60)',
@address = @address;
RETURN;
GO
我对引用语句的理解是@SQLString
变量和@address
参数不能被sp_executesql
过程可见和引用?变量是一个包含值的对象,因此如果它不存在或看不到(例如在中@statement =
),如何使用或传递该值
有人可以帮助调和这个矛盾吗?
该文档中没有矛盾。这里的混淆似乎是关于读者对变量范围如何工作的期望的隐含假设。在许多其他语言中,在外部作用域中声明的变量对子例程/函数是可见的。例如(这不是它在 T-SQL 中的工作方式;我只是在说明变量范围通常是如何工作的):
由于在外部作用域中声明的变量通常对内部作用域(即全局)可见,因此上面的代码在调用未声明的声明时不会
Sub1
出错OuterVariable
。相反,子例程可以访问的值OuterVariable
(在某些语言中,它甚至可以覆盖该值)。Result
因此,末尾的值为18。所以,当书中说:
他们说 T-SQL 不是那样工作的。他们并不是说 Proc1 中的变量不能传递到子 Proc 调用中;他们说如果你想在 sub-Proc 调用中使用这些值,那么你必须通过输入参数显式地传递它们。从本质上讲,“可见”意味着“无需通过输入参数显式传入即可使用”。
也许这将有助于说明:
执行
EXEC dbo.OuterProc 5;
或EXEC dbo.OuterProc @OuterInputParam = 5;
(同样的事情)将返回:这些值被 dbo.InnerProc“知道”,因为它们是传入的。并且它们被传入是因为它们对 dbo.InnerProc 不“可见”,即使它们在执行期间存在于 dbo.OuterProc 的外部/父范围内。但是在 dbo.InnerProc 中都不能引用
@OuterInputParam
nor@OuterName
,因为内部/子范围不知道外部/父范围,至少对于变量(包括表变量)和参数是这样。最后,将所有这些与本书中的初始示例联系起来,这就是为什么我在使用
sp_executesql
: 时尽力更改变量名称以使代码更具可读性。更改一个变量名可能会使它更清楚一点: