【问题标题】:How to create one-to-zero-or-one relationship programmatically - MySQL?如何以编程方式创建一对零或一关系 - MySQL?
【发布时间】:2013-04-14 14:53:41
【问题描述】:

我正忙于一个项目,遇到的绊脚石之一如下:

我有一个预订表,这可能会或可能不会导致发票被开具(因为一些不相关的事情,例如取消)。我将如何强制执行一(在预订方面)到零或一(在发票方面)的关系?到目前为止,这是我所拥有的:

CREATE TABLE IF NOT EXISTS `booking` (    
   `booking_id` int(11) NOT NULL AUTO_INCREMENT,   
   `voucher_id` int(11) NOT NULL,  
   `pickup_date_time` datetime NOT NULL, ...  
   PRIMARY KEY (`booking_id`,`voucher_id`)  
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

然后,稍后:

  CREATE TABLE IF NOT EXISTS `invoice` (  
  `booking_id` int(11) NOT NULL,  
  `voucher_id` int(11) NOT NULL,  
  `invoice_number` int(11) NOT NULL,  
  `paid` tinyint(1) NOT NULL,  
  PRIMARY KEY (`booking_id`,`voucher_id`),  
  UNIQUE KEY `invoice_number` (`invoice_number`),  
  KEY `voucher_id` (`voucher_id`)  
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

voucher_id 只是我在系统中使用的其他东西。 invoice_number也是在PHP中生成的,所以这无关紧要。

任何帮助将不胜感激!

【问题讨论】:

  • 我应该补充一点,我讨厌任何可以为空的值。所以任何避免 NULL 的东西都会很棒!
  • 我认为您当前的设计没有任何问题。
  • 此外,预订中的复合键 - 这意味着我可以拥有 same booking_id 两次,只要我输入不同的 voucher_id?您应该将 booking_id 设置为 PK 并在 voucher_id 上添加一个 UNIQUE 约束,以强制凭证只能使用一次。或将“booking_id”带到凭证表(是的,这将是可以为空的)即尚未使用的代金券将具有 null 作为 booking_id 并在使用后具有现有的 booking_id。
  • 不,它没有;首先,自动编号只是协助创建一个新号码,它不会阻止您手动插入带有 booking_id 的记录,这将允许重复的 booking_ids。此外;是否需要需要代金券才能进行预订?最后,如果您想要“无缝”预订 ID(即 想要 0001、0005、0006),也不要依赖自动编号,因为插入失败也可能会增加计数器。 IMO,booking_id 是 PK,voucher_id 是“优惠券”的外键(如果预订不需要优惠券,则应该可以为空)
  • 也标记我的第一条评论;这同样适用于发票; PK 应该是 invoice_id,现在预订的 PK 是 booking_id,您可以删除 voucher_id 列。最后要考虑的一件事;如果预订可以应用多个优惠券(例如,如果使用优惠券来获得折扣,并且允许组合它们),则将它们作为 n:m 关系 (HasAndBelongsToMany) 存储在连接表中 bookings_vouchers

标签: mysql sql database-design foreign-keys relational-database


【解决方案1】:

这更多是对@thaJeztah 在他的 cmets 中已经提出的建议的系统化,但无论如何你都可以...

CREATE TABLE voucher (
    voucher_id int(11) PRIMARY KEY
   -- Etc...
);

CREATE TABLE booking (
    booking_id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
    voucher_id int(11) REFERENCES voucher (voucher_id),
    pickup_date_time datetime NOT NULL
   -- Etc...
);

CREATE TABLE invoice (
    invoice_number int(11) NOT NULL PRIMARY KEY,
    booking_id int(11) NOT NULL UNIQUE REFERENCES booking (booking_id),
    paid tinyint(1) NOT NULL
   -- Etc...
);

最小基数:可以在没有发票的情况下进行预订。但是,没有预订就不可能有发票(由于非 NULL 字段 invoice.booking_id 上的 FK)。

最大基数:由于 invoice.booking_id 的 UNIQUE 限制,无法将预订连接到多张发票。一张发票不能关联到多个预订,因为一个字段(一行)不能包含多个值。

因此,预订和发票之间的最终关系是“一对零或一”。


或者,将所有内容放在一个表中,其中包含可空字段,随着预订的进行逐渐填充。

【讨论】:

  • 通常是否有理由使用两个表而不是一个具有可为空字段的表,或者仅仅是个人喜好?
  • @kcstricks 在这种特殊情况下,不。但是,如果这是一个更大的数据库模型的一部分,您可能希望保留独立的表,以便您可以更轻松地将它们连接到模型其余部分的表。也可能有一些物理上的考虑 - 这个answer 列出了一些真正的 1:1 关系的问题,但其中一些也可能适用于 1:0..1...
猜你喜欢
  • 1970-01-01
  • 2023-03-16
  • 2018-02-13
  • 2014-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-25
相关资源
最近更新 更多