假设我有用户和管理员的单独表格
users : username , password , email , name
admins : username , password , level
现在我有一个表,用户和管理员都可以在...中插入数据,就像销售书籍的网站一样:
books : title , price
因此想到了3种方法
方法1 - 为管理员和用户
添加2个filds到books表books : title , price , user_id , admin_id
----> some title , 1000 , 5 , -1 // user posted book
----> some other title , 2000 , -1 , 12 // admin posted book
当用户插入图书时,我会将id
保存在user_id
中并将-1
保存为admin_id
,反之亦然,以便管理员
方法2 - 为管理员条目保存user_id = -1
books : title , price , user_id
----> some title , 1000 , 5 // user posted book
----> some other title , 2000 , -1 // admin posted book
方法3 - 让用户在users表中代表管理员并使用此用户ID保存所有管理员条目 - 这并不是一件好事!
users : id , username , password
----> 1 , admin , adminpassword
----> 2 ,user1 , userpassword
----> 3 ,user2 , userpassword
books : title , price , user_id
----> some title , 1000 , 1 // admin posted book
----> some other title , 2000 , 2 // user posted book
----> some other title , 2000 , 3 // user posted book
有没有其他方法可以做到这一点?哪一个更容易接受?
我知道我们可以在同一个表中同时拥有用户和管理员,并为管理员用户提供单独的user_rules
或user_meta
表,但我不想使用该设计....我从事已经在线工作一年或两年的项目,数据库中有大量数据...原始程序员不可用,我正在为网站添加一些新功能...我试图避免将当前结构更改为
答案 0 :(得分:1)
您在这里寻求帮助的行为违反了最佳做法,因此,给出的建议类似于“如何破坏系统以可怕的方式工作”。在这种情况下,我给你的建议是用你最好的判断。
没有什么可以阻止您为系统中定义的每个实体添加列。您还可以规范化您的kludge并将EntityID添加到该表,然后链接回BookEntity表,然后定义EntityType,然而,这将在糟糕的设计之上添加另一个抽象级别。在你提供的情况下,我会说是的,添加另一栏。
答案 1 :(得分:1)
您提供的原因仍然不如您所建议的那么好。你以后只是讨厌自己。
如果users
和admins
表格的主键不重叠,那么我会合并表格,并添加一个额外的列,例如usertype
,指示每个条目的来源。
如果它们重叠,您只需将主键包含在id
和usertype
列中。这样,同一id
可以多次存在,但它与usertype
结合使用仍然是唯一的。
完成此操作后,您只需将id
列添加到books
表格,或者添加“使用类型”列表。同样。
答案 2 :(得分:1)
我必须同意罗斯的观点。设计糟糕的数据库只能做两件事 - 每当你需要做出改变或咬紧牙关并改进设计时,它就会变得更糟。
好的,这个数据库已经有一两年的历史了,并且有很多数据。如果你做得对,那不是问题。
create table OwnerTypes(
ID char( 1 ) not null primary key -- contains 'U' or 'A'
Name varchar( 16 ) not null -- contains 'User' or 'Admin'
Other [type] -- if needed
);
create table Owners_(
ID int not null -- could be auto generated
TypeID char( 1 ) not null references OwnerTypes( ID ),
Username varchar( 32 ) not null,
Password varchar( 32 ) not null,
constraint PK_Owners primary key( ID, TypeID )
);
create table Users_(
ID int not null primary key,
UserType char( 1 ) not null check UserType = 'U',
Email varchar( 128 ) not null,
Name varchar( 32 ) not null,
constraint FK_Users_Owners foreign key( ID, UserType )
references Owners_( ID, TypeID )
);
create table Admins_(
ID int not null primary key,
UserType char( 1 ) not null check UserType = 'A',
Level smallint not null,
constraint FK_Admins_Owners foreign key( ID, UserType )
references Owners_( ID, TypeID )
);
注意: MySQL接受但不强制执行检查约束。您必须使用触发器或其他代码执行此操作。
你会注意到我用一个下划线结束了三个表名。这是我命名一个预计不会被应用程序代码直接访问的表的方法。由于您仍然遇到期望看到用户和管理员表的各种现有脚本和应用程序代码的问题,我们将通过视图提供该访问。
create view Users as
select o.Username, o.Password, u.Email, u.name
from Owners o
join Users u
on u.ID = o.ID
and u.userType = o.TypeID;
现在您有一个名为Users
的数据库对象,它以应用程序所期望的形式提供数据。对Admins
做同样的事情。最后,在视图上写入触发器,拦截DML并根据需要执行操作以维护实际形式的数据。应用程序开发人员甚至不必知道任何改变。
这样,您可以根据需要更新数据库,但允许现有代码继续像以前一样运行。