当我忘记变量传递过程参数时,为什么SQL出错?

Kar*_*ger 4 t-sql sql-server

我从一个变量的使用中错过了一个错字.通常,SQL将包含未声明的变量.但是在使用它的情况下,sproc参数sql server不会抱怨.它只是推断一些单引号并继续前进.

任何人都可以解释为什么示例C没有错误?

--Ex A. Error
SELECT id

--Ex B. Error
CREATE FUNCTION dbo.fnTest (
  @id NVARCHAR(4)
) RETURNS NVARCHAR(4) AS BEGIN 
  RETURN @id 
END
GO
DECLARE @id NVARCHAR(4) 
SET @id= 'bob'
SELECT dbo.fnTest(@id) --missing my @, this should be @id
--SELECT dbo.fnTest(id) --missing my @, this should be @id
GO
DROP FUNCTION fnTest

--Ex C. No Error
CREATE PROC spTest (
  @id NVARCHAR(4)
) AS 
  SELECT @id
GO
DECLARE @id NVARCHAR(4) 
SET @id= 'bob'
EXEC spTest id --missing my @, this should be @id
GO
DROP PROC spTest
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 7

这一直是有效的原因:

EXEC sp_who2 active;
Run Code Online (Sandbox Code Playgroud)

与预期相符:

EXEC sp_who2 N'active';
Run Code Online (Sandbox Code Playgroud)

存储过程能够接受没有单引号的输入字符串,并且仍将其视为字符串,只要它没有任何特殊字符(如空格或短划线)即可.

为什么它适用于程序而不适用于功能?

怀疑你会得到一个满意的答案,除非你能找到那些在早期版本的SQL Server(好吧,可能是Sybase)上工作的开发人员,然后给他们买啤酒并哄骗他们.只是其中一个小的实现细节是"它的工作方式;没有原因." 最有可能的是,这两个代码路径是由不同的开发人员编写的,其中发布日期优先于一致性.(哦,等一下.)


PS你应该总是命名你的参数,你应该在创建或引用对象时始终使用模式前缀,例如

EXEC dbo.spTest @id = @id;
Run Code Online (Sandbox Code Playgroud)

这可以防止您遇到错误,并保护您免受存储过程的基础更改(例如,某人在参数列表的开头添加了一个新的可选参数).