我从一个变量的使用中错过了一个错字。通常,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
答案 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引擎的内容。
两个字符 id 作为参数传递给存储过程。它是类型转换为字符串并作为结果返回。这是因为EXEC调用只是寻找要解释为代码的字符串,它不会产生错误。
Basically late binding.
现在,让我们对函数的SELECT调用进行跟踪。引擎知道它是一个SELECT语句。因为您只能将变量或列传递给函数,所以它注意到没有@,因此它不是变量。因此,它必须是一列。但由于没有from子句,因此会引发错误。
Basically early binding.