如何检查 MySQL 中约束中外键引用的记录的值

How to check a value of a record referenced by foreign key in a constraint in MySQL

我目前在 arch 上使用 MariaDB,在 "production".

中,debian buster 代表 mysql

我正在尝试创建以下架构:

create or replace schema `test`
use `test`;

create table `tags` 
(
    `tag_id`           int           not null auto_increment,
    `tag_display_name` varchar(200)  not null unique,
    `tag_meta`         boolean       not null,

    primary key (`tag_id`)
);

create table `tag_aliases` 
(
    `alias_id` int not null,
    `tag_id`   int not null,

    primary key (`alias_id`, `tag_id`),

    foreign key (`alias_id`) references `tags`   (`tag_id`),
    foreign key (`tag_id`)   references `tags`   (`tag_id`),
    
-- This constraint I am trying to make that doesn't work (some kind of syntax error 1064)

    CONSTRAINT `cnstrnt` check (select `tag_meta` from `tags` where `tag_id`=`alias_id` limit 1)
);

目标是与 tags 建立 m:n 关系,其中 tag_meta 列为真,并且与任何其他 tags(元或非元)。

但是我找不到任何相关资源,因为每次我尝试 google 我都看到外键约束无处不在。

我也试过做一个函数,但是它说这个函数不能用在检查子句中。 (错误 1901)

-- The function

DELIMITER //

create or replace function tagIsMeta(id int) returns boolean
begin
    declare res boolean default null;
    select `tag_meta` into res from `tags` where `tag_id` = id limit 1;
    return res;
end //

DELIMITER ;

-- The constraint

create table .... 
(
    ...
    ...

    CONSTRAINT `cnstrnt` check (tagIsMeta(`alias_id`))

);

这是一个解决方案:

create table `tags` (
    `tag_id`           int           not null auto_increment,
    `tag_display_name` varchar(200)  not null unique,
    `tag_meta`         boolean       not null,

    primary key (`tag_id`),
    key (`tag_id`, `tag_meta`)
);

create table `tag_aliases` (
    `alias_id` int not null,
    `tag_id`   int not null,
    `tag_meta` boolean not null default true,

    primary key (`alias_id`),

    foreign key (`alias_id`) references `tags`   (`tag_id`),
    foreign key (`tag_id`, `tag_meta`)   references `tags`   (`tag_id`, `tag_meta`),
    check (`tag_meta` = true)
);

这使用了 InnoDB 的非标准功能,它允许外键引用父项的非唯一索引 table。通常这是要避免的事情,因为子行引用 multiple 父行意味着什么?但在这种情况下,由于 tags.tag_id 本身是唯一的,所以不会发生这种情况。

其工作方式是 tag_aliases 中的列对必须与 tags 中的对应列匹配。但是我们在 tag_aliases.tag_meta 上设置了一个检查约束,它必须是 true,因此只有当它引用 tags 中具有 tag_meta = true.