모든 제품은 고객 테이블의 기본 키에 해당하는 외래 키 고객 ID을 통해 고객을 참조합니다 (이름도 같습니다). 고객이 그 의상을 참조하는 모든 제품을 삭제
은삭제 : Product.CustomerID는 DELETE CASCADE ON 속성 있습니다.
이제 제품을 제거 할 때 기본 고객이 적어도 제품을 가져야한다고 가정 해 봅시다. 고객이 비용을내는 최종 제품 인 경우 costumer도 함께 제거해야합니다.
CREATE OR REPLACE TRIGGER RemoveCustomer
AFTER DELETE ON Product
BEGIN
DELETE FROM Customer
WHERE CustomerID IN (
SELECT c.CustomerID
FROM Customer c
LEFT OUTER JOIN Product p
ON p.CustomerID = c.CustomerID
GROUP BY c.CustomerID HAVING COUNT(p.CustomerID) = 0
);
END;
/
이 솔루션은 자연스러운 것 같지만 오라클은 싫어합니다. 은 모든 나는 오류가 제품의 삭제 : DELETE 프로그램을 일으킬하지 않을 경우에도
ORA-00036: maximum number of recursive SQL levels (50) exceeded
이 제거 할 수 있습니다.
놀랍게도,이 구문은 잘 작동합니다 :
CREATE OR REPLACE TRIGGER RemoveCustomer
AFTER DELETE ON Product
BEGIN
FOR my_row IN (
SELECT c.CustomerID
FROM Customer c
LEFT OUTER JOIN Product p
ON p.CustomerID = c.CustomerID
GROUP BY c.CustomerID HAVING COUNT(p.CustomerID) = 0
)
LOOP
DELETE FROM Customer WHERE CustomerID = my_row.CustomerID;
END LOOP;
END;
/
누군가가 설명 할 수 왜 이런 일이?
편집 : 여기
동작하는 예제가있다 :
CREATE TABLE Customer (
CustomerID INTEGER PRIMARY KEY
);
CREATE TABLE Product (
ProductID INTEGER PRIMARY KEY,
CustomerID INTEGER,
CONSTRAINT fk_Customer FOREIGN KEY (CustomerID)
REFERENCES Customer
ON DELETE CASCADE
);
INSERT INTo Customer (CustomerID) VALUES (0);
INSERT INTo Customer (CustomerID) VALUES (1);
INSERT INTo Customer (CustomerID) VALUES (2);
INSERT INTo Customer (CustomerID) VALUES (3);
INSERT INTo Customer (CustomerID) VALUES (4);
INSERT INTo Customer (CustomerID) VALUES (5);
INSERT INTo Customer (CustomerID) VALUES (6);
INSERT INTO Product (ProductID, CustomerID) VALUES (0, 0);
INSERT INTO Product (ProductID, CustomerID) VALUES (1, 0);
INSERT INTO Product (ProductID, CustomerID) VALUES (2, 1);
INSERT INTO Product (ProductID, CustomerID) VALUES (3, 2);
INSERT INTO Product (ProductID, CustomerID) VALUES (4, 3);
INSERT INTO Product (ProductID, CustomerID) VALUES (5, 3);
INSERT INTO Product (ProductID, CustomerID) VALUES (6, 3);
INSERT INTO Product (ProductID, CustomerID) VALUES (7, 4);
INSERT INTO Product (ProductID, CustomerID) VALUES (8, 5);
INSERT INTO Product (ProductID, CustomerID) VALUES (9, 5);
INSERT INTO Product (ProductID, CustomerID) VALUES (10, 6);
CREATE OR REPLACE TRIGGER RemoveCustomer
AFTER DELETE ON Product
BEGIN
DELETE FROM Customer
WHERE CustomerID IN (
SELECT c.CustomerID
FROM Customer c
LEFT OUTER JOIN Product p
ON p.CustomerID = c.CustomerID
GROUP BY c.CustomerID HAVING COUNT(p.CustomerID) = 0
);
END;
/
/* This request will produce the error */
DELETE FROM Product WHERE CustomerID = 3;
트리거의 두 번째 버전에서는 루프가 실행될 때에도 재귀가 발생하지 않습니다. 그게 정상인가요? – TTK
@TTK - 루프가 실행되지만 두 번째로 일치하는 행이 없으므로 루프 내부의 삭제가 다시 실행되지 않습니다. –
@Alex Poole - 맞다면 한 고객 만 제거해야한다고 가정 해보십시오. 처음으로 루프가 실행될 때 고객에게 DELETE가 수행됩니다. 계단식 삭제 문 때문에 DELETE가 트리거를 다시 실행해야합니다. 이 시점에서 우리는 하나의 재귀 레벨을 가지지 만 이번에는 유일한 고객이 이미 제거되었으므로 트리거가 루프 내부에 들어 가지 않습니다. 내가 맞습니까? – TTK