You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何禁止SQLite中consumable_items与weapons同时引用同一条items记录?

在SQLite中实现物品表的互斥引用约束

我创建了三张表,结构如下:

CREATE TABLE "items" (
    "key"   TEXT NOT NULL UNIQUE,
    "name_key"  TEXT,
    "base_price"    INTEGER,
    "description_key"   TEXT,
    PRIMARY KEY("key")
)
CREATE TABLE "consumable_items" (
    "key"   TEXT NOT NULL UNIQUE,
    "item_key"  TEXT NOT NULL,
    "scope" TEXT NOT NULL,
    "only_menu" BOOLEAN NOT NULL,
    PRIMARY KEY("key"),
    FOREIGN KEY("item_key") REFERENCES "items"("key")
)
CREATE TABLE "weapons" (
    "key"   TEXT NOT NULL UNIQUE,
    "item_key"  TEXT NOT NULL,
    "name_key"  TEXT,
    "type"  TEXT,
    FOREIGN KEY("item_key") REFERENCES "items"("key"),
    FOREIGN KEY("type") REFERENCES "weapon_types"("key"),
    PRIMARY KEY("key")
)

consumable_items和weapons通过外键item_key引用items表,实现物品公共属性的复用,现在需要实现约束:一条items记录只能被其中一张表引用,不能同时出现在consumable_items和weapons中。

比如插入这条items记录后:

INSERT INTO "main"."items" ("key", "name_key", "base_price", "description_key") VALUES ('excalibur', 'excalibur', '800000', 'excalibur');

该记录只能被consumable_items或weapons中的一个引用,不能同时存在两条关联记录。


实现方案:使用触发器(TRIGGER)

SQLite本身没有原生的互斥外键约束,但可以通过触发器实现这一逻辑,需要创建4个触发器覆盖INSERT和UPDATE操作:

  1. 插入consumable_items时检查冲突
CREATE TRIGGER prevent_consumable_if_weapon_exists
BEFORE INSERT ON consumable_items
FOR EACH ROW
BEGIN
    SELECT RAISE(ABORT, '该物品已被武器表引用,无法添加到消耗品表')
    WHERE EXISTS (
        SELECT 1 FROM weapons WHERE item_key = NEW.item_key
    );
END;
  1. 更新consumable_items的item_key时检查冲突
CREATE TRIGGER prevent_consumable_update_if_weapon_exists
BEFORE UPDATE OF item_key ON consumable_items
FOR EACH ROW
BEGIN
    SELECT RAISE(ABORT, '该物品已被武器表引用,无法更新消耗品表关联')
    WHERE EXISTS (
        SELECT 1 FROM weapons WHERE item_key = NEW.item_key
    );
END;
  1. 插入weapons时检查冲突
CREATE TRIGGER prevent_weapon_if_consumable_exists
BEFORE INSERT ON weapons
FOR EACH ROW
BEGIN
    SELECT RAISE(ABORT, '该物品已被消耗品表引用,无法添加到武器表')
    WHERE EXISTS (
        SELECT 1 FROM consumable_items WHERE item_key = NEW.item_key
    );
END;
  1. 更新weapons的item_key时检查冲突
CREATE TRIGGER prevent_weapon_update_if_consumable_exists
BEFORE UPDATE OF item_key ON weapons
FOR EACH ROW
BEGIN
    SELECT RAISE(ABORT, '该物品已被消耗品表引用,无法更新武器表关联')
    WHERE EXISTS (
        SELECT 1 FROM consumable_items WHERE item_key = NEW.item_key
    );
END;

测试验证

  1. 先插入基础物品:
INSERT INTO "items" ("key", "name_key", "base_price", "description_key") VALUES ('excalibur', 'excalibur', '800000', 'excalibur');
  1. 插入到weapons表:
INSERT INTO "weapons" ("key", "item_key", "name_key", "type") VALUES ('wp_excalibur', 'excalibur', 'excalibur', 'sword');

执行成功。

  1. 尝试插入到consumable_items表:
INSERT INTO "consumable_items" ("key", "item_key", "scope", "only_menu") VALUES ('cm_excalibur', 'excalibur', 'single', 1);

此时触发器触发,抛出错误:该物品已被武器表引用,无法添加到消耗品表,插入操作被终止。


注意事项

  • 触发器会在操作执行前触发,确保数据一致性;
  • 自定义错误信息可根据需求修改;
  • 删除关联表中的记录后,对应的item_key会自动解除限制,允许被另一张表引用。

内容的提问来源于stack exchange,提问作者user3001150

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 08:35:26