我如何约束可能引用多个其他表的外键关系?
how can I constrain a foreign key relationship where it may refer to multiple other tables?
我有一个名为 inventory_movements 的 table,我打算保存进出仓库的产品移动,它有像
这样的字段
1- movement_id(PK)
2- product_id(FK)
3- quantity int
4- unit_price decimal
5- movement ENUM('in','out')
6- date datetime
7- ????????? (reference )(e.g. sell(out)- purchase(in)- fire loss(out)
- sales return (in) - purchase return (out)
我的问题是我想存储移动的参考(移动的原因),它是订单 ID 或购买 ID,购买 return ID,....等
但我也想在这个字段上做一个约束,以确保没有无效数据(例如不存在的购买)将存储在数据库中,诅咒我不能使一个外键引用很多tables(销售、采购、采购 returns 等)
一个非常糟糕的解决方案是为每个参考类型(销售 ID、购买 ID、销售 return ID 等)添加列,并在每个移动中填写正确的一个,让其他的为空,但这是对规范化的诅咒,我以后不能再添加任何参考。
遇到这种情况我该怎么办?
请考虑我是新手,谢谢
你有几个方法。一种是每个 table 类型有一个外键,并带有一个约束以确保恰好有一个不为空。我同意这很笨重,但有些人更喜欢它(例如,David Fetter 在博客中介绍了这种方法的好处)。
另一种方法是将引用的 table 的公共部分分解为一个单独的、易于引用的 table。如果你不能这样做,你可以用一个触发器维护的 table 来代替。这意味着:
- 一笔交易文件table
- A table 用于 sales/purchase 数据(或者可能是不同的 table)。
如果做不到,那么你有另一个 table,它只存储 ID、相关的 table 和一个用于参考目的的 ID,并用触发器维护,然后你那里有引用约束。
无论哪种方式,long-运行 你可能最终会得到第二种解决方案(一个主交易日志,然后是其他 table 扩展它)。
(原创设计题答案如下。
根据您想如何解决这个问题,我可以看到两种方法之一。
第一个是使用正数输入和负数输出的基本约定。这适用于全球移动(采购和销售),但它不适用于本地移动(在仓库之间移动)。
这里的一个选择是有一个单独的 "states" table 来代表全局和局部状态。比如采购,销售,不同的仓库等等。那么你把状态之间的转移表示成一个图link。您还可以拥有一个文档 table,它可以代表采购和销售,并具有适当的分类等。这允许在州内、州外和文档之间存在三向关系。例如,销售可能有一个州内库存(或特定仓库)、一个州外销售和销售发票文件。
当然你可以两者都做,一种方式存储全球库存,另一种方式存储仓库移动。
我有一个名为 inventory_movements 的 table,我打算保存进出仓库的产品移动,它有像
这样的字段1- movement_id(PK)
2- product_id(FK)
3- quantity int
4- unit_price decimal
5- movement ENUM('in','out')
6- date datetime
7- ????????? (reference )(e.g. sell(out)- purchase(in)- fire loss(out)
- sales return (in) - purchase return (out)
我的问题是我想存储移动的参考(移动的原因),它是订单 ID 或购买 ID,购买 return ID,....等
但我也想在这个字段上做一个约束,以确保没有无效数据(例如不存在的购买)将存储在数据库中,诅咒我不能使一个外键引用很多tables(销售、采购、采购 returns 等)
一个非常糟糕的解决方案是为每个参考类型(销售 ID、购买 ID、销售 return ID 等)添加列,并在每个移动中填写正确的一个,让其他的为空,但这是对规范化的诅咒,我以后不能再添加任何参考。
遇到这种情况我该怎么办?
请考虑我是新手,谢谢
你有几个方法。一种是每个 table 类型有一个外键,并带有一个约束以确保恰好有一个不为空。我同意这很笨重,但有些人更喜欢它(例如,David Fetter 在博客中介绍了这种方法的好处)。
另一种方法是将引用的 table 的公共部分分解为一个单独的、易于引用的 table。如果你不能这样做,你可以用一个触发器维护的 table 来代替。这意味着:
- 一笔交易文件table
- A table 用于 sales/purchase 数据(或者可能是不同的 table)。
如果做不到,那么你有另一个 table,它只存储 ID、相关的 table 和一个用于参考目的的 ID,并用触发器维护,然后你那里有引用约束。
无论哪种方式,long-运行 你可能最终会得到第二种解决方案(一个主交易日志,然后是其他 table 扩展它)。
(原创设计题答案如下。
根据您想如何解决这个问题,我可以看到两种方法之一。
第一个是使用正数输入和负数输出的基本约定。这适用于全球移动(采购和销售),但它不适用于本地移动(在仓库之间移动)。
这里的一个选择是有一个单独的 "states" table 来代表全局和局部状态。比如采购,销售,不同的仓库等等。那么你把状态之间的转移表示成一个图link。您还可以拥有一个文档 table,它可以代表采购和销售,并具有适当的分类等。这允许在州内、州外和文档之间存在三向关系。例如,销售可能有一个州内库存(或特定仓库)、一个州外销售和销售发票文件。
当然你可以两者都做,一种方式存储全球库存,另一种方式存储仓库移动。