Проблема с сервером 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

Есть пара синтаксических ошибок еще до того, как я проверил ваш запрос:

  1. Слово "DECLARE" не должно появляться в середине без имени переменной, @name_Name и @name_PARENTID не объявлены

    ОБЪЯВИТЬ @name_NAME varchar, @name_PARENTID int

(проверьте типы переменных в соответствии с исходной таблицей)

  1. 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
Другие вопросы по тегам