Невозможно создать хранимую процедуру через конвейер Azure

Я пытаюсь создать хранимую процедуру через конвейер Azure, однако мне это не удалось.

Вот мой сценарий:

IF NOT EXISTS (SELECT ROUTINE_NAME 
               FROM INFORMATION_SCHEMA.ROUTINES 
               WHERE ROUTINE_NAME = 'sp_checknpapermission' 
                 AND ROUTINE_TYPE = 'PROCEDURE')
BEGIN
    SET QUOTED_IDENTIFIER ON

    EXEC('
          CREATE PROCEDURE sp_checknpapermission
          AS
          BEGIN
              SET NOCOUNT ON;
              DECLARE @UserName NVARCHAR(128);
              DECLARE user_cursor CURSOR FOR
                SELECT name
                FROM sys.database_principals
                WHERE name LIKE '%@web.onmicrosoft.com' AND type_desc = 'EXTERNAL_USER';

              BEGIN TRY
                OPEN user_cursor;
                FETCH NEXT FROM user_cursor INTO @UserName;

                WHILE @@FETCH_STATUS = 0
                BEGIN
                IF NOT EXISTS (
                   SELECT 1
                   FROM sys.database_role_members AS rm
                   JOIN sys.database_principals AS r ON rm.role_principal_id = r.principal_id
                   JOIN sys.database_principals AS u ON rm.member_principal_id = u.principal_id
                   WHERE u.name = @UserName  AND r.name = 'db_owner'
                )
                BEGIN
                     PRINT 'The user ' + @UserName + ' does not have db_owner role';
                     END
                     ELSE
                     BEGIN
                        PRINT 'The user ' + @UserName + ' already has the db_owner role';
                     END
                     FETCH NEXT FROM user_cursor INTO @UserName;
                END

               CLOSE user_cursor;
               DEALLOCATE user_cursor;
             END TRY
             BEGIN CATCH
                 ROLLBACK;
                 PRINT ERROR_MESSAGE();
            END CATCH;
    END
  ')
END

Это ошибка, которую я получаю:

Сообщение 102, уровень 15, состояние 1, сервер sqlserver-rba-dev, строка 17
Неверный синтаксис рядом с "%".

Есть идеи, что здесь не так?

К вашему сведению, префикс sp_ зарезервирован Microsoft для специальных/системных процедур. Его не следует использовать для пользовательских процедур. Это связано с затратами на производительность и риском того, что ваша процедура просто не заработает через день после обновления/обновления. Либо используйте другой префикс, либо (возможно, лучше) вообще не используйте префикс. Префикс sp_ по-прежнему запрещен?

Thom A 14.08.2024 14:54

Что касается ошибки, она говорит о вашей проблеме. Похоже, вы неправильно экранируете одинарные кавычки. Однако почему вы просто не используете CREATE OR ALTER? Вам больше не нужен синтаксис, который вы используете; все поддерживаемые версии SQL Server поддерживают CREATE OR ALTER, и вы находитесь в базе данных SQL Azure.

Thom A 14.08.2024 14:56

@ThomA, это работает, когда я запускаю непосредственно на ssms. но терпит неудачу, когда я прохожу через конвейер

ramesh reddy 14.08.2024 15:02

Могу вас заверить, что приведенный выше код не будет работать в SSMS, я был настолько уверен, что это неверный синтаксис, что проверил его; не получилось . Он также некорректно работает в db<>fiddle. Опять же, почему вы не используете CREATE OR ALTER?

Thom A 14.08.2024 15:06

в ssms исполняемый скрипт начинается с процедуры создания. но в реальном сценарии у меня также есть блок else: если процедура сохранения существует, она изменяет существующую, если нет, то создает новую. я опубликовал только создать блок

ramesh reddy 14.08.2024 15:09

Итак, вы не используете CREATE OR ALTER, потому что...? Почему вы используете SQL Server 2014 и более ранний синтаксис?

Thom A 14.08.2024 15:10

В сценарии я использую CREATE PROCEDURE, верно? и в противном случае это будет ALTER PROCEDURE. если вы возьмете сценарий из CREATE PROCEDURE sp_xxxxx, вы сможете запустить его в ssms

ramesh reddy 14.08.2024 15:11

Как писал Том, каждую цитату внутри EXEC('...') нужно дублировать. Например: select 'test' станет: EXEC('SELECT ''Test''')

siggemannen 14.08.2024 15:16

так что мне следует изменить имя WHERE LIKE '%@raboweb.onmicrosoft.com' И type_desc = 'EXTERNAL_USER'; в 'WHERE name LIKE ''%@raboweb.onmicrosoft.com'' AND type_desc = ''EXTERNAL_USER''';

ramesh reddy 14.08.2024 15:21

Да, я написал каждую цитату

siggemannen 14.08.2024 15:27

«Я использую CREATE PROCEDURE, верно? А иначе заблокируйте, это будет ALTER PROCEDURE», что не отвечает, почему вы не используете CREATE OR ALTER.

Thom A 14.08.2024 15:47
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
11
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка сообщает вам о проблеме: в вашем коде есть синтаксические ошибки; множество синтаксических ошибок.

По правде говоря, нет необходимости в синтаксисе, который вы используете (проверка существования процесса и последующее выполнение CREATE в отложенном пакете). Все поддерживаемые версии SQL Server допускают синтаксис CREATE OR ALTER, и вы используете базу данных SQL Azure, основанную на последней версии подсистемы данных (а иногда и на следующей).

Так что просто используйте CREATE OR ALTER (и избавьтесь от префикса sp_):

CREATE OR ALTER PROCEDURE dbo.checknpapermission
AS BEGIN
    SET NOCOUNT ON;
    DECLARE @UserName nvarchar(128);
    DECLARE user_cursor CURSOR FOR
        SELECT name
        FROM sys.database_principals
        WHERE name LIKE '%@web.onmicrosoft.com'
          AND type_desc = 'EXTERNAL_USER';

    BEGIN TRY
        OPEN user_cursor;
        FETCH NEXT FROM user_cursor
        INTO @UserName;

        WHILE @@FETCH_STATUS = 0 BEGIN
            IF NOT EXISTS (SELECT 1
                           FROM sys.database_role_members rm
                                JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id
                                JOIN sys.database_principals u ON rm.member_principal_id = u.principal_id
                           WHERE u.name = @UserName
                             AND r.name = 'db_owner') BEGIN
                PRINT 'The user ' + @UserName + ' does not have db_owner role';
            END;
            ELSE BEGIN
                PRINT 'The user ' + @UserName + ' already has the db_owner role';
            END;
            FETCH NEXT FROM user_cursor
            INTO @UserName;
        END;

        CLOSE user_cursor;
        DEALLOCATE user_cursor;
    END TRY
    BEGIN CATCH
        ROLLBACK; --Why is this here...?
        PRINT ERROR_MESSAGE();
    END CATCH;
END;

А еще лучше выбросьте это CURSOR; это будет ужасно медленно. Мы также можем избавиться от ошибок TRY...CATCH и ROLLBACK (что вы здесь пытаетесь откатить?), а ошибки PRINT — это антишаблон. Вы можете легко добиться тех же результатов с помощью простой агрегации строк.

CREATE OR ALTER PROCEDURE dbo.checknpapermission
AS BEGIN
    SET NOCOUNT ON;

    DECLARE @PrintStatement varchar(8000),
            @LF char(1) = CHAR(10)

    SELECT @PrintStatement = STRING_AGG('The user ' + u.name + ' ' + CASE WHEN r.principal_id IS NULL THEN 'does not have the db_owner role'
                                                                          ELSE 'already has the db_owner role' END, @LF)
    FROM sys.database_principals u
         LEFT JOIN sys.database_role_members rm
              JOIN sys.database_principals r ON rm.role_principal_id = r.principal_id
                                             AND r.name = 'db_owner'
                                             ON u.principal_id = rm.member_principal_id
    WHERE u.name LIKE '%@web.onmicrosoft.com'
      AND u.type_desc = 'EXTERNAL_USER';

    PRINT @PrintStatement;

END;

Хорошо, я попробовал описанное выше через ssms и смог создать SP, но когда я его выполняю, он не отображает список пользователей с ролями.

ramesh reddy 14.08.2024 16:01

Я опробовал его в своей базе данных песочницы, и он сработал, как и ожидалось , @rameshreddy. То же самое в db<>скрипке. Если вы не получаете никаких результатов, это означает, что в базе данных нет пользователей, соответствующих WHERE в вашей базе данных.

Thom A 14.08.2024 16:03

Другие вопросы по теме