2012-03-09 4 views
1

У меня есть функция, которая выполняет оператор 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.

Если скопировать и вставить, что выбрать заявление он работает отлично ... поэтому это не выбрать его что-то делать с моей 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 

Сейчас я получаю эту ошибку:

Msg 1087, уровень 16, состояние 1, строка 1 должен объявить переменную таблицы "@tbl"

на мой взгляд, кажется, правильно, поскольку переменные arent объявлены иначе, чем в переменной @PARAM ... Я что-то пропустил?

+3

Вы не можете использовать 'EXEC' на функцию – Lamak

+0

@Lamak, как бы я идти о выполнении этого выберите заявление в моем случае, так как его динамический ...? –

+0

Вы по-прежнему не можете использовать 'EXECUTE' или' sp_executesql' или вызывать любые другие хранимые процедуры внутри функции. Почему это должно быть функцией? –

ответ

4

Вы не можете назначать напрямую из инструкции EXEC и не можете напрямую назначать переменную из динамического SQL-массива d (он выходит за рамки). Это также не должно действительно вызываться из функции, поскольку 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; 

В этом примере мы устанавливаем определение пар, и выходной параметр. В общем случае sp_executesql является предпочтительным методом вызова динамического sql, поскольку он может быть параметризован, что повышает безопасность, избегая необходимости прямого связывания sql, но также позволяет повторно использовать повторное использование, когда ваш sql полностью параметризован.

Я также должен добавить обязательное предупреждение о том, что на самом деле вы не должны создавать динамический sql таким кавалером, как вы открываете себя до SQL-инъекции, либо сейчас, либо в будущем. Я понимаю, что вы не можете параметризовать свой конкретный запрос, но, по крайней мере, вы должны использовать QUOTENAME() для имени вашего столбца вместо hardcoding [].

Подробнее о sp_executesql здесь: http://msdn.microsoft.com/en-us/library/ms188001.aspx И еще на QUOTENAME() здесь: http://msdn.microsoft.com/en-us/library/ms176114.aspx

+0

Я только что обновил свой вопрос. Я пробовал ваше предложение, но теперь получаю еще одну ошибку, если у вас есть идея, почему это может быть? –

+0

@ Lord-Link Вы не можете параметризовать таблицы и столбцы. Те, которые вам нужно будет встроить в строку SQL, прежде чем вы вызовете 'sp_executesql' так:' SET @SQL = N'SELECT @WHOLE_NOOUT = MAX (LEN (CAST (FLOOR ('+ QUOTENAME (@COLUMN) +') AS VARCHAR (38)))) FROM '+ QUOTENAME (@TABLE) 'и удалить их из определения параметра. Таким образом вы будете только параметризировать выходную переменную. –

+0

Ну, похоже, что что-то сработало с тех пор, как я не получил ошибку ... Мой запрос застрял, но я плохо посмотрел, что один из них и посмотрим, могу ли я узнать, почему ... Спасибо за помощь, оцените ее и извините за запоздалый ответ, я заканчивал работу, и я здесь только понедельник до пятницы! :) –

0

Lamak правильный. Вы не можете выполнить хранимую процедуру (или что-либо, способное обновлять, вставлять, удалять) внутри функции.

Функции предназначены только для чтения.

Возможно, вам захочется использовать хранимую процедуру вместо вашей функции.

Смежные вопросы