2012-03-09 77 views
1

我有一个执行select语句的函数。当我尝试执行它返回一个值并将其设置为可变我的函数,出现以下错误崩溃此select语句:SQL无效标识符错误

Msg 203, Level 16, State 2, Procedure Info_GetWholeNumber, Line 20
The name 'SELECT MAX(LEN(CAST(FLOOR([pcom_audit_cant_con]) AS VARCHAR(38)))) AS WHOLE_NO FROM Auditorias.prod_com_audit' is not a valid identifier.

如果我复制和粘贴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 

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

更新:

确定这样的IM尝试使用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, 行必须声明表变量 “@TBL”

这在我看来似乎正确,因为变量没有在@PARAM变量中声明...我在这里丢失了什么?

+3

不能使用'EXEC'上的功能 – Lamak 2012-03-09 19:08:23

+0

@Lamak如何将我去执行,既然在我的情况选择语句中的动态...? – 2012-03-09 19:14:13

+0

您仍然不能使用'EXECUTE'或'sp_executesql'或调用函数内的任何其他存储过程。为什么这需要成为一个功能? – 2012-03-09 20:21:18

回答

4

您既不能直接从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, @[email protected]_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

+0

我刚刚更新了我的问题我尝试了你的建议,但现在有任何想法,为什么这可能是另一个错误? – 2012-03-09 19:53:46

+0

@ Lord-Link您不能像这样对表格和列进行参数化。那些在调用'sp_executesql'之前需要构建到SQL字符串中的语句如下:'SET @SQL = N'SELECT @WHOLE_NOOUT = MAX(LEN(CAST(FLOOR('+ QUOTENAME(@COLUMN)+')AS VARCHAR 38))))FROM'+ QUOTENAME(@TABLE)'并将它们从param定义中删除。这样你只会参数化输出变量。 – 2012-03-09 20:07:22

+0

那么这似乎已经做了正确的,因为我没有得到一个错误...我的查询卡住了,但生病检查一出来,看看我能找出原因...感谢您的帮助,感谢它,并为迟到的回应我正在工作结束,我只在这里星期一到星期五! :) – 2012-03-12 12:32:22

0

Lamak是对的。你不能在一个函数中执行存储过程(或任何能够更新,插入,删除)。

函数是用来读取的。

你可能要考虑的地方你的函数的使用存储过程。

相关问题