所以我和我的团队成员之间有一个关于数据库设计的论点,我们正在做的另一个数据库规范化。
外部数据仓库具有以下平台:
表Customer
:
customerID int not null unique pk auto_increment
customerName varchar(255) not null
.....
whole lot of columns here in a flat manner
(which should go to the appropriate tables when normalized)
当前数据位于此外部表(链接服务器)中。
我们的任务是创建一个程序,根据历史数据为客户创建新的报价。
我的队友设计了以下两个表格:
表CustomerHistory
:
c_id int not null unique pk auto_increment
customerID int not null
customerName varchar(255) not null
表Quote
:
quoteID int not null unique pk auto_increment
c_id int not null unique pk auto_increment
dtCreateDate datetime now()
当我看到这个时,我很震惊。
你怎么能忽略一个完全有效的PK并在它上面创建一个新的?
即使您这样做了,如果没有某种类型的日期时间/时间戳指向更改,您怎么能这样做?
我的队友解释说:
我无法信任来自数据仓库的数据,因此我创建了新的ID
当被问及跟踪时间变化时,他回答说:
没有必要,因为我在每次更改时拍摄数据库的快照
我很惊讶。
然后我提出了以下解决方案:
表CustomerHistory
:
customerID int not null
customerName varchar(255) not null
dtChanged datetime
composite key on customerID and dtChanged
这样,我想,我们可以在表格中查询任何给定的报价以及与正确的客户和他的名字签发的时间。
我的队友一直在争论他的方法是“安全的”,我们已经将项目推迟了两周。
拜托,你能帮我们解决这个问题吗?
如果我错了,我真的很有兴趣了解为什么,如果我说得对,对我有好处;)
修改
假设:
1.在任何时候我都需要在实际创建报价的customerName
上提供quote
。
2.访问Customer
表只适用于CURRENT客户(而不是过去)
3.能够跟踪customerName
更改。
答案 0 :(得分:0)
在我看来,你现在将有三张桌子:
Customer
CustomerHistory
Quote
我认为你的伴侣有正确的想法。客户有customerId
个主键。 CustomerHistory
使用customerId
作为外键,因此在这种情况下它需要它自己的主键(c_id
?我可能会尝试将它命名为更合理的东西id
- 停止使用smurf命名!)
这会使您的Quote
表格使用历史记录的密钥作为外键c_id
,并为自己添加新的主键quoteId
CustomerHistory
不需要customerName
字段,因为这已经存在于您的Customer
表格中。
如果您不需要CustomerHistory
和Customer
成为两个单独的表,那么您是对的 - 您可以相信NOT NULL
和UNIQUE
限制只需Customer
- 而且您不需要为其添加额外的主键。 UNIQUE
保证该字段是唯一标识符 - 因此,如果这是他所不信任的字段,那么然后告诉他他错了:P然而,如果你最终得到了上面的三张桌子,那么他并没有完全错,但是他的理由是“不信任”#34;某些事情没有意义。
编辑:
从特定日期范围获取特定客户报价的示例查询将如下所示:
SELECT CustomerHistory.customerName, Quote.*
FROM CustomerHistory
INNER JOIN Quote ON (CustomerHistory.c_id = Quote.c_id)
WHERE CustomerHistory.createdOn BETWEEN 'Jan 1, 2010' AND 'Jan 30, 2010'
AND CustomerHistory.customerId = 5000
您的复合键可能会略微更改查询 - 但老实说,我不认为答案是"正确"或"错误"。当他说他不需要时间戳时,我不确定你的伴侣是什么意思,因为他正在拍摄数据库的快照...你两个拍摄快照时,您应该记录拍摄快照时每个字段的日期。
我真的只是认为复合键过于复杂,而不是必要 - 但这是我的个人观点。如果它适用于您的情况,并且数据正是您在完成更改后正在寻找的 - 那么重要的是;)我怀疑两者都会有类似的表现,假设您有指数设定得非常好。
答案 1 :(得分:0)
这是一个讨论主题,你不会在这里得到“正确答案”。我所有的问题都是要问你的队友。
对我来说,关键因素是:当他说他“不信任来自数据仓库的数据”时,他的意思是什么?
如果CustomerID可以用于唯一标识每个客户随着时间的推移,那么就使用它。如果不能,后续问题是:
[编辑后更新]
听起来像是一种记录情况......
我,我不会再使用另一个代理键,我会使用像
这样的东西CUSTOMERHISTORY
CustomerId int not null PK
QUOTE
CustomerId int not null FK PK 1/2
LoadedAt datetime not null PK 2/2
Name varchar(255) no null
这确实假设您不必处理在完全相同的时间点提交的多个引号 - 如果这是真的,那么您可以从quoteID
中受益......如果事实上您确实需要此日志记录表上的主键。 (日志表通常是简单的数据转储,带有索引用于检索,但不需要唯一标识并检索任何一行。)
这仍然无法回答“不信任主键”问题。如果它是在Microsoft SQL Server中实现的真实和正确的主键,那么他不相信它提供真实和准确的信息要么(a)完全混淆和误导,让自己成为新的承包商,或(b)其余的过去15年来一直依赖它的我们一直都是错的。 (当然,他的架构可行,但它不必要地复杂。)