SQL Server 2008 - использование локальных переменных для триггера INSERT и UPDATE - PullRequest
2 голосов
/ 04 декабря 2010

Я какое-то время возился с этой проблемой, но у меня ничего не работает.

Вопрос заключается в том, чтобы создать триггеры INSERT и UPDATE (tr_check_qty) для таблицы order_details, чтобы разрешать только заказы продуктов, количество которых на складе больше или равно заказанным единицам.

CREATE TRIGGER tr_check_qty

ON order_details
FOR insert, update

AS

DECLARE @stock int
DECLARE @neworder int
SELECT @stock = quantity_in_stock FROM products
SELECT @neworder = quantity FROM inserted

IF @neworder > @stock

BEGIN
PRINT 'NO WAY JOSE'
ROLLBACK TRANSACTION
END

Чтобы проверить этот триггер, мы должны использовать этот запрос:

UPDATE order_details
SET quantity = 30
WHERE order_id = '10044'
AND product_id = 7

В запросе выбирается товар, который имеет только 28 amount_in_stock, что должно вызвать срабатывание триггера. Но мой триггер не срабатывает и успешно обновляет таблицу.

У меня было подозрение, что триггерам не нравятся локальные переменные, поэтому я старался не использовать локальные переменные:

(SELECT quantity FROM inserted) > (SELECT quantity_in_stock FROM products)

Но это дало мне ошибку.

Буду признателен за любую помощь!

Ответы [ 3 ]

2 голосов
/ 04 декабря 2010
  1. Вы предполагаете, что будет вставка или обновление только одной строки.

  2. quantity_in_stock FROM products не имеет предиката - возможно, ему нужно проверить уровень запаса вставленного продукта? Если да, какова структура таблицы products? (На данный момент @stock будет присвоено значение из произвольной строки, предполагающей более одной строки в таблице products.

  3. Это не будет работать при изоляции моментального снимка.

Чтобы обойти # 1 и # 2, вам нужно присоединиться к таблице inserted к таблице products, используя productid или что-то еще, и посмотреть, существуют ли какие-либо строки, где inserted.quantity > products.quantity_in_stock

Для некоторых идей о # 3 прочитайте обсуждение здесь

0 голосов
/ 04 декабря 2010

Альтернативное решение - использовать вместо триггера что-то вроде этого:

Create Trigger TR_Check_Qty
ON order_detail
INSTEAD OF insert AS

 insert into order_detail (order_id, productId, quantity)
    select i.order_id, i.productId, i.quantity
    from inserted i inner join product p on i.productId = p.productId
    where i.quantity <= p.quantity_in_stock

Этот триггер ведет себя не так, как другие предложения! Этот триггер будет вставлять выполненные заказы и игнорировать заказы, которые превышают уровень запаса, это может не потребоваться, на самом деле это не требуется [на самом деле это, вероятно, не в большинстве ситуаций; Ваше приложение хотело бы знать, когда заказ не был сохранен в БД !!!]

Примечание это просто вставка, вам нужно создать другой триггер для обновления, поскольку «вставленные» значения должны быть обновлениями, а не вставками.

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

0 голосов
/ 04 декабря 2010

Ваш триггер не за горами, но на самом деле вы могли бы использовать триггер INSTEAD OF

Создание тестовых данных

create table product ( productId int identity(1,1) constraint PK_product_productId primary key clustered, quantity_in_stock int )
create table order_detail (  order_id int
                        ,productId int constraint FK_order_product_productId foreign key references product (productId)
                        ,quantity int not null)
set identity_insert product on
insert into product (productId, quantity_in_stock) values ( 1, 100 ), ( 2, 25 ) , (3, 2);

Это «Работы» (в наименьшем смысле этого слова) Принимая во внимание комментарии Мартина, необходимо определить productid для quantity_in_stock.

CREATE TRIGGER tr_check_qty
ON order_detail
FOR insert, update AS

DECLARE @stock int
DECLARE @neworder int
SELECT @stock = quantity_in_stock 
        From product 
        Where productid = (select productid from inserted)
SELECT @neworder = quantity FROM inserted

IF @neworder > @stock

BEGIN
PRINT 'NO WAY JOSE'
ROLLBACK TRANSACTION
END

Теперь все работает как надо ...

INSERT order_detail (order_id, productId, quantity)
values 
 (10044, 1, 30) -- works as stock is 100
,(10044, 3,  1)

insert order_detail (order_id, productId, quantity)
values 
    (10044, 1, 130) /* fails (CORRECTLY) WITH Msg 3609, Level 16... (transacted ended in the trigger..) */

/* this should work... */
UPDATE order_detail
SET quantity = 30
WHERE order_id = 10044
AND productid = 1

/* this should fail..  */
UPDATE order_detail
SET quantity = 3000 /*< not enough stock. */
WHERE order_id = 10044
AND productid = 1

А если обратиться к первому пункту Мартинса, этот подход лучше:

CREATE TRIGGER tr_check_qty
ON order_detail
FOR insert, update AS

DECLARE @stock int
DECLARE @neworder int

if(exists(select * 
          from inserted i join product p on i.productId = p.productId 
          where i.quantity > p.quantity_in_stock)) 
begin 
PRINT 'NO WAY JOSE'
ROLLBACK TRANSACTION
End
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...