#sql #sql-server
#sql #sql-server
Вопрос:
Я работаю над триггером, который должен блокировать вставку, когда @verkoperstatus равно 0; это работает, но по какой-то причине он также останавливает вставку, когда @verkoperstatus равно 1. Что может быть основной причиной этого?
CREATE TRIGGER [dbo].[verkoper_check] ON [dbo].[Verkoper]
FOR INSERT,UPDATE
AS
BEGIN
DECLARE @verkoperstatus bit
DECLARE @gebruikersnaam varchar(25)
SELECT @gebruikersnaam = gebruikersnaam FROM inserted
SELECT @verkoperstatus = verkoper FROM Gebruiker WHERE gebruikersnaam = @gebruikersnaam
IF @verkoperstatus = 0
BEGIN
RAISERROR('Geen verkoper!',18,1);
ROLLBACK;
END
ELSE
BEGIN
COMMIT;
END
END
Он должен вставляться, когда @verkoperstatus равно 1, и вызывать ошибку, когда @verkoperstatus равно 0.
Таблица Gebruiker — это ссылки, которые включают столбец ‘gebruikersnaam’ и столбец ‘verkoper’. Значение столбца ‘gebruikersnaam’ является идентифицирующим столбцом, который (в данном конкретном случае — ‘Lars’). Verkoper — это столбец битов, который указывает, является ли он продавцом или нет, поэтому он имеет значение 0 или 1.
Цель, которую я пытаюсь достичь, — вставить в таблицу Verkoper, если ‘gebruikersnaam’ имеет значение ‘verkoper’, равное единице. Это означает, что если в Gebruiker есть строка с ‘gebruikersnaam’ из Lars, а значение verkoper равно 1. Это будет разрешенная вставка в таблицу Verkoper.
Поскольку в справочнике есть следующие столбцы: ‘gebruikersnaam’, ‘banknaam’, ‘rekeningnummer’, ‘controleoptienaam’ и ‘creditcardnummer’. Когда ‘gebruikersnaam’ соответствует ‘gebruikersnaam’ из таблицы Gebruikers И имеет значение 1 в столбце ‘verkoper’, этой записи будет разрешено вставляться в таблицу Verkoper.
На данный момент в столбце Gebruikers есть строка, которая включает в себя gebruikersnaam ‘Lars’ и значение verkoper ‘1’. Это означает, что любая вставка SQL с gebruikersnaam ‘Lars’ должна быть разрешена в таблице Verkoper.
Однако это работает не так, как я считаю нужным.
Это таблицы, упомянутые выше:
CREATE TABLE Verkoper (
gebruikersnaam varchar(25) NOT NULL,
banknaam varchar(255) NULL,
rekeningnummer varchar(32) NULL,
controleoptienaam char(10) NOT NULL,
creditcardnummer integer NULL,
CONSTRAINT pk_Verkoper PRIMARY KEY (gebruikersnaam),
CONSTRAINT fk_Verkoper_Gebruikersnaam FOREIGN KEY (gebruikersnaam) REFERENCES Gebruiker(gebruikersnaam),
CONSTRAINT ck_rekening CHECK (rekeningnummer is NOT NULL OR creditcardnummer is NOT NULL),
CONSTRAINT ck_controleoptie CHECK (controleoptienaam IN('Post', 'Creditcard'))
)
CREATE TABLE Gebruiker(
gebruikersnaam varchar(25) NOT NULL,
voornaam varchar(25) NOT NULL,
achternaam varchar(25) NOT NULL,
adresregel_1 varchar(255) NULL,
adresregel_2 varchar(255) NULL,
postcode char(7) NULL,
plaatsnaam varchar(255) NULL,
land varchar(255) NULL,
geboortedag char(10) NOT NULL,
mailbox varchar(255) NOT NULL,
wachtwoord varchar(255) NOT NULL,
verkoper bit NOT NULL,
CONSTRAINT pk_gebruiker PRIMARY KEY (gebruikersnaam),
)
Для вставок я использую следующие данные:
INSERT INTO Gebruiker VALUES ('Lars', 'Lars', 'Last_name', null, null, null, null, null, '04/04/2019', 'lars@mymailbox.cloud', 'MyPassword', 1)
INSERT INTO Verkoper VALUES ('Lars', 'ING', 'NL32ABN32492809', 'Post', null)
Комментарии:
1. Ваш триггер ошибочен; предполагается, что вы будете использовать только
INSERT
/UPDATE
одну строку за раз. Триггер срабатывает один раз для каждого оператора DML, а не один раз для каждой строки для оператора DML. Вероятно, именно поэтому вы думаете, что триггер «не срабатывает»; это потому, что он делает не то, что вы намереваетесь.2. Вы также совершаете транзакцию, которую не запускали.
3. @GSerg триггер уже находится в транзакции. Вы не можете запустить его в триггере, поскольку SQL Server не поддерживает «вложенные преобразования». Хотя, я признаю,
COMMIT
это не нужно, так как это должно обрабатываться вне триггера.4. @Larnu Я не говорю, что нет транзакции для фиксации. Я говорю, что триггер зафиксирует транзакцию, запущенную вызывающим кодом. Вызывающий код вряд ли будет подготовлен к этому.
5. да, я согласен, @GSerg . Я пытался добавить некоторые дополнительные детали к вашему комментарию, поскольку это можно понимать как означающее (по OP), что они должны запустить транзакцию внутри триггера; что делать неправильно.
Ответ №1:
Это непроверено, однако я подозреваю, что это та логика, которая вам действительно нужна:
CREATE TRIGGER [dbo].[verkoper_check] ON [dbo].[Verkoper]
FOR INSERT,UPDATE
AS BEGIN
IF EXISTS(SELECT 1
FROM inserted i
JOIN Gebruiker G ON i.gebruikersnaam = G.gebruikersnaam
WHERE G.verkoper = 0) BEGIN
RAISERROR('Geen verkoper!',18,1);
ROLLBACK;
END;
END;
Комментарии:
1. Это, к сожалению, возвращает
Msg 3609, Level 16, State 1, Line 1 The transaction ended in the trigger. The batch has been aborted.
2. Почему это нежелательно, @Lars? Это именно то, что вы описали, чего хотите добиться.
3. Ну, вставка не проходит, хотя так и должно быть, по крайней мере, я так считаю. Поскольку verkoper = 1 на вставке, которую я пытаюсь достичь.
INSERT INTO Verkoper VALUES ('Lars', 'ING', 'NL32ABN32492809', 'Post', null)
учетная запись Lars имеет значение Verkoper, равное 1.4. Это
INSERT
утверждение для меня бессмысленно @Lars. Я не знаю, в какие столбцы вставляются эти значения, и я понятия не имею, как это связано с вашей таблицейGebruiker
. Отредактируйте свой вопрос, чтобы включить DDL и ваши таблицы, а затем предоставьте образец базы данных и ожидайте результатов (все это должно быть какtext
).5. Я отредактировал основной вопрос и надеюсь, что включил достаточно информации, чтобы сделать мой вопрос более понятным.