Я пытаюсь создать хранимую процедуру через конвейер 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
Неверный синтаксис рядом с "%".
Есть идеи, что здесь не так?
Что касается ошибки, она говорит о вашей проблеме. Похоже, вы неправильно экранируете одинарные кавычки. Однако почему вы просто не используете CREATE OR ALTER
? Вам больше не нужен синтаксис, который вы используете; все поддерживаемые версии SQL Server поддерживают CREATE OR ALTER
, и вы находитесь в базе данных SQL Azure.
@ThomA, это работает, когда я запускаю непосредственно на ssms. но терпит неудачу, когда я прохожу через конвейер
Могу вас заверить, что приведенный выше код не будет работать в SSMS, я был настолько уверен, что это неверный синтаксис, что проверил его; не получилось . Он также некорректно работает в db<>fiddle. Опять же, почему вы не используете CREATE OR ALTER
?
в ssms исполняемый скрипт начинается с процедуры создания. но в реальном сценарии у меня также есть блок else: если процедура сохранения существует, она изменяет существующую, если нет, то создает новую. я опубликовал только создать блок
Итак, вы не используете CREATE OR ALTER
, потому что...? Почему вы используете SQL Server 2014 и более ранний синтаксис?
В сценарии я использую CREATE PROCEDURE, верно? и в противном случае это будет ALTER PROCEDURE. если вы возьмете сценарий из CREATE PROCEDURE sp_xxxxx, вы сможете запустить его в ssms
Как писал Том, каждую цитату внутри EXEC('...')
нужно дублировать. Например: select 'test'
станет: EXEC('SELECT ''Test''')
так что мне следует изменить имя WHERE LIKE '%@raboweb.onmicrosoft.com' И type_desc = 'EXTERNAL_USER'; в 'WHERE name LIKE ''%@raboweb.onmicrosoft.com'' AND type_desc = ''EXTERNAL_USER''';
Да, я написал каждую цитату
«Я использую CREATE PROCEDURE, верно? А иначе заблокируйте, это будет ALTER PROCEDURE», что не отвечает, почему вы не используете CREATE OR ALTER
.
Ошибка сообщает вам о проблеме: в вашем коде есть синтаксические ошибки; множество синтаксических ошибок.
По правде говоря, нет необходимости в синтаксисе, который вы используете (проверка существования процесса и последующее выполнение 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, но когда я его выполняю, он не отображает список пользователей с ролями.
Я опробовал его в своей базе данных песочницы, и он сработал, как и ожидалось , @rameshreddy. То же самое в db<>скрипке. Если вы не получаете никаких результатов, это означает, что в базе данных нет пользователей, соответствующих WHERE
в вашей базе данных.
К вашему сведению, префикс
sp_
зарезервирован Microsoft для специальных/системных процедур. Его не следует использовать для пользовательских процедур. Это связано с затратами на производительность и риском того, что ваша процедура просто не заработает через день после обновления/обновления. Либо используйте другой префикс, либо (возможно, лучше) вообще не используйте префикс. Префикс sp_ по-прежнему запрещен?