2011-12-03 32 views
3

我正在为各种项目计时的个人项目工作,但我不确定构建数据库的最佳方式。我是否应该将所有的MySQL表彼此关联?

结构的简化细目如下:

  • 每个客户端可以有多个报告。
  • 每个报表可以有多个行项目。
  • 每个订单项都可以有多个时间记录。

最终会有更多的关系,但这是应用程序的基础。正如您所看到的,每件商品都与其下面的商品以一对多的关系相关。

我的问题是,我应该将每个表格与上面的每个“父”表关联起来吗?像这样的事情:

clients 
    id 

reports 
    id 
    client_id 

line_items 
    id 
    report_id 
    client_id 

time_records 
    id 
    report_id 
    line_item_id 
    client_id 

而且,随着级联,越来越多的外键被添加到每个新表中。

我最初的反应是,这不是正确的做法,但我很想得到第二个(和第三个!)意见。

+1

您是如何(概念上)区分订单项和时间记录的?订单项是一项任务吗? – jwiscarson

+0

是的,订单项是一项任务。例如,一个订单项可能会读取“内置计时应用程序”,并且它会包含多个时间记录(此处为30分钟,12分钟时间等),这些时间记录会累计到订单项上的总时间。 –

+2

鉴于此,我认为您当前的设计完全可以接受(减去子表中的额外ID)。 – jwiscarson

回答

3

你这样做的好处是,你可以检查所有的时间记录,比如说,一个特定的客户端ID,而无需连接。但真的,这不是必要的。您所需要的只是将参考存储备份到一个“级别”上。这里是从“客户端”的视角一些例子:

要获得特定客户的报告:(简单;同当前架构你的建议)

SELECT * FROM `reports` 
    WHERE `client_id` = ?; 

要获得特定客户的订单项:(新的模式;不需要 “的client_id” 表)

SELECT `line_items`.* FROM `line_items` 
    JOIN `reports` ON `reports`.`id` = `line_items`.`id` 
    JOIN `clients` ON `clients`.`id` = `reports`.`client_id` 
    WHERE `clients`.`id` = ?; 

要获得特定客户的时间条目:(NE w模式;不需要 “的client_id” 或表 “REPORT_ID”)

SELECT `time_records`.* FROM `time_records` 
    JOIN `line_items` ON `line_items`.`id` = `time_records`.`line_item_id` 
    JOIN `reports` ON `reports`.`id` = `line_items`.`id` 
    JOIN `clients` ON `clients`.`id` = `reports`.`client_id` 
    WHERE `client_id` = ?; 

因此,修改后的方案将是:

clients 
    id 

reports 
    id 
    client_id 

line_items 
    id 
    report_id 

time_records 
    id 
    line_item_id 

编辑:

此外,我会考虑使用视图来简化查询(我假设你经常使用它们),绝对在连接列上创建索引,并利用外键引用进行规范化(仅适用于InnoDB)。

+0

我希望我能接受所有的答案,但我觉得你的解释最彻底。谢谢! –

0

由于个人的看法,我会:

clients 
    id 

time_records 
    id 
    client_id 
    report 
    line_item 
    report_id 

这样,所有的领域都超过在time_records表。然后,您可以这样做:

SELECT * 
FROM 'time_records' 
WHERE 'time_records'.'client_id' = 16542 
    AND 'time_records'.'report' = 164652 
ORDER BY 'time_records'.'id' ASC 
+1

格式化您的查询时,我也将'=='更改为'='。我希望这种改变是你想要的;对不起,如果不是。 –

+0

谢谢!它是。尝试比我想的会更快。 –

1

没有,如果在该模型的元素没有直接关系,那么不应该有相应的表格中直接的关系。否则,您的数据将会有冗余,您将有更新问题。

这是正确的方式:

clients 
    id 

reports 
    id 
    client_id 

line_items 
    id 
    report_id 

time_records 
    id 
    line_id 
1

你并不需要在line_items表中创建client_id如果你从来没有参加行项目直接客户,becouse你可以通过reports表。同样发生在其他FK上。

我建议您在创建可能会使开发复杂化的冗余外键之前,在您的报告中考虑对此数据集合的需求/查询。

如果将来需要它们,创建多余的FK并不难,但某些ALTERS和UPDATE SELECTS解决了您的问题。

如果您在line_items中没有太多信息,则可以在time_records中进行规范化并添加此信息。

1

任何地方有两个表之间存在直接关系,您应该使用外键来保持数据的完整性。就个人而言,我想看看这样的结构:

Client 
    ClientId 

Report 
    ReportId 
    ClientId 

LineItem 
    LineItemId 
    ReportId 

TimeRecord 
    TimeRecordId 
    LineItemId 

在这个例子中,你不需要在LineItemClientId,因为你必须通过Report表关系。在所有表中使用ClientId的主要缺点是,如果业务逻辑不强制执行这些值的一致性(代码中存在错误),则可能遇到以下情况:如果您基于

Report: 
    ReportId = 3 
    ClientId = 2 
LineItem: 
    LineItemId = 1 
    ReportId = 3 
    ClientId = 3 

在上述情况下,你会在看ClientId = 2如果您的查询通过ReportClientId = 3去,如果你的查询通过LineItem就很难一旦发生这种情况,以确定哪些关系是正确的,并且其中的错误是。

此外,我会主张没有id列,而是更明确的名称来描述id用于什么。 (ReportIdClientId)在我看来,这使得连接更易于阅读。举例:

SELECT COUNT(1) AS NumberOfLineItems 
FROM Client AS c 
INNER JOIN Report AS r ON c.ClientId = r.ClientId 
INNER JOIN LineItem AS li ON r.ReportId = li.ReportId 
WHERE c.ClientId = 12 
相关问题