在 SQL 中,您可以在一组属性上添加外键约束,以便所有属性都必须位于引用表的同一行吗?

问题描述 投票:0回答:1

我有以下场景:

有开发者工作室,每个工作室都制作了游戏,并且每个游戏都有一组地图。这些地图并不是游戏所独有的,因为有些地图是由不同的开发工作室在不同的游戏中重新制作的。不过,游戏对于工作室来说是独一无二的,因为在我的场景中,没有工作室曾经从另一个工作室重新制作过现有的游戏。

每个地图都有一组求解器。同一游戏的两个不同地图可以具有相同名称的解算器,不同游戏(例如重制版)的相同地图可以具有相同名称的解算器。

这是我现在的架构:

CREATE TABLE IF NOT EXISTS Studio (
    name TEXT NOT NULL,
    position INT UNIQUE NOT NULL,
    localizedDescription TEXT NOT NULL,
    assetsImageName TEXT NOT NULL,
    PRIMARY KEY (name)
);

CREATE TABLE IF NOT EXISTS Game (
    name TEXT NOT NULL,
    position INT NOT NULL,
    localizedDescription TEXT NOT NULL,
    assetsImageName TEXT NOT NULL,
    studio TEXT NOT NULL,
    PRIMARY KEY (name),
    FOREIGN KEY (studio) REFERENCES Studio(name)
);

CREATE TABLE IF NOT EXISTS Map (
    name TEXT NOT NULL,
    position INT NOT NULL,
    localizedDescription TEXT NOT NULL,
    assetsImageName TEXT NOT NULL,
    game TEXT NOT NULL,
    PRIMARY KEY (name, game),
    FOREIGN KEY (game) REFERENCES Game(name)
);

CREATE TABLE IF NOT EXISTS Solver (
    name TEXT NOT NULL,
    position INT NOT NULL,
    localizedDescription TEXT NOT NULL,
    assetsImageName TEXT NOT NULL,
    map TEXT NOT NULL,
    game TEXT NOT NULL,
    PRIMARY KEY (name, map, game),
    FOREIGN KEY (map) REFERENCES Map(name),
    FOREIGN KEY (game) REFERENCES Game(name)
);

使用给定的模式,假设您要在表 Solver 上插入新行:DBMS 将检查是否存在具有主键 NEW.map

map
,以及是否存在具有主键
NEW.game
的游戏。

这很有用,但不完全是我需要的:我希望在插入新行的表求解器之前,DBMS 检查 Map 中是否存在具有

name = NEW.map AND game = NEW.game
的一行。

我知道我可以为此创建一个触发器,但我想知道是否存在一种语法可以让我实现相同的结果,因此我可以利用

CASCADE DELETE
UPDATE
而无需为其创建自定义触发器。

sql sqlite relational-database
1个回答
0
投票

在关系数据库中,外键约束通常用于强制表之间的引用完整性。但是,在您的情况下,您希望在允许插入求解器表之前确保更具体的条件。

不幸的是,标准 SQL 不提供直接语法来在插入时强制执行此类条件。正如您提到的,处理此问题的典型方法是使用触发器。

如果您想坚持使用标准 SQL 并避免触发器,一种选择可能是重新考虑您的架构。例如,您可以有一个单独的表来表示地图和游戏之间的关系,然后使用外键从 Map 和 Solver 表中引用该表。

这是一个例子:

CREATE TABLE IF NOT EXISTS MapGameRelationship (
    map_name TEXT NOT NULL,
    game_name TEXT NOT NULL,
    PRIMARY KEY (map_name, game_name),
    FOREIGN KEY (map_name) REFERENCES Map(name),
    FOREIGN KEY (game_name) REFERENCES Game(name)
);

CREATE TABLE IF NOT EXISTS Solver (
    name TEXT NOT NULL,
    position INT NOT NULL,
    localizedDescription TEXT NOT NULL,
    assetsImageName TEXT NOT NULL,
    map TEXT NOT NULL,
    game TEXT NOT NULL,
    PRIMARY KEY (name, map, game),
    FOREIGN KEY (map, game) REFERENCES MapGameRelationship(map_name, game_name)
);

现在,在插入 Solver 表之前,您首先需要确保 MapGameRelationship 表中存在相应的条目。这样,您就可以利用外键约束来实现引用完整性。

值得注意的是,虽然这种方法遵循标准 SQL 并避免触发您想要的特定检查,但它确实引入了一个额外的表。触发器和这种模式重新设计之间的选择取决于您的具体用例和偏好。

© www.soinside.com 2019 - 2024. All rights reserved.