指向不同表的外键

时间:2010-04-27 12:33:15

标签: mysql database-design innodb

我正在实现previous question中讨论的每个子类设计的表。它是一个产品数据库,产品根据其类型可以具有非常不同的属性,但是每种类型的属性都是固定的,并且类型根本不可管理。我有一个包含公共属性的主表:

product_type
============

product_type_id INT
product_type_name VARCHAR

E.g.:

1 'Magazine'
2 'Web site'

product
=======

product_id INT
product_name VARCHAR
product_type_id INT -> Foreign key to product_type.product_type_id
valid_since DATETIME
valid_to DATETIME

E.g.

1 'Foo Magazine'      1 '1998-12-01' NULL
2 'Bar Weekly Review' 1 '2005-01-01' NULL
3 'E-commerce App'    2 '2009-10-15' NULL
4 'CMS'               2 '2010-02-01' NULL

...以及每种产品类型的一个子表:

item_magazine
=============

item_magazine_id INT
title VARCHAR
product_id INT -> Foreign key to product.product_id
issue_number INT
pages INT
copies INT
close_date DATETIME
release_date DATETIME

E.g.

1 'Foo Magazine Regular Issue'      1 89 52 150000 '2010-06-25' '2010-06-31'
2 'Foo Magazine Summer Special'     1 90 60 175000 '2010-07-25' '2010-07-31'
3 'Bar Weekly Review Regular Issue' 2 12 16  20000 '2010-06-01' '2010-06-02'

item_web_site
=============

item_web_site_id INT
name VARCHAR
product_id INT -> Foreign key to product.product_id
bandwidth INT
hits INT
date_from DATETIME
date_to DATETIME

E.g.

1 'The Carpet Store'        3 10  90000 '2010-06-01'         NULL
2 'Penauts R Us'            3 20 180000 '2010-08-01'         NULL
3 'Springfield Cattle Fair' 4 15 150000 '2010-05-01' '2010-10-31'

现在我想添加一些与特定项目相关的费用。由于子类型非常少,因此可以这样做:

fee
===

fee_id INT
fee_description VARCHAR
item_magazine_id INT -> Foreign key to item_magazine.item_magazine_id
item_web_site_id INT -> Foreign key to item_web_site.item_web_site_id
net_price DECIMAL

E.g.:

1 'Front cover'      2 NULL 1999.99
2 'Half page'        2 NULL  500.00
3 'Square banner' NULL    3  790.50
4 'Animation'     NULL    3 2000.00

我有紧密的外键来处理级联版本,我认为我可以添加一个约束,所以只有一个ID是NOT NULL。

然而,我的直觉表明,摆脱item_WHATEVER_id列并保留一个单独的表会更清晰:

fee_to_item
===========

fee_id INT -> Foreign key to fee.fee_id
product_id INT -> Foreign key to product.product_id
item_id INT -> ???

但我无法弄清楚如何在item_id上创建外键,因为源表因product_id而异。我应该坚持原来的想法吗?

更新

我实际考虑的替代方案是:

fee
===

fee_id INT
fee_description VARCHAR
product_id INT -> Foreign key to product.product_id
item_id INT -> ???
net_price DECIMAL

我不确定为什么提到一个单独的fee_to_item表(我想我还在考虑别的东西)但是它并没有真正改变问题,因为关键点是相同的:foo1_id+foo2_id+foo3_id vs source_id+foo_id

2 个答案:

答案 0 :(得分:1)

我通常使用一个FK列和一个标志列。而不是

fee 
=== 

fee_id INT 
fee_description VARCHAR 
item_magazine_id INT -> Foreign key to item_magazine.item_magazine_id 
item_web_site_id INT -> Foreign key to item_web_site.item_web_site_id 
net_price DECIMAL 

你有

fee 
=== 

fee_id INT 
fee_description VARCHAR 
item_id INT -> Foreign key to item_magazine/website.item_magazine/website_id 
product_type_id INT -> Foreign key to product_type.product_type_id
net_price DECIMAL 

然后您的查询可以推广。而不是2个不同的查询,例如:

SELECT * FROM fee WHERE item_magazine_id=x
SELECT * FROM fee WHERE item_website_id=y

你做的事情如下:

SELECT * FROM fee WHERE item_id=x and product_type_id=1
SELECT * FROM fee WHERE item_id=y and product_type_id=2

答案 1 :(得分:0)

某些数据库甚至不允许FK列中包含空值,这会阻止您的第一个解决方案。我不记得MySQL是否有。但我同意单独的表更好。如果需要,你可以UNION他们在一起,所以想要一起看所有费用的人可以这样做。但是,由于今天对不同的“凡是”有收费,因此未来它们也可能会有所不同,然后你可能会被迫拆分,因为一种费用仅适用于一种。例如,也许您的费用将来是基于数量的,并且没有网站数量这样的东西。或基于时间,或基于优惠券,或其他。

此外,如果你添加第三种收费的东西,你会把它添加到同一张桌子吗?或者你在那时分裂了吗?我认为你们正在强迫这些因为它们是相似的,但它们并不是真的相同。

无论如何,我说拆分表。