如果 og_id 指的是已取消的奥运会,则触发引发应用程序错误并显示有意义的消息
Trigger to raise raise an application error with a meaningful message if og_id refers to a cancelled Olympic Game
这些是我创建的以下 table:
CREATE TABLE Country
(
country_id NUMBER(3) PRIMARY KEY,
country_name VARCHAR(3) UNIQUE NOT NULL,
CONSTRAINT check_country_id CHECK (country_id > 0)
);
CREATE TABLE OG_Type
(
og_type_id NUMBER(3) PRIMARY KEY,
og_type_title VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE Olympic_Game
(
og_id NUMBER(3) PRIMARY KEY,
og_type_id NUMBER(3) NOT NULL,
og_year NUMBER(4) NOT NULL,
og_website VARCHAR(150),
og_cancel VARCHAR(1) NOT NULL,
country_id NUMBER(3) NOT NULL,
CONSTRAINT check_og_id CHECK (og_id > 0),
CONSTRAINT check_og_year_og_type UNIQUE (og_type_id, og_year),
CONSTRAINT fk_og_type_id FOREIGN KEY(og_type_id) REFERENCES OG_Type(og_type_id),
CONSTRAINT fk_country_id FOREIGN KEY(country_id) REFERENCES Country(country_id)
);
CREATE TABLE Sport
(
sport_id NUMBER(3) PRIMARY KEY,
sport_title VARCHAR(100) UNIQUE NOT NULL,
CONSTRAINT check_sport_id CHECK (sport_id > 0)
);
CREATE TABLE Event
(
event_id NUMBER(6) PRIMARY KEY,
sport_id NUMBER(3) NOT NULL,
og_id NUMBER(3) NOT NULL,
event_title VARCHAR(100) NOT NULL,
event_team VARCHAR(1) NOT NULL,
no_per_team NUMBER(2) NOT NULL,
event_gender VARCHAR(1) NOT NULL,
CONSTRAINT check_event_id CHECK (event_id > 0),
CONSTRAINT check_event_title_sport_id_og_id_event_team_event_gender UNIQUE (event_title, sport_id, og_id, event_team, event_gender),
CONSTRAINT check_event_team CHECK (event_team IN ('Y','N')),
CONSTRAINT check_event_team_no_per_team CHECK ((event_team='N' AND no_per_team=1) OR (event_team='Y' AND no_per_team>1)),
CONSTRAINT check_event_gender CHECK (event_gender IN ('M','F')),
CONSTRAINT fk_sport_id FOREIGN KEY(sport_id) REFERENCES Sport(sport_id),
CONSTRAINT fk_og_id FOREIGN KEY(og_id) REFERENCES Olympic_Game(og_id)
);
创建这 4 个 table 之后,我插入了这 4 个 table 的值:
insert into country(country_id,country_name) values (country_seq.nextval,'FRA');
insert into country(country_id,country_name) values (country_seq.nextval,'GBR');
insert into country(country_id,country_name) values (country_seq.nextval,'GRE');
insert into country(country_id,country_name) values (country_seq.nextval,'USA');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Summer');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Winter');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Special');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Youth');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Senior');
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1896,null,'N',3);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1900,null,'N',1);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1904,null,'N',4);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1908,'op1908.org','N',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,2,1924,null,'N',1);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,3,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,4,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,5,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,2012,'https://www.olympic.org/london-2012','N',2);
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Track and Field');
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Tennis');
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Speed Skating');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,1,'100m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,2,1,'Double','Y',2,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,2,'200m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,2,2,'Single','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,3,'400m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,3,'100m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,4,'1500m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,3,5,'800m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,10,'100m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,10,'100m','N',1,'F');
现在问题是:
创建一个名为 TR_event_on_cancelled_og 的触发器。此触发器在事件 table 中插入或更新行之前触发。如果 og_id 指的是取消的奥林匹克运动会,触发器应引发应用程序错误并显示有意义的消息。
现在这是我想出的解决方案:
CREATE OR REPLACE TRIGGER TR_event_on_cancelled
BEFORE INSERT OR UPDATE
ON Event
FOR EACH ROW
BEGIN
DECLARE
v_og_cancel Olympic_Game.og_cancel%TYPE;
BEGIN
SELECT og_cancel INTO V_og_cancel
FROM Olympic_Game, Event
WHERE Olympic_Game.og_id = Event.og_id
AND Olympic_Game.og_id = :NEW.og_id;
IF (v_og_cancel = 'N')
THEN
RAISE_APPLICATION_ERROR(-20001, 'This Olympic Game is cancelled already');
END IF;
END;
END;
Trigger TR_EVENT_ON_CANCELLED compiled
触发器已成功编译,但问题是当我尝试测试触发器时收到以下错误消息:
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,8,'400m','N',1,'F');
Error report -
SQL Error: ORA-01403: no data found
ORA-06512: at "OG_JC480454.TR_EVENT_ON_CANCELLED", line 5
ORA-04088: error during execution of trigger 'OG_JC480454.TR_EVENT_ON_CANCELLED'
01403. 00000 - "no data found"
*Cause: No data was found from the objects.
*Action: There was no data from the objects which may be due to end of fetch.
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,2,'400m','N',1,'F');
Error report -
SQL Error: ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "OG_JC480454.TR_EVENT_ON_CANCELLED", line 5
ORA-04088: error during execution of trigger 'OG_JC480454.TR_EVENT_ON_CANCELLED'
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
我到底哪里出错了? ...
如果能提供触发方案代码就更好了
我认为你的问题是你的触发代码是从 EVENT 中选择的。它不需要这样做,因为该规则仅适用于您正在插入或更新的当前事件。
所以:
SELECT og_cancel INTO V_og_cancel
FROM Olympic_Game
WHERE Olympic_Game.og_id = :NEW.og_id;
顺带一提,下一个测试看起来不对:
IF (v_og_cancel = 'N')
除非您以一种奇怪的方式使用 Y/N 标志,否则这将测试奥运会是否 未 被取消。当然应该是= 'Y'
?
" I want to get this error message"
我已经使用您的数据和我的触发器版本创建了一个 Oracle LiveSQL。 Find it here (but you will need an OTN account to look at it).
当我尝试插入时...
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender)
values(event_seq.nextval,2,9,'Double','Y',2,'M');
它在
上失败
ORA-20001: This Olympic Game is cancelled already
完全正确,因为 og_id = 9
的游戏有 og_cancel='Y'
。
现在你说你得到 ORA-20977: the game was cancelled
。这是一个用户定义的错误(在 -20999 到 -20000 范围内。所以它是 你的代码库 的一部分,它正在抛出它。
如果您不知道它是哪一部分,您将需要深入研究您的数据字典。我不能为你解决。但这里有一个想法:你在 table 上有不止一个触发器吗?你的作业说要创建一个名为 TR_event_on_cancelled_og
的触发器,但你发布的代码确实是 CREATE OR REPLACE TRIGGER TR_event_on_cancelled
。也许您之前使用其他名称创建了一个触发器,这就是引发 ORA-20977
的原因。
这些是我创建的以下 table:
CREATE TABLE Country
(
country_id NUMBER(3) PRIMARY KEY,
country_name VARCHAR(3) UNIQUE NOT NULL,
CONSTRAINT check_country_id CHECK (country_id > 0)
);
CREATE TABLE OG_Type
(
og_type_id NUMBER(3) PRIMARY KEY,
og_type_title VARCHAR(20) UNIQUE NOT NULL
);
CREATE TABLE Olympic_Game
(
og_id NUMBER(3) PRIMARY KEY,
og_type_id NUMBER(3) NOT NULL,
og_year NUMBER(4) NOT NULL,
og_website VARCHAR(150),
og_cancel VARCHAR(1) NOT NULL,
country_id NUMBER(3) NOT NULL,
CONSTRAINT check_og_id CHECK (og_id > 0),
CONSTRAINT check_og_year_og_type UNIQUE (og_type_id, og_year),
CONSTRAINT fk_og_type_id FOREIGN KEY(og_type_id) REFERENCES OG_Type(og_type_id),
CONSTRAINT fk_country_id FOREIGN KEY(country_id) REFERENCES Country(country_id)
);
CREATE TABLE Sport
(
sport_id NUMBER(3) PRIMARY KEY,
sport_title VARCHAR(100) UNIQUE NOT NULL,
CONSTRAINT check_sport_id CHECK (sport_id > 0)
);
CREATE TABLE Event
(
event_id NUMBER(6) PRIMARY KEY,
sport_id NUMBER(3) NOT NULL,
og_id NUMBER(3) NOT NULL,
event_title VARCHAR(100) NOT NULL,
event_team VARCHAR(1) NOT NULL,
no_per_team NUMBER(2) NOT NULL,
event_gender VARCHAR(1) NOT NULL,
CONSTRAINT check_event_id CHECK (event_id > 0),
CONSTRAINT check_event_title_sport_id_og_id_event_team_event_gender UNIQUE (event_title, sport_id, og_id, event_team, event_gender),
CONSTRAINT check_event_team CHECK (event_team IN ('Y','N')),
CONSTRAINT check_event_team_no_per_team CHECK ((event_team='N' AND no_per_team=1) OR (event_team='Y' AND no_per_team>1)),
CONSTRAINT check_event_gender CHECK (event_gender IN ('M','F')),
CONSTRAINT fk_sport_id FOREIGN KEY(sport_id) REFERENCES Sport(sport_id),
CONSTRAINT fk_og_id FOREIGN KEY(og_id) REFERENCES Olympic_Game(og_id)
);
创建这 4 个 table 之后,我插入了这 4 个 table 的值:
insert into country(country_id,country_name) values (country_seq.nextval,'FRA');
insert into country(country_id,country_name) values (country_seq.nextval,'GBR');
insert into country(country_id,country_name) values (country_seq.nextval,'GRE');
insert into country(country_id,country_name) values (country_seq.nextval,'USA');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Summer');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Winter');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Special');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Youth');
insert into og_type(og_type_id, og_type_title) values(og_type_seq.nextval,'Senior');
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1896,null,'N',3);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1900,null,'N',1);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1904,null,'N',4);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1908,'op1908.org','N',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,2,1924,null,'N',1);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,3,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,4,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,5,1944,null,'Y',2);
insert into olympic_game(og_id,og_type_id,og_year,og_website,og_cancel,country_id) values(og_seq.nextval,1,2012,'https://www.olympic.org/london-2012','N',2);
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Track and Field');
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Tennis');
insert into sport(sport_id,sport_title) values(sport_seq.nextval, 'Speed Skating');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,1,'100m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,2,1,'Double','Y',2,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,2,'200m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,2,2,'Single','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,3,'400m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,3,'100m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,4,'1500m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,3,5,'800m','N',1,'F');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,10,'100m','N',1,'M');
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,10,'100m','N',1,'F');
现在问题是: 创建一个名为 TR_event_on_cancelled_og 的触发器。此触发器在事件 table 中插入或更新行之前触发。如果 og_id 指的是取消的奥林匹克运动会,触发器应引发应用程序错误并显示有意义的消息。
现在这是我想出的解决方案:
CREATE OR REPLACE TRIGGER TR_event_on_cancelled
BEFORE INSERT OR UPDATE
ON Event
FOR EACH ROW
BEGIN
DECLARE
v_og_cancel Olympic_Game.og_cancel%TYPE;
BEGIN
SELECT og_cancel INTO V_og_cancel
FROM Olympic_Game, Event
WHERE Olympic_Game.og_id = Event.og_id
AND Olympic_Game.og_id = :NEW.og_id;
IF (v_og_cancel = 'N')
THEN
RAISE_APPLICATION_ERROR(-20001, 'This Olympic Game is cancelled already');
END IF;
END;
END;
Trigger TR_EVENT_ON_CANCELLED compiled
触发器已成功编译,但问题是当我尝试测试触发器时收到以下错误消息:
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,8,'400m','N',1,'F');
Error report -
SQL Error: ORA-01403: no data found
ORA-06512: at "OG_JC480454.TR_EVENT_ON_CANCELLED", line 5
ORA-04088: error during execution of trigger 'OG_JC480454.TR_EVENT_ON_CANCELLED'
01403. 00000 - "no data found"
*Cause: No data was found from the objects.
*Action: There was no data from the objects which may be due to end of fetch.
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender) values(event_seq.nextval,1,2,'400m','N',1,'F');
Error report -
SQL Error: ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "OG_JC480454.TR_EVENT_ON_CANCELLED", line 5
ORA-04088: error during execution of trigger 'OG_JC480454.TR_EVENT_ON_CANCELLED'
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
我到底哪里出错了? ... 如果能提供触发方案代码就更好了
我认为你的问题是你的触发代码是从 EVENT 中选择的。它不需要这样做,因为该规则仅适用于您正在插入或更新的当前事件。
所以:
SELECT og_cancel INTO V_og_cancel
FROM Olympic_Game
WHERE Olympic_Game.og_id = :NEW.og_id;
顺带一提,下一个测试看起来不对:
IF (v_og_cancel = 'N')
除非您以一种奇怪的方式使用 Y/N 标志,否则这将测试奥运会是否 未 被取消。当然应该是= 'Y'
?
" I want to get this error message"
我已经使用您的数据和我的触发器版本创建了一个 Oracle LiveSQL。 Find it here (but you will need an OTN account to look at it).
当我尝试插入时...
insert into event(event_id,sport_id,og_id,event_title,event_team,no_per_team,event_gender)
values(event_seq.nextval,2,9,'Double','Y',2,'M');
它在
上失败ORA-20001: This Olympic Game is cancelled already
完全正确,因为 og_id = 9
的游戏有 og_cancel='Y'
。
现在你说你得到 ORA-20977: the game was cancelled
。这是一个用户定义的错误(在 -20999 到 -20000 范围内。所以它是 你的代码库 的一部分,它正在抛出它。
如果您不知道它是哪一部分,您将需要深入研究您的数据字典。我不能为你解决。但这里有一个想法:你在 table 上有不止一个触发器吗?你的作业说要创建一个名为 TR_event_on_cancelled_og
的触发器,但你发布的代码确实是 CREATE OR REPLACE TRIGGER TR_event_on_cancelled
。也许您之前使用其他名称创建了一个触发器,这就是引发 ORA-20977
的原因。