Почему другой результат, когда я выполняю функцию напрямую и использую ее в процедуре? - PullRequest
1 голос
/ 19 июня 2019

Я выполняю услугу бронирования номеров, в которой, помимо бронирования комнаты, для встречи будут зарезервированы некоторые необходимые ресурсы.

У меня есть хранимая процедура, которая выполняет некоторые предварительные проверки и после завершения резервирует комнату (вставляя новую строку в таблицу бронирования). После этого начинается процесс резервирования ресурса.

Для каждого типа ресурса я хочу знать, сколько из них можно зарезервировать бесплатно, поэтому я создал для него функцию. И вот тут происходит странное поведение.

Если я вызываю функцию из обычного запроса, она возвращает количество свободных ресурсов, которые должны быть зарезервированы.

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

Моя основная хранимая процедура такова:

CREATE PROCEDURE [dbo].[Pr_SaveBooking] 
    @room_id        INT = 0, 
    @start_date     DATETIME,
    @end_date       DATETIME,
    @resources      BookingResourceType READONLY
AS
BEGIN
    SET NOCOUNT ON;
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    BEGIN TRANSACTION;

    BEGIN TRY
        DECLARE @id BIGINT;

        -- Some checks
        -- ...
        -- ...

        INSERT INTO Booking(room_id, start_date, end_date) 
        VALUES (@room_id, @start_date, @end_date);

        IF (@@ROWCOUNT <= 0) 
            THROW 55008, 'Error', 1;

        SELECT @id = SCOPE_IDENTITY();
        PRINT CONCAT('Booking done (#', @id, ')')

        EXEC Pr_InsertBookingResources @id, @resources, @start_date, @end_date;
        PRINT 'BookingResources done'


    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0 
            ROLLBACK TRANSACTION;

        PRINT 'Rollback';
        THROW;

    END CATCH

    IF @@TRANCOUNT > 0 
        COMMIT TRANSACTION;
END

Эта процедура вызывает другое, которое отвечает за создание резервов ресурсов.

CREATE PROCEDURE [dbo].[Pr_InsertBookingResources]
    @bookingId      INT,
    @resources      BookingResourceType READONLY,
    @startDate      DATETIME,
    @endDate        DATETIME
AS

DECLARE @cursor CURSOR;
DECLARE @bookingResourceId INT;
DECLARE @resourceId INT;
DECLARE @amount INT;
DECLARE @amountFree INT;

BEGIN

    -- For every resource
    SET 
        @cursor = CURSOR 
    FOR
        SELECT 
            bookingResource_id, resource_id, amount
        FROM 
            @resources;

    OPEN @cursor 

    FETCH NEXT FROM @cursor INTO @bookingResourceId, @resourceId, @amount;

    -- Iterate
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SELECT @amountFree = [dbo].[Fu_GetFreeResources](@startDate, @endDate, @resourceId);

        DECLARE @text NVARCHAR(250);
        SELECT @text = CONCAT('StartDate = ', @startDate, ', EndDate = ', @endDate, ', ResourceId = ', @resourceId, ', AmountFree = ', @amountFree);
        THROW 59002, @text, 1;

        -- Some code to insert into BookingResource
        -- ...
        -- ...

        FETCH NEXT FROM @cursor INTO @bookingResourceId, @resourceId, @amount;
    END; 

    CLOSE @cursor;
    DEALLOCATE @cursor;
END

В этом случае у меня есть некоторый код для выдачи ошибки, чтобы показать мне значения. Брошенное сообщение таково:

StartDate = Jun 24 2019 12:30PM, EndDate = Jun 24 2019 2:00PM, ResourceId = 3, AmountFree =  

Наконец, код функции таков:

CREATE FUNCTION [dbo].[Fu_GetFreeResources] (
    @start_date datetime, 
    @end_date datetime, 
    @resource_id bigint
)
RETURNS int
AS
BEGIN
    DECLARE @reserved int = 0;
    DECLARE @total int = 0;


    SELECT 
        @reserved = SUM(br.amount)
    FROM 
        BookingResource AS br,
        Booking AS b
    WHERE 
        br.booking_id = b.id AND
        br.resource_id = @resource_id AND 
        (
            (b.start_date < @start_date  AND b.end_date > @start_date) OR
            (b.start_date < @end_date    AND b.end_date > @end_date)  OR
            (b.start_date >= @start_date AND b.end_date <= @end_date)
        );


    SELECT 
        @total = amount
    FROM 
        Resource
    WHERE 
        id = @resource_id;

    RETURN @total - @reserved;
END

Если я выполню этот фрагмент предложения:

DECLARE @start_date DATETIME;
DECLARE @end_date DATETIME;
DECLARE @R INT;

SELECT @start_date = start_date, @end_date = end_date FROM Booking WHERE id = 19;
SELECT @R = dbo.Fu_ObtenerNumRecursosLibres(@start_date, @end_date, 3);

PRINT CONCAT('Start date: ', @start_date);
PRINT CONCAT('End date: ', @end_date);
PRINT CONCAT('Resource Id: ', 3);
PRINT CONCAT(Free resources: ', @R);

Я получаю этот вывод:

Start date: Jun 24 2019 12:30PM
End date: Jun 24 2019  2:00PM
Resource Id: 3
Free resources: 3

Но когда я пытаюсь зарезервировать комнату с тем же ресурсом:

DECLARE @start_date DATETIME;
DECLARE @end_date DATETIME;
DECLARE @resources BookingResourceType;

SELECT @start_date = start_date, @end_date = end_date FROM Booking WHERE id = 19;
INSERT INTO @resources(bookingResource_id, resource_id, amount) VALUES (NULL, 3, 8);

PRINT CONCAT('Start date: ', @start_date);
PRINT CONCAT('End date: ', @end_date);
PRINT CONCAT('Resource Id: ', 3);

EXEC [dbo].[Pr_SaveBooking] 18, @start_date, @end_date, @resources

Я получаю этот другой вывод:

Start date: Jun 24 2019 12:30PM
End date: Jun 24 2019  2:00PM
Resource Id: 3
Booking done (#57)
Rollback
Mensaje 59002, nivel 16, estado 1, procedimiento Pr_InsertBookingResources, línea 41 [línea de inicio de lote 0]
StartDate = Jun 24 2019 12:30PM, EndDate = Jun 24 2019  2:00PM, ResourceId = 3, AmountFree = 

Я недавно использую SQL Server, так что, возможно, это фиктивная ошибка, но я ее не нашел.

Что я переживаю? Почему это происходит? Любая рекомендация?

Спасибо

PS : создание базы данных


CREATE TYPE [dbo].[BookingResourceType] AS TABLE(
    [bookingResource_id] [bigint] NULL,
    [resource_id] [bigint] NOT NULL,
    [amount] [int] NOT NULL
)
GO




CREATE TABLE [dbo].[Booking](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [user_id] [bigint] NOT NULL,
    [room_id] [bigint] NOT NULL,
    [observations] [text] NULL,
    [start_date] [datetime] NOT NULL,
    [end_date] [datetime] NOT NULL,
 CONSTRAINT [Booking_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

GO


CREATE TABLE [dbo].[BookingResource](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [resource_id] [bigint] NOT NULL,
    [booking_id] [bigint] NOT NULL,
    [amount] [int] NOT NULL,
 CONSTRAINT [BookingResource_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY],
 CONSTRAINT [BookingResource_UN] UNIQUE NONCLUSTERED 
(
    [resource_id] ASC,
    [booking_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


CREATE TABLE [dbo].[Resource](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](50) NOT NULL,
    [amount] [int] NOT NULL,
 CONSTRAINT [Resource_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


CREATE TABLE [dbo].[Room](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](100) NOT NULL,
 CONSTRAINT [Room_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


CREATE TABLE [dbo].[User](
    [id] [bigint] IDENTITY(1,1) NOT NULL,
    [name] [nvarchar](60) NOT NULL,
    [code] [nvarchar](50) NOT NULL,
    [surname] [nvarchar](60) NOT NULL,
 CONSTRAINT [User_PK] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO




ALTER TABLE [dbo].[BookingResource] ADD  DEFAULT ((1)) FOR [amount]
GO
ALTER TABLE [dbo].[Resource] ADD  DEFAULT ((1)) FOR [amount]
GO
ALTER TABLE [dbo].[Booking]  WITH CHECK ADD  CONSTRAINT [Booking_Room_FK] FOREIGN KEY([room_id])
REFERENCES [dbo].[Room] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Booking] CHECK CONSTRAINT [Booking_Room_FK]
GO
ALTER TABLE [dbo].[Booking]  WITH CHECK ADD  CONSTRAINT [Booking_User_FK] FOREIGN KEY([user_id])
REFERENCES [dbo].[User] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Booking] CHECK CONSTRAINT [Booking_User_FK]
GO
ALTER TABLE [dbo].[BookingResource]  WITH CHECK ADD  CONSTRAINT [BookingResource_Booking_FK] FOREIGN KEY([booking_id])
REFERENCES [dbo].[Booking] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[BookingResource] CHECK CONSTRAINT [BookingResource_Booking_FK]
GO
ALTER TABLE [dbo].[BookingResource]  WITH CHECK ADD  CONSTRAINT [BookingResource_Resource_FK] FOREIGN KEY([resource_id])
REFERENCES [dbo].[Resource] ([id])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[BookingResource] CHECK CONSTRAINT [BookingResource_Resource_FK]
GO

и вставить данные:


INSERT INTO Room(id, name) VALUES (1,  'Sala de Juntas');
INSERT INTO Room(id, name) VALUES (2,  'Sala de Reuniones');
INSERT INTO Room(id, name) VALUES (3,  'Sala de Conferencias');
INSERT INTO Room(id, name) VALUES (11, 'Sala de Cursos');
INSERT INTO Room(id, name) VALUES (18, 'Sala de Espera');

INSERT INTO Resource(id, name, amount) VALUES (1, 'Teléfono',  5);
INSERT INTO Resource(id, name, amount) VALUES (2, 'Altavoces', 5);
INSERT INTO Resource(id, name, amount) VALUES (3, 'Proyector', 5);
INSERT INTO Resource(id, name, amount) VALUES (4, 'Micrófono', 5);
INSERT INTO Resource(id, name, amount) VALUES (5, 'Ordenador', 5);

INSERT INTO [dbo].[User](id, name, code, surname) VALUES (1,  'Nombre01', 'Codigo01', 'Apellido01');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (2,  'Nombre02', 'Codigo02', 'Apellido02');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (3,  'Nombre03', 'Codigo03', 'Apellido03');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (4,  'Nombre04', 'Codigo04', 'Apellido04');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (5,  'Nombre05', 'Codigo05', 'Apellido05');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (6,  'Nombre06', 'Codigo06', 'Apellido06');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (7,  'Nombre07', 'Codigo07', 'Apellido07');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (8,  'Nombre08', 'Codigo08', 'Apellido08');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (9,  'Nombre09', 'Codigo09', 'Apellido09');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (10, 'Nombre10', 'Codigo10', 'Apellido10');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (11, 'Nombre11', 'Codigo11', 'Apellido11');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (12, 'Nombre12', 'Codigo12', 'Apellido12');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (13, 'Nombre13', 'Codigo13', 'Apellido13');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (14, 'Nombre14', 'Codigo14', 'Apellido14');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (15, 'Nombre15', 'Codigo15', 'Apellido15');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (16, 'Nombre16', 'Codigo16', 'Apellido16');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (17, 'Nombre17', 'Codigo17', 'Apellido17');
INSERT INTO [dbo].[User](id, name, code, surname) VALUES (18, 'Nombre18', 'Codigo18', 'Apellido18');

INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (1,  15, 4, NULL, '2019-06-25 10:30:00.000', '2019-06-25 15:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (2,  1,  4, NULL, '2019-06-28 16:30:00.000', '2019-06-28 18:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (3,  9,  2, NULL, '2019-06-21 10:30:00.000', '2019-06-21 13:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (4,  6,  1, NULL, '2019-06-24 14:00:00.000', '2019-06-24 16:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (5,  11, 5, NULL, '2019-06-25 09:30:00.000', '2019-06-25 11:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (6,  9,  2, NULL, '2019-06-22 15:00:00.000', '2019-06-22 16:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (7,  17, 5, NULL, '2019-06-28 15:30:00.000', '2019-06-28 13:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (8,  11, 2, NULL, '2019-06-30 08:30:00.000', '2019-06-30 13:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (9,  15, 5, NULL, '2019-06-20 13:30:00.000', '2019-06-20 14:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (10, 15, 4, NULL, '2019-06-21 10:00:00.000', '2019-06-21 16:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (11, 17, 2, NULL, '2019-06-24 14:30:00.000', '2019-06-24 15:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (12, 2   3, NULL, '2019-06-29 11:00:00.000', '2019-06-29 13:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (13, 11, 4, NULL, '2019-06-28 13:30:00.000', '2019-06-28 14:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (14, 5,  5, NULL, '2019-06-20 12:00:00.000', '2019-06-20 13:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (15, 8,  3, NULL, '2019-06-30 10:00:00.000', '2019-06-30 18:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (16, 11, 2, NULL, '2019-06-26 12:00:00.000', '2019-06-26 12:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (17, 9,  4, NULL, '2019-06-25 15:30:00.000', '2019-06-25 18:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (18, 9,  3, NULL, '2019-06-20 07:30:00.000', '2019-06-20 14:30:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (19, 18, 1, NULL, '2019-06-24 12:30:00.000', '2019-06-24 14:00:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (20, 4,  2, 'Horario raro, comienza a las 9:15 y termina a las 12:20', '2019-06-28 09:15:00.000', '2019-06-28 12:20:00.000');
INSERT INTO Booking(id, user_id, room_id, observations, start_date, end_date) VALUES (21, 1,  2, '', '2019-06-03 10:00:00.000', '2019-06-03 12:30:00.000');

INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (1,  1, 3,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (2,  2, 18, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (4,  4, 14, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (5,  5, 10, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (7,  2, 20, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (8,  3, 12, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (9,  4, 9,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (10, 5, 16, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (11, 1, 16, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (12, 2, 4,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (13, 3, 8,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (14, 4, 1,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (15, 5, 11, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (16, 1, 8,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (17, 2, 5,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (18, 3, 7,  2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (19, 4, 15, 2);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (34, 2, 21, 1);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (35, 4, 21, 1);
INSERT INTO BookingResource(id, resource_id, booking_id, amount) VALUES (83, 3, 19, 7);

1 Ответ

1 голос
/ 19 июня 2019

Удалите THROW.

Когда вы throw в вашем Pr_InsertBookingResources, ошибка возвращается к Pr_SaveBooking, которая перехватывает его внутри блока try-tran-catch и откатываетсякаждое произведенное изменение (как указывает напечатанная строка «Откат»).

Не используйте throw для печати.Если вы хотите печатать точно во время выполнения, используйте RAISERROR('yourtexthere',0,0) with nowait.Обратите внимание, что первый 0 - это уровень серьезности, а уровень серьезности 0 означает, что на самом деле это не ошибка, и поток не передается в блок catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...