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_racegender 值,请参阅 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中查看结果。