首页 > 解决方案 > 如何解决这个存储过程问题?

问题描述

我在 SQL Server 2017 中创建了这个存储过程,显然它一开始可以工作,但突然就停止工作了。

这应该验证汽车是否已经进入停车场。如果没有,则在车辆表中创建行和在车辆支付表中创建行。如果不是这种情况,它只会在车辆支付表中创建行并将状态更新为(意味着它当前处于)。

--table names, fields and variables are in spanish
CREATE TABLE Estacionamiento.Vehiculo
(
    id INT IDENTITY (1, 1) NOT NULL
        CONSTRAINT PK_Vehiculo_Estacionamiento_id
        PRIMARY KEY CLUSTERED (id),
    tipoVehiculo INT NOT NULL,
    placa NVARCHAR(8) NOT NULL UNIQUE,
        CONSTRAINT CHK_Formato_Placa_Vehiculo
        CHECK (placa LIKE '[A-Z][A-Z][A-Z]-[0-9][0-9][0-9][0-9]'),
    estado BIT NOT NULL
)
GO

--Crear la tabla PagoVehiculo
CREATE TABLE Estacionamiento.PagoVehiculo
(
    id INT IDENTITY(1, 1) NOT NULL
        CONSTRAINT PK_Vehiculo_PagoVehiculo_id
        PRIMARY KEY CLUSTERED (id),
    vehiculo INT NOT NULL,
    fechaHoraEntrada DATETIME NOT NULL,
    fechaHoraSalida DATETIME NOT NULL,
    total DECIMAL NOT NULL
)
GO

--The problem is here
CREATE PROCEDURE SP_InsercionVehiculosEntradasSalidas
    (@placa NVARCHAR(8),
     @tipoVehiculo NVARCHAR(15))
AS
    BEGIN TRY
        DECLARE @placaVehiculo INT
        DECLARE @horaEntrada DATETIME
        DECLARE @horaSalida DATETIME

        IF NOT EXISTS(SELECT * FROM Estacionamiento.Vehiculo WHERE placa = @placa AND tipoVehiculo = @tipoVehiculo)
        BEGIN
            INSERT INTO Estacionamiento.Vehiculo (placa, tipoVehiculo, estado)
            VALUES (@placa, @tipoVehiculo, 1)

            SET @placaVehiculo = (SELECT id FROM Estacionamiento.Vehiculo WHERE placa = @placa)

            INSERT INTO Estacionamiento.PagoVehiculo (vehiculo, fechaHoraEntrada, fechaHoraSalida, total)
            VALUES (@placaVehiculo, GETDATE(), GETDATE(), 0)
        END
        ELSE IF EXISTS(SELECT * FROM Estacionamiento.Vehiculo WHERE placa = @placa)
        BEGIN
            SET @placaVehiculo = (SELECT id FROM Estacionamiento.Vehiculo WHERE placa = @placa)
            PRINT(@placaVehiculo)

            IF (SELECT estado FROM Estacionamiento.Vehiculo WHERE placa = @placa) = 0
            BEGIN
                INSERT INTO Estacionamiento.PagoVehiculo (vehiculo, fechaHoraEntrada, fechaHoraSalida, total)
                VALUES (@placaVehiculo, GETDATE(), GETDATE(), 0)

                UPDATE Estacionamiento.Vehiculo 
                SET estado = 1
            END
            ELSE IF (SELECT estado FROM Estacionamiento.Vehiculo WHERE placa = @placa) = 1
            BEGIN
                UPDATE Estacionamiento.PagoVehiculo 
                SET fechaHoraSalida = GETDATE() 
                WHERE vehiculo = @placaVehiculo  
                  AND id = (SELECT MAX(id) FROM Estacionamiento.PagoVehiculo)

                SET @horaEntrada = (SELECT MAX(fechaHoraEntrada) 
                                    FROM Estacionamiento.PagoVehiculo 
                                    WHERE vehiculo = @placaVehiculo)
                SET @horaSalida = (SELECT MAX(fechaHoraSalida) 
                                   FROM Estacionamiento.PagoVehiculo 
                                   WHERE vehiculo = @placaVehiculo)

                UPDATE Estacionamiento.Vehiculo 
                SET estado = 0

                UPDATE Estacionamiento.PagoVehiculo 
                SET total = dbo.Fctn_CalculoPagoVehiculo(@horaEntrada, @horaSalida, @tipoVehiculo) 
                WHERE vehiculo = @placaVehiculo
                  AND id = (SELECT MAX(id) 
                            FROM Estacionamiento.PagoVehiculo)
            END
        END
    END TRY
    BEGIN CATCH
        DECLARE @error INT

        SET @error = @@ERROR

        RETURN @error
    END CATCH
GO

我期待在需要时验证、插入和更新。

标签: sql-server

解决方案


在阅读您的过程时,我注意到了一些事情:

在某些地方,您可以通过以下方式检查表中的独特汽车vehiculo

WHERE placa = @placa AND tipoVehiculo = @tipoVehiculo

和其他地方做的只是

WHERE placa = @placa

根据哪个为您提供独特的汽车,在您的代码中保持一致

当汽车插入时PagoVehiculo,您将使用当前日期填充进入和退出日期。虽然技术上没有错误,但我希望退出日期在汽车退出之前为空。这将有助于数据的清晰度。

有很多地方可以检查select *,可以代替select 1,效果会更好

没有ELSE声明捕捉意外情况并报告和发布。

有一次,您试图通过执行以下操作获取特定汽车的 pagoVehiculo 表的 id:

id = (SELECT MAX(id) FROM Estacionamiento.PagoVehiculo)

没有保证会检索到正确的汽车(特别是因为您可能有多个客户同时写入表。添加一个附加子句以确保您正在为正确的汽车提取数据。例如:

id = (SELECT MAX(id) FROM Estacionamiento.PagoVehiculo where vehiculo = @placaVehiculo)

就 proc 的情况而言,我的猜测是要么静默失败,要么没有落入 IF 或 ELSE IF 中,因此只是跳过了整个过程。我将按如下方式进行调试(在查看评论后:

  1. 在主 If 语句中添加和 ELSE 语句以捕获意外情况
  2. 在 IF 部分、ELSE If 和 ELSE 部分添加一个打印语句(类似print ('in IF statement')这样您就知道正在执行哪个分支(或者您可以只调试它,如果您熟悉 SQL Proc 调试)
  3. 删除该try catch部分并查看是否有异常被捕获并且由于某种原因没有重新抛出。

哦,我刚刚看到,在表tipoVehiculo中定义INT,但是您在 proc 中传递了 NVARCHAR(15),这可能是您遇到问题的原因。


推荐阅读