所以我有這個問題。
如果客戶在插入每一行之前已經使用觸發器至少有一個未付費的購物車(以防插入多個新購物車),我想阻止添加新購物車。
表的模型截圖
我設法在修改表的paidTime列中包含NULL的T-SQL計數記錄中很容易地解決了這個問題。
CREATE TRIGGER one_unpaid_cart_per_client ON Cart
FOR INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE newCart_cursor CURSOR FOR SELECT IdClient, IdCart, isPaid FROM inserted;
DECLARE @IdClient int;
DECLARE @IdCart int;
DECLARE @isPaid datetime;
OPEN newCart_cursor;
FETCH NEXT FROM newCart_cursor INTO @IdClient, @IdCart, @isPaid;
WHILE @@FETCH_STATUS = 0
BEGIN
IF @isPaid is null
BEGIN
if 1 < (SELECT COUNT(1) FROM Cart WHERE IdClient = @IdClient AND isPaid is Null)
BEGIN
PRINT 'Unpaid cart already exists for client id: ' Cast(@IdClient as Varchar);
DELETE FROM Cart WHERE IdCart = @IdCart;
Raiserror('New cart has not been added', 1, 1);
END;
END;
FETCH NEXT FROM newCart_cursor INTO @IdClient, @IdCart, @isPaid;
END;
CLOSE newCart_cursor;
DEALLOCATE newCart_cursor;
SET NOCOUNT OFF;
END;
在 PL/SQL 中,盡管據我所知您無法查詢更改表,因此我無法檢查有多少未付款的購物車。
我可以做些什么來使用 PL/SQL 中的觸發器來完成這項作業?
謝謝你的幫助!
uj5u.com熱心網友回復:
正如 OldProgrammer 建議的那樣,您可以使用 Oracle 中的復合觸發器來完成您正在考慮做的事情。在這種方法中,您將有一個 BEFORE INSERT...FOR EACH ROW 觸發器來記錄記憶體中的客戶端 ID(PL/SQL 陣列或其他東西),然后是一個 BEFORE INSERT 陳述句級觸發器來檢查多個未付款購物車中的任何一個記錄的客戶端 ID(如果找到則拋出例外)。
然而,使用觸發器來強制執行完整性是很難做到的。這主要是因為在提交事務之前觸發觸發器。因此,例如:
- 會話 A,時間 1:為客戶 100 插入未付款的購物車(觸發檢查通過)
- 會話 B,時間 2:為客戶 100 插入未付費購物車(觸發檢查也通過,因為會話 A 尚未提交!)
- 會話 A:時間 3:提交
- 會話 B:時間 4:提交
...并且您的觸發器未能實作其目的。
一個更好的方法是創建一個唯一約束,依賴于唯一約束不拒絕NULL在約束的所有列中具有值的行的事實。
像下面的例子應該避免上述競爭條件并在 100% 的時間內作業。
--drop table cart;
CREATE TABLE cart
( cart_id NUMBER NOT NULL,
client_id NUMBER NOT NULL,
payment_time TIMESTAMP,
unpaid_client_id NUMBER
INVISIBLE GENERATED ALWAYS AS (DECODE(payment_time,NULL,client_id, NULL)) VIRTUAL,
is_unpaid VARCHAR2(1)
INVISIBLE GENERATED ALWAYS AS (DECODE(payment_time,NULL,'Y',NULL)) VIRTUAL,
CONSTRAINT cart_pk PRIMARY KEY ( cart_id ),
CONSTRAINT max_one_unpaid UNIQUE ( unpaid_client_id, is_unpaid)
);
delete from cart;
-- This should be allowed: the first unpaid cart for a client
insert into cart ( cart_id, client_id, payment_time ) values ( 100, 1, null );
--1 row(s) inserted.
-- This should be rejected: a second unpaid cart for a client
insert into cart ( cart_id, client_id, payment_time ) values ( 101, 1, null );
--ORA-00001: unique constraint (SQL_PRUOVRWCMSHZECACDIWPGIBED.MAX_ONE_UNPAID) violated ORA-06512: at "SYS.DBMS_SQL", line 1721
-- This should be allowed, a paid cart for a client having an unpaid one
insert into cart ( cart_id, client_id, payment_time ) values ( 102, 1, SYSTIMESTAMP );
--1 row(s) inserted.
-- This should be allowed, a second paid cart for a client having an unpaid one
insert into cart ( cart_id, client_id, payment_time ) values ( 103, 1, SYSTIMESTAMP );
--1 row(s) inserted.
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/399915.html
上一篇:復制時如何在查詢結果中包含邊框?
下一篇:從表oracle中洗掉所有約束
