Проблема с сервером SQL - функция Create должна быть единственным оператором в пакете
У меня есть функция, которую я создал в SQL, но я получаю эту ошибку "Проблема сервера SQL - функция Create должна быть единственным оператором в пакете". Я проверил другие подобные темы, но не смог найти ничего плохого. Я использую SQL Server 2012
CREATE FUNCTION GETLLPATH(@objectid FLOAT)
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE @dir VARCHAR(MAX);
DECLARE @obj_id FLOAT;
DECLARE Name_Cursor CURSOR LOCAL FOR
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A
WHERE A.DataID = @obj_id;
DECLARE
SET @dir = NULL;
SET @obj_id = @objectid;
WHILE 1=1 BEGIN
OPEN Name_Cursor;
FETCH Name_Cursor INTO @name;
IF @@FETCH_STATUS <> 0 BREAK or @name_NAME = 'Enterprise';
IF @dir IS NOT NULL BEGIN
SET @dir = (ISNULL(@name_NAME, '') + ':' + isnull(@dir, '')) ;
END
IF @dir IS NULL BEGIN
SET @dir = @name_NAME;
END
SET @obj_id = @name_PARENTID;
CLOSE Name_Cursor;
DEALLOCATE Name_Cursor;
END;
return(@dir);
END;
GO
Я также получаю сообщение об ошибке для переменных, как "Должен объявить скалярную переменную". В конце концов, есть еще одна ошибка - "Ожидается разговор", прошу вас помочь.
3 ответа
Я полагаю, у вас просто плохой код.
Попробуй это:
CREATE FUNCTION GETLLPATH(
@objectid FLOAT
)
RETURNS VARCHAR(4000)
AS
BEGIN
DECLARE @dir VARCHAR(MAX);
DECLARE
@obj_id FLOAT
, @name_NAME VARCHAR(50) -- or whatever your field size is.
, @name_PARENTID VARCHAR(50) -- again, whatever your field size is.
DECLARE Name_Cursor CURSOR LOCAL FOR
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A WHERE A.DataID = @obj_id;
SET @dir = NULL; -- redundant.
SET @obj_id = @objectid; -- this can be set at declaration ( e.g. DELARE @obj_id FLOAT = @obj_id ).
WHILE ( 1 = 1 ) BEGIN
OPEN Name_Cursor;
FETCH Name_Cursor INTO @name;
IF ( @@FETCH_STATUS <> 0 OR @name_NAME = 'Enterprise' )
BREAK;
IF ( @dir IS NOT NULL ) BEGIN
SET @dir = (ISNULL(@name_NAME, '') + ':' + isnull(@dir, '')) ;
END
IF @dir IS NULL BEGIN
SET @dir = @name_NAME;
END
SET @obj_id = @name_PARENTID;
CLOSE Name_Cursor;
DEALLOCATE Name_Cursor;
END
RETURN @dir;
END
GO
Что касается меня, я никогда не любил использовать WHILE (1=1). У вас есть гарантированный выход?
Кроме того, я очень рекомендую использовать альтернативу курсору. Возможно, используйте переменную TABLE и переберите ее так:
CREATE FUNCTION GETLLPATH(
@objectid FLOAT
)
RETURNS VARCHAR(4000)
AS
BEGIN
-- declare variables --
DECLARE @id INT
, @dir VARCHAR(MAX)
, @obj_id FLOAT = @objectid
, @name_NAME VARCHAR(50)
, @name_PARENTID VARCHAR(50)
-- declare table variable --
DECLARE @data TABLE( [name] VARCHAR(50), [parent_id] VARCHAR(50), [id] INT IDENTITY (1,1) );
-- insert data --
INSERT INTO @data ( [name], [parent_id] )
SELECT A.Name, A.ParentID FROM OTCS_User.DTree A WHERE A.DataID = @obj_id;
-- for-each row... --
SET @id = 1;
WHILE ( @id <= ( SELECT MAX( id ) FROM @data ) )
BEGIN
-- current row --
SELECT
@name_NAME = [name]
, @name_PARENTID = [parent_id]
FROM @data WHERE [id] = @id;
-- do your work here...
-- next row --
SET @id = ( @id + 1 );
END
RETURN @dir;
END
GO
Есть пара синтаксических ошибок еще до того, как я проверил ваш запрос:
Слово "DECLARE" не должно появляться в середине без имени переменной, @name_Name и @name_PARENTID не объявлены
ОБЪЯВИТЬ @name_NAME varchar, @name_PARENTID int
(проверьте типы переменных в соответствии с исходной таблицей)
IF @@FETCH_STATUS <> 0 BREAK или @name_NAME = 'Enterprise' неверно
IF @@ FETCH_STATUS<> 0 или @name_NAME = 'Enterprise' BREAK
"Create Function должна быть единственным оператором в пакете" - обычно означает, что есть некоторая синтаксическая ошибка.
Это, честно говоря, полная догадка и (что самое важное) полностью непроверенная; из-за отсутствия данных выборки и ожидаемых результатов.
Во всяком случае, как я уже сказал в комментариях, CURSOR
и функция скалярного значения здесь действительно плохие исполнители. Если вы пытаетесь просто разделить ваши данные двоеточием (:
), то вы можете использовать STUFF
а также FOR XML PATH
,
Как я уже сказал, это завершено непроверенным, но может привести вас на правильный путь:
CREATE FUNCTION dbo.GetllPath (@objectID int) --Is it really a float? I've used an int
RETURNS table
AS RETURN
SELECT STUFF((SELECT ':' + DT.[Name]
FROM OTCS_User.DTree DT
WHERE DT.DataID = @obj_id
--ORDER BY SOMETHING HERE!!!
FOR XML PATH('')),1,1,'') AS llPath;
GO