【问题标题】:how to allow 0 in foreign keys constraint in mysql?如何在mysql的外键约束中允许0?
【发布时间】:2012-08-31 09:18:59
【问题描述】:

假设我有一个下表:

UID int (11) not null,  FOREIGN KEY (UID) REFERENCES users(ID),
OID int (11),  FOREIGN KEY (OID) REFERENCES orders(ID),
primary key(UID,OID)

注意主键。

而且,我想允许每个用户 ID (UID) 有一个 NULL 顺序 ID (OID)。

虽然设置主键后它会自动使我的 OID 字段为NOT NULL

作为一种解决方法,我正在考虑存储0,而不是将其标记为不相关的字段。

那么,现在的问题是,除了指定字段的references 之外,是否可以允许外键约束也接受零 (0)?

【问题讨论】:

    标签: mysql null foreign-keys primary-key zero


    【解决方案1】:

    一种选择是使用“代理主键”而不是您当前的 PK,而是在以下复合 (UID,OID) 上放置 UNIQUE 约束 - 只要您愿意拥有代理主键 - 比如一个身份列

    【讨论】:

    • 这是个好主意,但是当我们基于这些字段进行选择时,它不会影响没有主键的性能吗?是否需要手动定义索引,还是可以这样使用?
    • 您需要在 UID、OID 上创建一个索引,但这应该考虑到您的性能问题
    • UNIQUE KEY (uid, oid) 实际上在这两个字段上创建了一个复合索引。
    【解决方案2】:

    UNIQUE KEY在这种情况下可以使用约束:

    CREATE TABLE users (id int not null, primary key (id));
    INSERT INTO users VALUES (1), (2), (3);
    
    CREATE TABLE orders (id int not null, primary key (id));
    INSERT INTO orders VALUES (1), (2), (3);
    
    CREATE TABLE users_orders (uid int NOT NULL, oid int DEFAULT NULL,
                     FOREIGN KEY (uid) REFERENCES users (id),
                     FOREIGN KEY (oid) REFERENCES orders (id),
                     UNIQUE KEY (uid, oid));
    
    INSERT INTO users_orders (uid) VALUES (1);
    

    这里有a demo 可以玩。

    但请注意,您(可能)仍然可以在您的表中插入多个 specific UID - NULL 组合(我在这里假设您使用 InnoDB)。比如这个查询...

    INSERT INTO users_orders o (uid) VALUES (1), (1);
    

    ... 也会成功(因为它不会破坏任何现有的约束)。

    如果这应该被严格禁止,您最好在usersorders 表中同时使用一些虚拟值both - 以使您的交集表中的foreign key 约束可用。

    作为旁注,我承认我对这种情况有点惊讶。交集表通常设计为没有任何可为空的字段:例如,查询中的 LEFT(或 RIGHT)JOIN 应该用于包含没有任何订单的用户。您能否解释一下为什么首先选择了这个决定(使 OID 可以为空)?

    【讨论】:

    • 这个想法是存储帐单信息。每个用户都有一个默认的计费信息,它也为每个订单单独存储。如果您建议以其他方式存储它,我会很乐意跟进...
    • 嗯,是什么让您认为将uid 添加到orders 表不合适? )因为每个订单(我假设)都有一个且只有一个用户分配给它。这样就很容易查询到所有用户及其订单(包括通过LEFT JOIN的方式完全没有订单的用户)。
    • 这是有道理的。我也可以在每个订单中存储账单信息。但我想知道我会在哪里存储默认账单?..
    • 不要存储整个账单信息,这是多余的。而是存储对它的引用。由于user - billing info 显然在1-n 关系中,它应该存储在一个单独的表中,该表也引用users(通过uid)。
    • 啊哈,我想我理解这个想法,所以我可以只使用带有账单参考的订单表,其中我将有一个带有 auto_increment 的主要账单 ID。唯一的问题是,我如何确定哪个计费条目是默认条目?..
    【解决方案3】:

    我认为这在 MySQL 中是不可能的,但解决方法可能是在引用外部表时插入一个值为 0 的虚拟条目。

    【讨论】:

    • 是的,这就是我的第一个想法,但这看起来像一个肮脏的方式,因为它实际上会影响关系并使其成为一个相关领域,而理想情况下它不应该与任何关系这样的领域。
    【解决方案4】:

    尝试使用唯一键。它允许使用 NULL 值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-23
      相关资源
      最近更新 更多