Внешний ключ, указывающий на разные таблицы - PullRequest
1 голос
/ 27 апреля 2010

Я реализую таблицу для подкласса дизайна, который я обсуждал в предыдущем вопросе . Это база данных продуктов, в которой продукты могут иметь очень разные атрибуты в зависимости от их типа, но атрибуты фиксированы для каждого типа, а типы вообще не поддаются управлению. У меня есть главная таблица, которая содержит общие атрибуты:

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

У меня жесткие внешние ключи для обработки каскадных выпусков, и я предполагаю, что могу добавить ограничение, чтобы только один из идентификаторов НЕ был НЕДЕЙСТВИТЕЛЕН.

Однако моя интуиция подсказывает, что было бы чище избавиться от столбцов 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 против source_id+foo_id

Ответы [ 2 ]

1 голос
/ 27 апреля 2010

Я обычно иду с одним столбцом 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 

Тогда ваши запросы обобщаются. Вместо двух разных запросов, например:

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
0 голосов
/ 27 апреля 2010

Некоторые базы данных даже не позволяют столбцам FK содержать нулевые значения, что помешает вашему первому решению. Я не могу вспомнить, если MySQL делает или нет. Но я согласен, что отдельная таблица лучше. При необходимости вы можете UNION их вместе, чтобы люди, которые хотят видеть все сборы вместе, могли это сделать. Но так как сегодня существуют сборы для разных «тех, кто любит», также возможно, что они будут меняться в будущем, и тогда вам придется разделить таблицу, потому что тип сборов применяется только к одному. Например, возможно, ваши сборы будут основаны на количестве в будущем, и не существует такой вещи, как количество для веб-сайта. Или на основе времени, или на основе купона, или что-то еще.

Кроме того, если вы добавляете третий тип вещей, с которого вы взимаете плату, добавляете ли вы ее в ту же таблицу? Или вы разделяете это в этот момент? Я думаю, что вы сводите их вместе, потому что они похожи, но на самом деле это не одно и то же.

Во всяком случае, я говорю разделить столы.

...