MaximusDebois Ответов: 2

Как заблокировать запись, чтобы предотвратить удаление


у меня есть база данных в sql server под названием travel. В базе данных есть таблица под названием пользователи. В таблице users имя пользователя в столбце метка в качестве первичного ключа. Я хочу заблокировать запись в таблице users с идентификатором пользователя 101. Я пытаюсь сделать это с помощью спускового крючка. Но это не работает.

Что я уже пробовал:

ALTER TRIGGER [dbo].[UserTrigger]
На [dbo].[Пользователи]
ВМЕСТО ТОГО, ЧТОБЫ УДАЛИТЬ
АС
Если существует (выберите UserId из пользователей, где UserId = 101)
НАЧАТЬ
Инструкция raiserror ('не допускается, чтобы удалить имя пользователя : 1, в качестве супер пользователя',16,1)
КОНЕЦ
ЕЩЕ
НАЧАТЬ
Удалить из пользователей, где UserId in (UserId)
КОНЕЦ

2 Ответов

Рейтинг:
2

Richard Deeming

Вы вызываете ошибку, когда кто-то пытается удалить какой-нибудь запись пользователя, до тех пор, пока Users таблица содержит указанную запись.

Вы должны вызывать ошибку только в том случае, если кто-то попытается удалить указанную запись.

Но это хорошая работа, что ваш тест провалился; ваш Else блок настроен на удаление все пользователи! Вы говорите SQL, чтобы удалить пользователей, чьи UserId равен их UserId- а это , очевидно, все они.

Используйте deleted виртуальная таблица для проверки того, какие записи будут удалены:
Использование вставленных и удаленных таблиц - SQL Server | Microsoft Docs[^]

ALTER TRIGGER [dbo].[UserTrigger]
ON [dbo].[Users]
INSTEAD OF DELETE
AS
BEGIN
    SET NOCOUNT ON;
    
    If Exists(SELECT 1 FROM deleted WHERE UserId = 101)
    BEGIN
        RAISERROR('Not Allowed to delete UserId : 101 as is a SUPER USER', 16, 1);
        ROLLBACK TRANSACTION;
        Return;
    END;
    
    DELETE
    FROM
        Users
    WHERE
        UserId In (SELECT UserId FROM deleted)
    ;
END 


MaximusDebois

спасибо чувак это сработало

Рейтинг:
0

Wendelius

Я не совсем вижу необходимости использовать instead of спусковой крючок. С помощью такого рода триггера вам нужно заново реализовать всю логику. Не было бы удобнее использовать обычный триггер и просто проверить, что было удалено и приемлемо ли это.

Рассмотрим следующий пример

create table Users (
   UserId int,
   Name varchar(100)
);

insert into Users (UserId, Name) values 
(101, 'A'),
(102, 'B'),
(103, 'C');

create trigger UserTrigger on Users
after delete as
begin
  If Exists(SELECT 1 FROM deleted WHERE UserId = 101)
    BEGIN
        ROLLBACK TRANSACTION;
        RAISERROR('Not Allowed to delete UserId : 101 as is a SUPER USER', 16, 1);
    END;
end;

begin transaction;
delete from Users where UserId = 102; -- Successful

begin transaction;
delete from Users where UserId = 101; -- Raises error

begin transaction;
delete from Users;                    -- Raises error

На самом деле есть и более "декларативный" способ сделать это. Вы также можете определить дочернюю таблицу с внешним ключом к таблице Users. После этого вы можете добавить нужные идентификаторы пользователя в эту дочернюю таблицу, чтобы предотвратить удаление этих идентификаторов. Это решение не требовало бы никакого кода T-SQL, а ведение списка "постоянных" пользователей было бы более динамичным.

Рассмотреть следующее
create table Users2 (
   UserId int primary key,
   Name varchar(100)
);

insert into Users2 (UserId, Name) values 
(101, 'A'),
(102, 'B'),
(103, 'C');

create table Users2DeletePrevention (
   UserId int references Users2(UserId)
);

insert into Users2DeletePrevention (UserId) values (101);

begin transaction;
delete from Users2 where UserId = 102; -- Successful

begin transaction;
delete from Users2 where UserId = 101; -- Raises a foreign key error

begin transaction;
delete from Users2;                    -- Raises a foreign key error

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