SQL: 在子类型插入之前创建触发器
SQL: Creating a trigger before subtype insert
所以我处理的情况可以描述为:
基本上,我有两种类型的汽车和超级跑车
CREATE OR REPLACE TYPE CAR_T AS OBJECT (
id VARCHAR (10),
fuel_type VARCHAR (10)
) NOT FINAL;
CREATE OR REPLACE TYPE SUPERCAR_T UNDER CAR_T (
number_cylinders number(10)
);
将超级跑车插入汽车时:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 12));
我想在插入 CAR 之前检查气缸数是否大于 6 table WITHOUT CREATING A TABLE FOR SUPERCARS:
CREATE OR REPLACE TRIGGER INSERT_SUPERCAR
BEFORE INSERT ON CAR
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
IF :NEW.number_cylinders < 6 THEN
RAISE_APPLICATION_ERROR(-20001,'Not a supercar');
END;
我总是遇到以下错误:
bad bind variable 'NEW.number_cylinders'
看来我无法直接访问子类型的属性。我的问题是如何修复这样的错误,有没有更好的方法来使用检查约束而不为超级跑车创建新的 table?
您可以使用 :NEW.OBJECT_VALUE
pseudo-column and the TREAT
function 将对象转换为 SUPERCAR_T
类型,然后检查 number_cylinders
属性:
CREATE OR REPLACE TRIGGER INSERT_SUPERCAR
BEFORE INSERT ON CAR
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
IF :NEW.OBJECT_VALUE IS OF (SUPERCAR_T)
AND TREAT(:NEW.OBJECT_VALUE AS SUPERCAR_T).number_cylinders < 6
THEN
RAISE_APPLICATION_ERROR(-20001,'Not a supercar');
END IF;
END;
/
然后:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 12));
有效但是:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 4));
引发异常:
ORA-20001: Not a supercar
您还可以使用 CHECK
约束:
ALTER TABLE car ADD CONSTRAINT car__supercar_cylinders__chk CHECK (
OBJECT_VALUE IS NOT OF (SUPERCAR_T)
OR TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders >= 6
);
或
ALTER TABLE car ADD CONSTRAINT car__supercar_cylinders2__chk CHECK (
TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders IS NULL
OR TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders >= 6
);
db<>fiddle here
所以我处理的情况可以描述为:
基本上,我有两种类型的汽车和超级跑车
CREATE OR REPLACE TYPE CAR_T AS OBJECT (
id VARCHAR (10),
fuel_type VARCHAR (10)
) NOT FINAL;
CREATE OR REPLACE TYPE SUPERCAR_T UNDER CAR_T (
number_cylinders number(10)
);
将超级跑车插入汽车时:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 12));
我想在插入 CAR 之前检查气缸数是否大于 6 table WITHOUT CREATING A TABLE FOR SUPERCARS:
CREATE OR REPLACE TRIGGER INSERT_SUPERCAR
BEFORE INSERT ON CAR
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
IF :NEW.number_cylinders < 6 THEN
RAISE_APPLICATION_ERROR(-20001,'Not a supercar');
END;
我总是遇到以下错误:
bad bind variable 'NEW.number_cylinders'
看来我无法直接访问子类型的属性。我的问题是如何修复这样的错误,有没有更好的方法来使用检查约束而不为超级跑车创建新的 table?
您可以使用 :NEW.OBJECT_VALUE
pseudo-column and the TREAT
function 将对象转换为 SUPERCAR_T
类型,然后检查 number_cylinders
属性:
CREATE OR REPLACE TRIGGER INSERT_SUPERCAR
BEFORE INSERT ON CAR
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
IF :NEW.OBJECT_VALUE IS OF (SUPERCAR_T)
AND TREAT(:NEW.OBJECT_VALUE AS SUPERCAR_T).number_cylinders < 6
THEN
RAISE_APPLICATION_ERROR(-20001,'Not a supercar');
END IF;
END;
/
然后:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 12));
有效但是:
INSERT INTO CAR VALUES(SUPERCAR_T(99, 'petrol', 4));
引发异常:
ORA-20001: Not a supercar
您还可以使用 CHECK
约束:
ALTER TABLE car ADD CONSTRAINT car__supercar_cylinders__chk CHECK (
OBJECT_VALUE IS NOT OF (SUPERCAR_T)
OR TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders >= 6
);
或
ALTER TABLE car ADD CONSTRAINT car__supercar_cylinders2__chk CHECK (
TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders IS NULL
OR TREAT(OBJECT_VALUE AS SUPERCAR_T).number_cylinders >= 6
);
db<>fiddle here