2011-12-03 66 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 
相關問題