Gre*_*ida 25 database rdbms database-design
我知道这种情况违背了关系数据库的原则,但让我来描述一下情况.
我有一个页面,用户将放置一些项目.
________________
| -Item1 |
| -Item2 |
| -Item3 |
| -Item4 |
|________________|
Run Code Online (Sandbox Code Playgroud)
这些项目必须保持用户给出的顺序.然而,用户可以将该顺序改变任意次数.
________________
| -Item1 |
| -Item4 |
| -Item2 |
| -Item3 |
|________________|
Run Code Online (Sandbox Code Playgroud)
方法1
我最初的想法是给项目一个索引来代表列表中的位置
Page Item
----------- ---------------
FK | pid FK | pid
| name PK | iid
| index
| content
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,您可以选择项目where pid = Page.pid,order by index方便.但是,每次更改订单时,您必须在另一个项目(最佳案例)和所有其他项目(最差情况)之间进行任何更改.
方法2
我还考虑制作一个"链表",如数据结构,其中每个项指向列表中的下一个项.
Page Item
----------- ---------------
FK | pid FK | pid
| name PK | iid
| next
| content
Run Code Online (Sandbox Code Playgroud)
这可能会使订单更改成本更低,但我们必须依靠前端编程来提取订单.
有没有我没想过的方法?请告诉我.
Ale*_*ird 23
解决方案:创建index一个字符串(因为字符串本质上具有无限的"任意精度").或者如果使用int,则增加index100而不是1.
性能问题是:两个排序项之间没有"中间"值.
item index
-----------------
gizmo 1
<<------ Oh no! no room between 1 and 2.
This requires incrementing _every_ item after it
gadget 2
gear 3
toolkit 4
box 5
Run Code Online (Sandbox Code Playgroud)
相反,这样做(下面更好的解决方案):
item index
-----------------
gizmo 100
<<------ Sweet :). I can re-order 99 (!) items here
without having to change anything else
gadget 200
gear 300
toolkit 400
box 500
Run Code Online (Sandbox Code Playgroud)
更好的是:这是Jira如何解决这个问题.他们的"等级"(你称之为索引)是一个字符串值,允许在排名项之间有大量的喘息空间.
这是我使用的jira数据库的一个真实示例
id | jira_rank
---------+------------
AP-2405 | 0|hzztxk:
ES-213 | 0|hzztxs:
AP-2660 | 0|hzztzc:
AP-2688 | 0|hzztzk:
AP-2643 | 0|hzztzs:
AP-2208 | 0|hzztzw:
AP-2700 | 0|hzztzy:
AP-2702 | 0|hzztzz:
AP-2411 | 0|hzztzz:i
AP-2440 | 0|hzztzz:r
Run Code Online (Sandbox Code Playgroud)
注意这个例子hzztzz:i.字符串排名的优点是您在两个项目之间用尽了空间,您仍然不必重新排名其他任何内容.您只需开始在字符串中附加更多字符以缩小焦点范围.
我认为@ a1ex07在这里是正确的轨道(+1).我不认为itemOrder违反3NF的差距,但我确实担心3NF的不同违规行为(更多内容见下文).我们还必须留意该itemOrder领域的不良数据.这是我开始的方式:
create table pages (
pid int,
primary key (pid)
);
create table users (
uid int,
primary key (uid)
);
create table items (
iid int,
primary key (iid)
);
create table details (
pid int not null references pages(pid),
uid int not null references users(uid),
iid int not null references items(iid),
itemOrder int,
primary key (pid, uid, iid),
unique (pid, uid, itemOrder)
);
Run Code Online (Sandbox Code Playgroud)
主键确保对于每个页面,对于每个用户,存在唯一的项目.唯一约束确保对于每个页面,对于每个用户,都有唯一的itemOrders.这是我对3NF的担心:在这种情况下,itemOrder并不完全依赖于主键; 它只取决于(pid, uid)零件.那甚至不是2NF; 这是一个问题.我们可以包含itemOrder在主键中,但后来我担心它可能不是最小的,因为PK需要.我们可能需要将其分解为更多表.仍然在想 ...
[编辑 - 更多关于这个主题的思考...]
假设
有用户.
有页面.
有物品.
(页面,用户)标识一组项目.
(页面,用户)标识插槽的有序LIST,如果我们愿意,我们可以在其中存储项目.
我们不希望在(页面,用户)列表中有重复的项目.
计划A.
杀死details上面的桌子.
添加表,ItemsByPageAndUser以表示由(页面,用户)标识的项目的SET.
create table ItemsByPageAndUser (
pid int not null references pages(pid),
uid int not null references users(uid),
iid int not null references items(iid),
primary key (pid, uid, iid)
)
Run Code Online (Sandbox Code Playgroud)
添加表,, SlotsByPageAndUser表示可能包含项目的插槽的有序LIST.
create table SlotsByPageAndUser (
pid int not null references pages(pid),
uid int not null references users(uid),
slotNum int not null,
iidInSlot int references items(iid),
primary key (pid, uid, slotNum),
foreign key (pid, uid, iid) references ItemsByPageAndUser(pid, uid, iid),
unique (pid, uid, iid)
)
Run Code Online (Sandbox Code Playgroud)
注1:可以iidInSlot为空,如果我们愿意,我们可以有空槽.但是如果存在一个项目,则必须根据项目表进行检查.
注意2:我们需要最后一个FK以确保我们不添加任何不在此(用户,页面)的可能项目集中的项目.
注3:唯一约束(pid, uid, iid)强制实现我们在列表中具有唯一项目的设计目标(假设6).如果没有这个,我们就可以在我们喜欢的(页面,用户)标识集中添加尽可能多的项目,只要它们位于不同的插槽中即可.
现在我们很好地将项目从他们的插槽中解耦,同时保持他们对(页面,用户)的共同依赖.
这个设计肯定在3NF,可能在BCNF,虽然我SlotsByPageAndUser在这方面担心.
这个问题是因为在表中的唯一约束是SlotsByPageAndUser关系的基数SlotsByPageAndUser和ItemsByPageAndUser是一个对一个.通常,非实体子类型的1-1关系是错误的.当然也有例外,也许这就是其中之一.但也许有更好的方法...
B计划
杀了SlotsByPageAndUser桌子.
添加一slotNum列到ItemsByPageAndUser.
在(pid, uid, iid)to 上添加唯一约束ItemsByPageAndUser.
现在是:
create table ItemsByPageAndUser (
pid int not null references pages(pid),
uid int not null references users(uid),
iid int not null references items(iid),
slotNum int,
primary key (pid, uid, iid),
unique (pid, uid, slotNum)
)
Run Code Online (Sandbox Code Playgroud)
注4:保留slotNum可空可保留我们指定集合中不在列表中的项目的能力.但是...
注意5:对涉及可为空列的表达式设置唯一约束可能会在某些数据库中导致"有趣"的结果.我认为它将按照我们在Postgres中的意图行事.(请参阅此处的讨论.)对于其他数据库,您的里程可能会有所不同.
现在没有乱七八糟的关系,所以那更好.它仍然是3NF,因为唯一的非键属性(slotNum)取决于键,整个键,除了键之外什么都没有.(你不能在slotNum不告诉我你正在谈论的页面,用户和项目的情况下询问.)
它不是BCNF,因为[ (pid, uid, iid)- > slotNum]和[ (pid,uid,slotNum)- > iid ].但这就是为什么我们在(pid,uid,slotNum)上有唯一约束来阻止数据进入不一致状态.
我认为这是一个可行的解决方案.
您可以将一个新字符 (nvarchar) 列添加到包含按您喜欢的顺序分隔的's列表的Page名为的表中,即. 优点是只需维护一张表中的一个字段 - 明显的缺点是需要编写一个实用程序函数来在字符和数字类型之间进行转换,这实际上可能不会花费太长时间。orderiid1,4,3,2
| 归档时间: |
|
| 查看次数: |
10070 次 |
| 最近记录: |