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

时间:2013-12-12 17:53:09

标签: sql-server tsql

我从一个变量的使用中错过了一个错字。通常,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

2 个答案:

答案 0 :(得分:7)

这一直是有效的原因:

EXEC sp_who2 active;

与预期相符:

EXEC sp_who2 N'active';

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

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

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


PS你应该总是命名你的参数,you should always use the schema prefix when creating or referencing objects,例如

EXEC dbo.spTest @id = @id;

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

答案 1 :(得分:3)

与任何解释器一样,TSQL有时会做出假设而不是产生错误。

让我们通过跟踪来了解SQL引擎的内容。

enter image description here

两个字符 id 作为参数传递给存储过程。它是类型转换为字符串并作为结果返回。这是因为EXEC调用只是寻找要解释为代码的字符串,它不会产生错误。

Basically late binding.

现在,让我们对函数的SELECT调用进行跟踪。引擎知道它是一个SELECT语句。因为您只能将变量或列传递给函数,所以它注意到没有@,因此它不是变量。因此,它必须是一列。但由于没有from子句,因此会引发错误。

Basically early binding.

enter image description here