假设我有以下表格:
User : id, login, password
Card : id, name, value
一个User
可以多次具有相同的Card
。例如:ID为1的User
可以有ID为1的多个Card
。
我将创建下表:
UserCard : id, user_id, card_id
因此对于该示例,UserCard
可能类似于:
| id | user_id | card_id |
|1 | 1 | 1 |
|2 | 1 | 1 |
|3 | 1 | 2 |
但是我与之讨论过的一位同事告诉我,有些行具有相同的值是不好的设计,并且
| id | user_id | card_id | quantity |
|1 | 1 | 1 | 2 |
|2 | 1 | 2 | 1 |
这将是最好的方法,因为它会删除重复的行。
我认为这是错误的,原因如下:
quantity
可以计算,因此该字段无用quantity
字段会添加很多不必要的内容,例如在向用户添加卡之前,我必须检查用户是否已经拥有此卡(如果他已经拥有了,我会增加数量字段,否则我会添加卡)我的同事的观点是:
问题:
在这种情况下最佳的数据库设计是什么? 一个用户可以拥有0张或任何具有相同ID的卡
编辑:
我们在PostgreSQL中使用Django 没有同事,我只是想知道什么是最好的数据库设计
答案 0 :(得分:1)
您的同事是对的。我会给您介绍一下该理论,并举例说明原因,但是阅读CJ Date的教科书会更好。
UserCard表的基本问题是它没有自然键。您在其上贴上了无意义的id
以使其“唯一”,但id 1和id 2之间没有有意义的区别:它们的值没有差异,因此它们代表的东西是难以区分。当您发现自己无法分辨的事物时,通常的解决方案是对它们进行计数。那就是您用美元做的银行业务。
关系理论基于一组不同的(非重复)元素。您无视这种危险的基础。
实际上(仅举一个例子),当用户丢一张卡时会发生什么?您将如何删除无法区分的行?你的同事可能会说
update UserCard set quantity = quantity - 1 where user = 1 and card = 1
delete UserCard where quantity = 0
你会怎么做?使用另一种limit 1
这样的非理论难题来解决问题?如果限制不为1,因为任意一组用户丢了卡,该怎么办?
您部分地通过人为的独特性来帮助自己:
delete UserCard where id =
(select min(id) from UserCard where user = 1 and card = 1)
说明了唯一性是如何帮助的。但是quantity
是您的朋友。因此,如果您使用该理论而不是与之抗争,那么您的设计和查询都将更加简单。
答案 1 :(得分:0)
希望这可以帮助您
create table #user
(
id int identity(1,1),
login nvarchar(100),
password nvarchar(100)
)
create table #card
(
id int identity(1,1),
name nvarchar(100),
value int
)
create table #usercard
(
id int identity(1,1),
user_id int, /* <-- (in theory) foreign key to #user table*/
card_id int /* <-- (in theory) foreign key to #card table */
)
insert into #user (login, password) values
('user1','password1'),
('user2','password2')
insert into #card (name, value) values
('card1', 1),
('card2', 2),
('card3', 3)
insert into #usercard (user_id, card_id) values
(1,1),
(1,2),
(2,3)
select a.id as user_id, count(b.card_id) as quantity from #user a
inner join #usercard b on a.id = b.user_id
inner join #card c on b.card_id = c.id
group by a.id
在数据库设计中,第三个表(#usercard)称为“连接表”。当您希望实现数据库规范化时,首选此设计。