SQL无效标识符错误

时间:2012-03-09 19:02:42

标签: sql sql-server sql-server-2008-r2

我有一个执行select语句的函数。当我尝试执行这个返回单个值并将其设置为变量的select语句时,我的函数崩溃并出现以下错误:

  

Msg 203,Level 16,State 2,Procedure Info_GetWholeNumber,Line 20
  名称'SELECT MAX(LEN(CAST(FLOOR([pcom_audit_cant_con])AS   VARCHAR(38))))AS Audoleias.prod_com_audit的WHOLE_NO'不是   有效的标识符。

如果我复制并粘贴那个select语句就可以正常工作......因此它不是选择它与我的EXEC有关...反正这里是我的函数代码......

ALTER FUNCTION [dbo].[Info_GetWholeNumber]
(
    @TABLE VARCHAR(MAX)
    , @COLUMN VARCHAR(MAX)
)
RETURNS INT
AS
BEGIN
    -- Declare the return variable here
    DECLARE @WHOLE_NO INT

    -- Add the T-SQL statements to compute the return value here
    DECLARE @SQL VARCHAR(MAX)
    SET @SQL = 'SELECT MAX(LEN(CAST(FLOOR([' + @COLUMN + ']) AS VARCHAR(38))))
      AS WHOLE_NO FROM ' + @TABLE
    EXEC @WHOLE_NO = @SQL

    -- Return the result of the function
    RETURN @WHOLE_NO

END

如果有人有任何想法我可以解决这个问题,我真的很感激帮助!提前谢谢!

更新

好的,所以我试图按照说明使用sp_executesql函数,我将粘贴新函数。

ALTER FUNCTION [dbo].[Info_GetWholeNumber]
(
@TABLE VARCHAR(MAX)
, @COLUMN VARCHAR(MAX)
)
RETURNS INT
AS
BEGIN
DECLARE @WHOLE_NO INT
DECLARE @SQL NVARCHAR(MAX)
DECLARE @PARAMS NVARCHAR(MAX)

SET @SQL = N'SELECT @WHOLE_NOOUT = MAX(LEN(CAST(FLOOR(@COL) AS VARCHAR(38)))) FROM @TBL'
SET @PARAMS = N'@COL VARCHAR(MAX), @TBL VARCHAR(MAX), @WHOLE_NOOUT INT OUTPUT'

EXECUTE sp_executesql @SQL, @PARAMS, @COL = @COLUMN, @TBL = @TABLE, @WHOLE_NOOUT = @WHOLE_NO OUTPUT;

-- Return the result of the function
RETURN @WHOLE_NO

END

我现在收到此错误:

消息1087,级别16,状态1,第1行 必须声明表变量“@TBL”

在我看来这似乎是正确的,因为变量不是在@PARAM变量中声明的...我在这里遗漏了什么?

2 个答案:

答案 0 :(得分:4)

既不能直接从EXEC语句中分配,也不能直接从EXEC动态SQL内部分配变量(它超出范围)。这也不应该从函数中调用,因为SQL期望函数是确定性的,而事实上并非如此(事实上,即使您修复了错误,它仍然可能无法正常工作。)

假设你改变了调用这段代码的方式,你需要知道如何从动态sql中获取你的价值。如果要从动态SQL字符串传递变量,则必须将EXEC SP_ExecuteSQL与输出参数一起使用。

这是一个简单的例子:

DECLARE @whole_no int;
DECLARE @SQL nvarchar(500);
DECLARE @Parms nvarchar(500);;

SET @SQL = N'SELECT @whole_noOUT = 1';
SET @Parms = N'@whole_noOUT int OUTPUT';

EXECUTE sp_executesql @SQL, @Parms, @whole_noOUT=@whole_no OUTPUT;
SELECT @WHOLE_NO;

在这个例子中,我们设置了一个param定义和一个输出参数。通常,sp_executesql是调用动态sql的首选方法,因为它可以参数化,既可以通过避免直接连接sql来提高安全性,也可以在sql完全参数化时允许计划重用。

我还应该添加强制性警告,即你现在或将来都不应该像现在或未来一样打开自己的SQL注入方式来构建动态sql。我们了解到您无法对您的特定查询进行参数化,但至少您应该在列名上使用QUOTENAME()而不是对[]进行硬编码。

点击此处sp_executesql了解详情:http://msdn.microsoft.com/en-us/library/ms188001.aspx 还有更多关于QUOTENAME()的信息:http://msdn.microsoft.com/en-us/library/ms176114.aspx

答案 1 :(得分:0)

Lamak是对的。您无法在函数内执行存储过程(或任何能够进行更新,插入,删除的操作)。

函数应该是只读的。

您可能需要考虑使用存储过程代替您的功能。