一个简单的数据库设计问题已经困扰了我一段时间,以为我会在这里问。
假设我有一个数据库表,"Loan"
包含以下字段,
StudentIdentification, LoanDate, ReturnDate
此表用于跟踪已借出某些东西(不在数据库中)的每个学生。 由于每个学生都可以再次贷款和退还贷款(但不是多次贷款而不退货,贷款必须跟着退货),复合主键是
used: StudentIdentifcation and LoanDate
以这种方式存储数据或者有两个表是否更好
table 1: Loan ( StudentIdentification, LoanDate)
table 2: LoanHistory ( StudentIdentification, LoanDate, ReturnDate)
在这种情况下,贷款表的主键是
StudentIdentification
和LoanHistory表的主键是
StudentIdentification, LoanDate
每次学生返回时,“Loan”中的记录将被移至“LoanHistory”表,并且ReturnDate已更新(在交易中完成)。
哪个更好?
答案 0 :(得分:1)
您可以使用简单的SCD(缓慢变化的维度)结构,并使用一个表来存储当前和历史数据。
StudentIdentification, CreationDate, LoanDate, ReturnDate
前两列是PK。
您还可以添加金额来表示贷款或退货。
您可能会找到this question relvant
答案 1 :(得分:1)
使用三列的单个表是最简单的方法。它允许您回答诸如“2013年3月有多少学生借了东西?”之类的问题。容易。如果你有两个表,你需要访问它们来回答这个问题,因为你实际上有一个“开放贷款”和“退回贷款”表。
可能是您的系统对当前开放的贷款非常感兴趣。他们可能经常被查询和更新。在这种情况下,如果您在一个表中具有当前活动的贷款,并且将历史记录推送到辅助表中,它将表现得更好。如果您需要保留很多历史记录,但很少阅读,那就很好。
答案 2 :(得分:1)
我会创建一个表,然后使用过滤索引(SQL Server 2008+)或索引视图(SQL Server 2005-)来强制每个学生只有一行NULL
返回日期:
CREATE TABLE Loans (
StudentID int not null,
LoanDate datetime not null,
ReturnDate datetime null,
constraint PK_Loans PRIMARY KEY (StudentID,LoanDate),
constraint CK_Loans_NoTimeTravel CHECK (LoanDate < ReturnDate)
)
过滤索引:
CREATE UNIQUE INDEX IX_Loans_SingleOpen ON Loans (StudentID) WHERE ReturnDate IS NULL
索引视图:
CREATE VIEW dbo.Loans_SingleOpen_DRI
WITH SCHEMABINDING
AS
SELECT StudentID FROM dbo.Loans WHERE ReturnDate IS NULL
GO
CREATE UNIQUE CLUSTERED INDEX IX_Loans_SingleOpen ON Loans_SingleOpen_DRI (StudentID)
(假设dbo
是适当的模式 - SCHEMABINDING
需要这个模式,而这需要创建索引)
答案 3 :(得分:0)
提供准确答案更多信息。关于应用程序是必要的。例如,为什么没有一个包含StudentId和LoanDate的表,主键为StudentId。返回借出项目后删除该行。因此,没有StudentId记录,那么目前没有任何贷款。此建议假定LoanDate对于发送延迟提醒非常重要。如果不需要延迟提醒那么为什么甚至有LoanDate呢?
如果您需要包含退货日期和贷款日期的贷款历史记录。然后添加第二个历史记录表来存储行,因为它们将从贷款表中删除,并带有附加返回日期字段。