基于多对多关系触发插入多行
Trigger to insert multiple rows based on many-to-many relationship
我有三个表 Reservation
、Reservation_Passenger
和 Ticket
。
每个预订可以有多名乘客。每次预订状态更新为 'Booked' 时,我都需要创建一个触发器来插入一张票(根据乘客数量)。我怎样才能实现它?
- 预订(reservationId,状态)
- Reservation_Passenger (reservationId, passengerId)
- 机票(ticketId, passengerId, issuedDate)
我尝试过的:
CREATE
TRIGGER Generate_Ticket
ON Reservation
AFTER UPDATE
AS
DECLARE @reservationStatus varchar(15)
SELECT @reservationStatus = INSERTED.Status from INSERTED
IF @reservationStatus = 'Booked'
BEGIN
--stuck here
END
GO
与将状态存储到变量中的方式相同,您也可以检索 reservationId
DECLARE @reservationStatus varchar(15)
DECLARE @reservationId int
SELECT @reservationId = INSERTED.reservationId,
@reservationStatus = INSERTED.Status
FROM INSERTED
现在,在您卡住的部分,要为预订中的每位乘客创建一张票,您可以在 INSERT 中提供 SELECT 相关乘客。
INSERT INTO Ticket (passengerId, issuedDate)
SELECT passengerId, getdate()
FROM Reservation_Passenger
WHERE reservationId = @reservationId
PS 您需要注意,您的代码不会在同一个 UPDATE 命令上将多个预订更改为已预订。因为在那种情况下,触发器只会触发一次,所有更新的预订都存储在 INSERTED 数据集中。您将需要使用 CURSOR 遍历所有这些预订以应用您的逻辑,或者切换到这个更简单的触发器,一步为所有预订的所有乘客创建机票:
CREATE TRIGGER Generate_Ticket ON Reservation AFTER UPDATE
AS
INSERT INTO Ticket (passengerId, issuedDate)
SELECT P.passengerId, getdate()
FROM INSERTED as R
INNER JOIN Reservation_Passenger as P on P.reservationId = R.reservationID
WHERE R.Status = 'Booked'
您还应该小心,因为在预订 table 上更新任何字段时都会触发触发器。如果您要更新另一个字段,例如对已预订的评论的评论,您的触发器将再次复制他的所有门票。
我建议您不仅要检查 INSERTED.Status = 'Booked',还要检查 DELETED.Status <> 'Booked',这样您只在状态字段时创建工单已从其他内容更改为已预订。
那就是:
CREATE TRIGGER Generate_Ticket ON Reservation AFTER UPDATE
AS
INSERT INTO Ticket (passengerId, issuedDate)
SELECT P.passengerId, getdate()
FROM INSERTED as I
INNER JOIN DELETED as D on D.reservationId = I.reservationID
INNER JOIN Reservation_Passenger as P on P.reservationId = I.reservationID
WHERE I.Status = 'Booked' and coalesce(D.Status, '') <> 'Booked'
我有三个表 Reservation
、Reservation_Passenger
和 Ticket
。
每个预订可以有多名乘客。每次预订状态更新为 'Booked' 时,我都需要创建一个触发器来插入一张票(根据乘客数量)。我怎样才能实现它?
- 预订(reservationId,状态)
- Reservation_Passenger (reservationId, passengerId)
- 机票(ticketId, passengerId, issuedDate)
我尝试过的:
CREATE
TRIGGER Generate_Ticket
ON Reservation
AFTER UPDATE
AS
DECLARE @reservationStatus varchar(15)
SELECT @reservationStatus = INSERTED.Status from INSERTED
IF @reservationStatus = 'Booked'
BEGIN
--stuck here
END
GO
与将状态存储到变量中的方式相同,您也可以检索 reservationId
DECLARE @reservationStatus varchar(15)
DECLARE @reservationId int
SELECT @reservationId = INSERTED.reservationId,
@reservationStatus = INSERTED.Status
FROM INSERTED
现在,在您卡住的部分,要为预订中的每位乘客创建一张票,您可以在 INSERT 中提供 SELECT 相关乘客。
INSERT INTO Ticket (passengerId, issuedDate)
SELECT passengerId, getdate()
FROM Reservation_Passenger
WHERE reservationId = @reservationId
PS 您需要注意,您的代码不会在同一个 UPDATE 命令上将多个预订更改为已预订。因为在那种情况下,触发器只会触发一次,所有更新的预订都存储在 INSERTED 数据集中。您将需要使用 CURSOR 遍历所有这些预订以应用您的逻辑,或者切换到这个更简单的触发器,一步为所有预订的所有乘客创建机票:
CREATE TRIGGER Generate_Ticket ON Reservation AFTER UPDATE
AS
INSERT INTO Ticket (passengerId, issuedDate)
SELECT P.passengerId, getdate()
FROM INSERTED as R
INNER JOIN Reservation_Passenger as P on P.reservationId = R.reservationID
WHERE R.Status = 'Booked'
您还应该小心,因为在预订 table 上更新任何字段时都会触发触发器。如果您要更新另一个字段,例如对已预订的评论的评论,您的触发器将再次复制他的所有门票。
我建议您不仅要检查 INSERTED.Status = 'Booked',还要检查 DELETED.Status <> 'Booked',这样您只在状态字段时创建工单已从其他内容更改为已预订。
那就是:
CREATE TRIGGER Generate_Ticket ON Reservation AFTER UPDATE
AS
INSERT INTO Ticket (passengerId, issuedDate)
SELECT P.passengerId, getdate()
FROM INSERTED as I
INNER JOIN DELETED as D on D.reservationId = I.reservationID
INNER JOIN Reservation_Passenger as P on P.reservationId = I.reservationID
WHERE I.Status = 'Booked' and coalesce(D.Status, '') <> 'Booked'