sql - Mad cursor (SQL Server) 使程序冻结和崩溃
问题描述
我开发了一个航班预订程序。我在触发器中有一个(荒谬的)条件,如果它被填充则应该执行。
我的问题是,当我调用存储过程为客户预订航班时,我的程序由于延迟而冻结并崩溃。
我知道这个问题来自我的触发器,你知道是什么卡住了吗?
如果您需要更多详细信息(表、存储过程、代码),请随时告诉我!(对不起法国的评论:p)
ALTER TRIGGER [dbo].[Tr_Check60j]
ON [dbo].[Reservation]
FOR INSERT
AS
BEGIN
DECLARE @IdVolInsere INT, @DateVol DATETIME, @IdVolExistant INT, @IdClient INT
SELECT @IdVolInsere = v.VOL_Id
FROM Vol v
JOIN Planning AS p ON p.PLA_Vol_Id = v.VOL_Id
JOIN inserted AS i ON p.PLA_Id = i.RES_Pla_Id
WHERE v.VOL_Id = p.PLA_Vol_Id
AND p.PLA_Id = i.RES_Pla_Id
SELECT @IdClient = i.RES_Client_Id
FROM inserted i
DECLARE @DateVolExistant DATETIME, @DateVolInsere DATETIME;
DECLARE @IdVilleDepartExistant INT, @IdVilleArriveeExistant INT;
DECLARE @IdVilleDepartInseree INT, @IdVilleArriveeInseree INT;
-- Sélectionne l'id des villes du vol inséré
SELECT @IdVilleDepartInseree = v.VOL_Vil_Depart_Id FROM Vol v WHERE v.VOL_Id = @IdVolInsere
SELECT @IdVilleArriveeInseree = v.VOL_Vil_Arrivee_Id FROM Vol v WHERE v.VOL_Id = @IdVolInsere
SELECT @DateVolInsere = p.PLA_Date
FROM Planning p
JOIN inserted AS i ON i.RES_Pla_Id = p.PLA_Id
WHERE i.RES_Pla_Id = p.PLA_Id
-- Curseur qui compare chaque vol du client existant avec le vol inséré pour vérifier si le vol existant
-- est un vol retour, si oui, les 2 vols ont-ils plus de 60 jours entre eux?
-- Si oui, alors il faut vérifier s'il existe un vol réservé entre ces 2 vols --> S'il y en a un: ERREUR
DECLARE CR_Check_Vols_Par_Id_Client CURSOR FOR
SELECT v.VOL_Id
FROM Vol v
JOIN Planning AS p ON v.VOL_Id = p.PLA_Vol_Id
JOIN Reservation AS r ON p.PLA_Id = r.RES_Pla_Id
WHERE r.RES_Client_Id = @IdClient
OPEN CR_Check_Vols_Par_Id_Client
FETCH CR_Check_Vols_Par_Id_Client INTO @IdVolExistant
WHILE @@FETCH_STATUS = 0
BEGIN
-- Sélectionne l'id des villes aller (mêmes villes) du dernier vol existant à moins de 60j
SELECT @IdVilleDepartExistant = v.VOL_Vil_Depart_Id FROM Vol v WHERE v.VOL_Id = @IdVolExistant
SELECT @IdVilleArriveeExistant = v.VOL_Vil_Arrivee_Id FROM Vol v WHERE v.VOL_Id = @IdVolExistant
-- Vérifie s'il existe un vol aller pour le vol inséré
IF (@IdVilleDepartInseree = @IdVilleArriveeExistant) AND (@IdVilleArriveeInseree = @IdVilleDepartExistant)
BEGIN
SELECT @DateVolExistant = p.PLA_Date
FROM Planning p
JOIN Reservation AS r
ON r.RES_Pla_Id = p.PLA_Id
JOIN Vol AS v
ON p.PLA_Vol_Id = @IdVolExistant
JOIN inserted AS i
ON r.RES_Id = i.RES_Id
WHERE r.RES_Client_Id = @IdClient
-- Vérifie si le vol inséré est à une date de moins de 60 jours du vol retour existant
IF ( (DATEDIFF(DAY, @DateVolExistant , @DateVolInsere)) < 60 )
BEGIN
DECLARE @CheckVolEntre INT
-- Sélectionne un vol existant entre le vol aller inséré et le vol retour existant
SELECT @CheckVolEntre = v.VOL_Id
FROM Vol v
JOIN Planning AS p
ON v.VOL_Id = p.PLA_Vol_Id
JOIN Reservation AS r
ON p.PLA_Id = r.RES_Pla_Id
WHERE r.RES_Client_Id = @IdClient AND v.VOL_Id BETWEEN @IdVolExistant AND @IdVolInsere
-- Vérifie s'il existe un vol existant entre le vol aller inséré et le vol retour existant
IF (@CheckVolEntre != NULL)
BEGIN
RAISERROR('Réservation impossible', 1, 601)
ROLLBACK TRANSACTION
STOP
END
END
END
END
CLOSE CR_Check_Vols_Par_Id_Client
DEALLOCATE CR_Check_Vols_Par_Id_Client
END
先感谢您!
乔恩
解决方案
这只是一个临时的解决方法。正如我的评论中所述,您需要从触发器中删除光标。
您可能会遇到锁定问题。尝试下面的解决方法,看看是否有帮助。我还解决了一些编码问题。如前一条评论所述,您不能使用!=检查 NOT NULL ,它必须是IS NOT NULL
or IS NULL
。
ALTER TRIGGER [dbo].[Tr_Check60j]
ON [dbo].[Reservation]
FOR INSERT
AS
BEGIN
DECLARE @IdVolInsere INT, @DateVol DATETIME, @IdVolExistant INT, @IdClient INT
SELECT
@IdVolInsere = v.VOL_Id
FROM Vol v WITH ( NOLOCK )
JOIN Planning AS p WITH ( NOLOCK )
ON p.PLA_Vol_Id = v.VOL_Id
JOIN inserted AS i
ON p.PLA_Id = i.RES_Pla_Id
WHERE
v.VOL_Id = p.PLA_Vol_Id
AND p.PLA_Id = i.RES_Pla_Id
SELECT @IdClient = i.RES_Client_Id FROM inserted i;
DECLARE @DateVolExistant DATETIME, @DateVolInsere DATETIME;
DECLARE @IdVilleDepartExistant INT, @IdVilleArriveeExistant INT;
DECLARE @IdVilleDepartInseree INT, @IdVilleArriveeInseree INT;
-- Sélectionne l'id des villes du vol inséré
SELECT
@IdVilleDepartInseree = v.VOL_Vil_Depart_Id
, @IdVilleArriveeInseree = v.VOL_Vil_Arrivee_Id
FROM Vol v WITH ( NOLOCK )
WHERE
v.VOL_Id = @IdVolInsere;
SELECT
@DateVolInsere = p.PLA_Date
FROM Planning p WITH ( NOLOCK )
JOIN inserted AS i
ON i.RES_Pla_Id = p.PLA_Id
WHERE
i.RES_Pla_Id = p.PLA_Id
-- Curseur qui compare chaque vol du client existant avec le vol inséré pour vérifier si le vol existant
-- est un vol retour, si oui, les 2 vols ont-ils plus de 60 jours entre eux?
-- Si oui, alors il faut vérifier s'il existe un vol réservé entre ces 2 vols --> S'il y en a un: ERREUR
DECLARE CR_Check_Vols_Par_Id_Client CURSOR FOR
SELECT
v.VOL_Id
FROM Vol v WITH ( NOLOCK )
JOIN Planning AS p WITH ( NOLOCK )
ON v.VOL_Id = p.PLA_Vol_Id
JOIN Reservation AS r WITH ( NOLOCK )
ON p.PLA_Id = r.RES_Pla_Id
WHERE
r.RES_Client_Id = @IdClient
OPEN CR_Check_Vols_Par_Id_Client
FETCH CR_Check_Vols_Par_Id_Client INTO @IdVolExistant
WHILE @@FETCH_STATUS = 0
BEGIN
-- Sélectionne l'id des villes aller (mêmes villes) du dernier vol existant à moins de 60j
SELECT
@IdVilleDepartExistant = v.VOL_Vil_Depart_Id
, @IdVilleArriveeExistant = v.VOL_Vil_Arrivee_Id
FROM Vol v WITH ( NOLOCK )
WHERE
v.VOL_Id = @IdVolExistant;
-- Vérifie s'il existe un vol aller pour le vol inséré
IF (@IdVilleDepartInseree = @IdVilleArriveeExistant) AND (@IdVilleArriveeInseree = @IdVilleDepartExistant)
BEGIN
SELECT
@DateVolExistant = p.PLA_Date
FROM Planning p WITH ( NOLOCK )
JOIN Reservation AS r WITH ( NOLOCK )
ON r.RES_Pla_Id = p.PLA_Id
JOIN Vol AS v WITH ( NOLOCK )
ON p.PLA_Vol_Id = @IdVolExistant
JOIN inserted AS i
ON r.RES_Id = i.RES_Id
WHERE
r.RES_Client_Id = @IdClient;
-- Vérifie si le vol inséré est à une date de moins de 60 jours du vol retour existant
IF ( (DATEDIFF(DAY, @DateVolExistant , @DateVolInsere)) < 60 )
BEGIN
DECLARE @CheckVolEntre INT
-- Sélectionne un vol existant entre le vol aller inséré et le vol retour existant
SELECT
@CheckVolEntre = v.VOL_Id
FROM Vol v WITH ( NOLOCK )
JOIN Planning AS p WITH ( NOLOCK )
ON v.VOL_Id = p.PLA_Vol_Id
JOIN Reservation AS r WITH ( NOLOCK )
ON p.PLA_Id = r.RES_Pla_Id
WHERE
r.RES_Client_Id = @IdClient
AND v.VOL_Id BETWEEN @IdVolExistant AND @IdVolInsere;
-- Vérifie s'il existe un vol existant entre le vol aller inséré et le vol retour existant
IF (@CheckVolEntre IS NOT NULL)
BEGIN
RAISERROR('Réservation impossible', 1, 601)
ROLLBACK TRANSACTION
STOP
END
END
END
END
CLOSE CR_Check_Vols_Par_Id_Client
DEALLOCATE CR_Check_Vols_Par_Id_Client
END
推荐阅读
- laravel-5 - IFSC 编号无效。该数字应为 11 位数字,格式为 ABCD0123456 条带
- html - 无论我做什么,CSS 都不会加载到烧瓶中,即使直接加载到 HTML 文件中也是如此
- docker - 如何从 Dockerfile 等指令/脚本集创建 AWS AMI?
- php - 如何在 PHP 中将 While 循环 SQL 结果放入表中?
- flutter - 如何在 Dart 中的多个命名构造函数上重用构造函数?
- python - 使用 Python pyodbc 模块,如何从 SQL Server 存储过程中获取输出参数的值?
- java - 解析片段时出错:“${h3}”:无法解析模板或片段
- haskell - 模式匹配在 Haskell 函数中并非详尽无遗
- c# - 处理 SQS 项目队列的多线程方法
- c++ - 为什么 CTAD 不适用于结构内的模板化数据成员