postgresql触发器将倒数第三个字符与属性进行比较
postgresql trigger to compare the third to last character with an attribute
我最近开始研究 PostgreSQL,但在创建触发器时遇到了问题。
在特定情况下,我应该检查男性运动员不能参加女性比赛,反之亦然;在 match_code 属性中插入 'M' 或 'F' 作为倒数第三个字符以标识该种族是男性还是女性(例如:'Q100x4M06');只有一个字符 'M' 或 'F' 存储在性别属性中。
因此,我需要了解如何比较它们并在它们未正确输入参与时激活触发器 table。
这是我的假设,但我知道这是错误的,这只是一个想法,有人可以帮助我吗?
CREATE FUNCTION check()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $BODY$
DECLARE
x VARCHAR;
y VARCHAR;
BEGIN
SELECT match_code INTO x FROM race;
SELECT gender INTO y FROM athlete;
IF $x LIKE '&$y__' == athlete.gender
THEN
RETURN new;
ELSE
RAISE EXCEPTION $$It is not possible to add an athlete of a gender that is not compatible with the competition$$;
RETURN NULL;
END IF;
END;
$BODY$
CREAT TRIGGER triggerCheck
BEFORE INSERT OR UPDATE ON participation
FOR EACH ROW
EXECUTE PROCEDURE check();
下面是 table 的定义:
CREATE TABLE race (
ID_g SERIAL NOT NULL,
code_race VARCHAR (20) PRIMARY KEY,
r_date DATE,
discipline VARCHAR (20) NOT NULL
);
CREATE TABLE athlete (
ID_a SERIAL NOT NULL,
code_athlete INT CHECK (codice_atleta >= 0 AND codice_atleta <= 15000) PRIMARY KEY,
name VARCHAR (30),
surname VARCHAR (30) NOT NULL,
nation VARCHAR (3) NOT NULL,
gender CHAR CHECK (gender = 'M' OR gender = 'F'),
b_date DATE,
sponsor VARCHAR (20)
);
CREATE TABLE participation (
ID_p SERIAL NOT NULL,
codR VARCHAR (20) REFERENCES race (code_race) ON DELETE CASCADE ON UPDATE CASCADE,
codA INT REFERENCES athlete (code_athlete) ON DELETE CASCADE ON UPDATE CASCADE,
arrival_order INT CHECK (arrival_order > 0),
r_time TIME DEFAULT '00:00:00.00',
PRIMARY KEY (codG, codA)
);
根据 table 的定义,您的触发函数应该类似于:
CREATE FUNCTION check()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $BODY$
BEGIN
IF EXISTS ( SELECT 1
FROM race AS r
INNER JOIN athlete AS a
ON r.code_race ~ (a.gender || '..$')
WHERE r.code_race = NEW.codR
AND a.code_athlete = NEW.codA
)
THEN
RETURN NEW ;
ELSE
RAISE EXCEPTION 'It is not possible to add an athlete of a gender that is not compatible with the competition';
RETURN NULL;
END IF;
END;
$BODY$
在触发器调用的函数中,您可以(必须)使用变量 NEW
(resp. OLD
)以便引用新行(resp. 旧行) 在目标 table(在您的情况下为 "participation"
)中插入或更新(resp. 仅更新)请参阅 manual.
建议的函数不需要声明任何变量,因为可以通过建议的 sql
查询直接执行测试。
建议sql查询:
- 首先搜索 table
"race"
中 code_race
等于 participation.codR = NEW.codR
[=55 的 inserted/updated 值的行=]
- 然后搜索 table
"athlete"
中 code_athlete
等于的行
participation.codA 的 inserted/updated 值 = NEW.codA
- 最后比较 tables
"race"
和
"athlete"
使用 正则表达式 将 code_race
与
gender
值,请参阅 manual
顺便说一句,
(a) 我没有在 table 定义中看到类型为 serial
的列 ID 的附加值,特别是因为它们未在任何主键或外键中使用.
(b) 为 code_race
属性定义的重要编纂(例如:定义性别的倒数第三个字符,定义比赛级别的另一个字符,...)是一种相当老式的做法这是 30 年前使用的,当时计算机科学的能力和性能有限。在更新的方法中,我建议您在 table "race"
的专用列中管理这些有意义的信息,然后,如果您真的需要重要的复合 code_race
, 将其实现为 generated column :
CREATE TABLE race
( ID_g SERIAL NOT NULL PRIMARY KEY
, gender_race CHAR(1) NOT NULL CHECK (gender_race IN ('M', 'F'))
, competition_level VARCHAR(12) NOT NULL CHECK (competition_level IN ('Q-Qualifiers', 'H-Heats', 'S-Semifinals', 'F=Finals'))
, code_race VARCHAR (20) GENERATED ALWAYS AS (ID_g :: text || '-' || discipline || '-' || gender_race || '-' || left(competition_level, 1)) STORED
, r_date DATE NOT NULL
, discipline VARCHAR (20) NOT NULL
);
在db<>fiddle中查看结果。
我最近开始研究 PostgreSQL,但在创建触发器时遇到了问题。 在特定情况下,我应该检查男性运动员不能参加女性比赛,反之亦然;在 match_code 属性中插入 'M' 或 'F' 作为倒数第三个字符以标识该种族是男性还是女性(例如:'Q100x4M06');只有一个字符 'M' 或 'F' 存储在性别属性中。 因此,我需要了解如何比较它们并在它们未正确输入参与时激活触发器 table。 这是我的假设,但我知道这是错误的,这只是一个想法,有人可以帮助我吗?
CREATE FUNCTION check()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $BODY$
DECLARE
x VARCHAR;
y VARCHAR;
BEGIN
SELECT match_code INTO x FROM race;
SELECT gender INTO y FROM athlete;
IF $x LIKE '&$y__' == athlete.gender
THEN
RETURN new;
ELSE
RAISE EXCEPTION $$It is not possible to add an athlete of a gender that is not compatible with the competition$$;
RETURN NULL;
END IF;
END;
$BODY$
CREAT TRIGGER triggerCheck
BEFORE INSERT OR UPDATE ON participation
FOR EACH ROW
EXECUTE PROCEDURE check();
下面是 table 的定义:
CREATE TABLE race (
ID_g SERIAL NOT NULL,
code_race VARCHAR (20) PRIMARY KEY,
r_date DATE,
discipline VARCHAR (20) NOT NULL
);
CREATE TABLE athlete (
ID_a SERIAL NOT NULL,
code_athlete INT CHECK (codice_atleta >= 0 AND codice_atleta <= 15000) PRIMARY KEY,
name VARCHAR (30),
surname VARCHAR (30) NOT NULL,
nation VARCHAR (3) NOT NULL,
gender CHAR CHECK (gender = 'M' OR gender = 'F'),
b_date DATE,
sponsor VARCHAR (20)
);
CREATE TABLE participation (
ID_p SERIAL NOT NULL,
codR VARCHAR (20) REFERENCES race (code_race) ON DELETE CASCADE ON UPDATE CASCADE,
codA INT REFERENCES athlete (code_athlete) ON DELETE CASCADE ON UPDATE CASCADE,
arrival_order INT CHECK (arrival_order > 0),
r_time TIME DEFAULT '00:00:00.00',
PRIMARY KEY (codG, codA)
);
根据 table 的定义,您的触发函数应该类似于:
CREATE FUNCTION check()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $BODY$
BEGIN
IF EXISTS ( SELECT 1
FROM race AS r
INNER JOIN athlete AS a
ON r.code_race ~ (a.gender || '..$')
WHERE r.code_race = NEW.codR
AND a.code_athlete = NEW.codA
)
THEN
RETURN NEW ;
ELSE
RAISE EXCEPTION 'It is not possible to add an athlete of a gender that is not compatible with the competition';
RETURN NULL;
END IF;
END;
$BODY$
在触发器调用的函数中,您可以(必须)使用变量 NEW
(resp. OLD
)以便引用新行(resp. 旧行) 在目标 table(在您的情况下为 "participation"
)中插入或更新(resp. 仅更新)请参阅 manual.
建议的函数不需要声明任何变量,因为可以通过建议的 sql
查询直接执行测试。
建议sql查询:
- 首先搜索 table
"race"
中code_race
等于 participation.codR =NEW.codR
[=55 的 inserted/updated 值的行=] - 然后搜索 table
"athlete"
中code_athlete
等于的行 participation.codA 的 inserted/updated 值 =NEW.codA
- 最后比较 tables
"race"
和"athlete"
使用 正则表达式 将code_race
与gender
值,请参阅 manual
顺便说一句,
(a) 我没有在 table 定义中看到类型为 serial
的列 ID 的附加值,特别是因为它们未在任何主键或外键中使用.
(b) 为 code_race
属性定义的重要编纂(例如:定义性别的倒数第三个字符,定义比赛级别的另一个字符,...)是一种相当老式的做法这是 30 年前使用的,当时计算机科学的能力和性能有限。在更新的方法中,我建议您在 table "race"
的专用列中管理这些有意义的信息,然后,如果您真的需要重要的复合 code_race
, 将其实现为 generated column :
CREATE TABLE race
( ID_g SERIAL NOT NULL PRIMARY KEY
, gender_race CHAR(1) NOT NULL CHECK (gender_race IN ('M', 'F'))
, competition_level VARCHAR(12) NOT NULL CHECK (competition_level IN ('Q-Qualifiers', 'H-Heats', 'S-Semifinals', 'F=Finals'))
, code_race VARCHAR (20) GENERATED ALWAYS AS (ID_g :: text || '-' || discipline || '-' || gender_race || '-' || left(competition_level, 1)) STORED
, r_date DATE NOT NULL
, discipline VARCHAR (20) NOT NULL
);
在db<>fiddle中查看结果。