我正在开展个人项目,以便对各种项目进行计时,但我不确定构建数据库的最佳方法。
结构的简化细分如下:
最终会有更多关系,但这是应用程序的基础。如您所见,每个项目都与一对多关系中的项目相关。
我的问题是,我应该将每个表与上面的每个“父”表相关联吗?像这样:
clients
id
reports
id
client_id
line_items
id
report_id
client_id
time_records
id
report_id
line_item_id
client_id
随着它逐渐减少,每个新表中会添加越来越多的外键。
我最初的反应是,这不是正确的做法,但我希望得到一些第二(和第三!)意见。
答案 0 :(得分: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` = ?;
获取特定客户的时间条目:(新架构;表格中不需要“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)。
答案 1 :(得分:1)
不,如果模型的元素没有直接关系,那么在相应的表中不应该有直接的关系。否则,您的数据将有冗余,您将无法进行更新。
这是正确的方法:
clients
id
reports
id
client_id
line_items
id
report_id
time_records
id
line_id
答案 2 :(得分:1)
如果您从未直接将订单项直接加入客户,则无需在client_id
表格上创建line_items
,因为您可以通过reports
表格获取该订单项。其他FK也是如此。
我建议您在创建可能使开发复杂化的冗余外键之前,在报表中考虑对此数据集的需求/查询。
如果您将来需要它们,创建冗余FK并不困难,一些ALTERS和UPDATE SELECTS可以解决您的问题。
如果您在line_items
中没有太多信息,可以在time_records
中进行非规范化并添加此信息。
答案 3 :(得分:1)
在两个表之间存在直接关系的任何地方,您应该使用外键来保持数据的完整性。就个人而言,我会看一下这样的结构:
Client
ClientId
Report
ReportId
ClientId
LineItem
LineItemId
ReportId
TimeRecord
TimeRecordId
LineItemId
在此示例中,ClientId
中不需要LineItem
,因为您通过Report
表拥有该关系。在所有表中使用ClientId
的主要缺点是,如果业务逻辑不强制执行这些值的一致性(代码中存在错误),则可以遇到如果基于搜索而获得不同值的情况上
Report:
ReportId = 3
ClientId = 2
LineItem:
LineItemId = 1
ReportId = 3
ClientId = 3
在上述情况下,如果您的查询经历了ClientId = 2
和Report
,如果您的查询通过ClientId = 3
,那么您会看LineItem
这一切很难发生确定哪个关系是正确的,以及错误的位置。
另外,我主张不使用id
列,而是使用更明确的名称来描述id
的用途。 (ReportId
或ClientId
)在我看来,这使得联接更容易阅读。举个例子:
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
答案 4 :(得分: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