我正在设计一个数据库,用于跟踪用户及其与不同组织的关系。用户可以属于许多组织,组织可以拥有许多用户。这部分很容易通过多对多关系来解决。但是,如果事情变得更加模糊,那么用户也可以成为一个或多个组织的管理员,并且用户需要能够记录每个组织的时间花费。
似乎有很多方法可以解决这个问题。这是我到目前为止的表结构,如果您认为有更好的方法,我希望您的意见。
CREATE TABLE `organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`)
);
CREATE TABLE `user` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`last_name` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`email` VARCHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`password` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`),
UNIQUE INDEX `email` (`email`)
);
CREATE TABLE `time_log` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_organization_id` INT(11) NOT NULL,
`date` DATE NOT NULL,
`time` TINYINT(4) NOT NULL,
PRIMARY KEY (`id`),
INDEX `user_organization_id` (`user_organization_id`),
CONSTRAINT `fk_time_log_user_organization` FOREIGN KEY (`user_organization_id`) REFERENCES `user_organization` (`id`)
);
CREATE TABLE `user_organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`, `user_id`, `organization_id`, `admin`) USING BTREE,
INDEX `user_id` (`user_id`),
INDEX `organization_id` (`organization_id`),
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
);
我选择使用id
表上的user_organization
字段,因为它更容易创建time_log
表的外键。不过,我也可以将user_id
和organization_id
放在time_log table
中。
答案 0 :(得分:0)
CREATE TABLE `user_organization` (
`id` INT(11) NOT NULL AUTO_INCREMENT, -- remove
`user_id` INT(11) NOT NULL, -- don't you want INT UNSIGNED?
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`, `user_id`, `organization_id`, `admin`) USING BTREE, -- Bad!
INDEX `user_id` (`user_id`), -- see below
INDEX `organization_id` (`organization_id`),
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
);
- >
CREATE TABLE `user_organization` (
`user_id` INT(11) NOT NULL,
`organization_id` INT(11) NOT NULL,
`admin` TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`user_id`, `organization_id`) -- PK, and lookup from user
INDEX `organization_id` (`organization_id`, user_id), -- lookup the other way
CONSTRAINT `fk_user_organization_organization` FOREIGN KEY (`organization_id`) REFERENCES `organization` (`id`),
CONSTRAINT `fk_user_organization_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`)
) ENGINE=InnoDB; -- don't let it default to MyISAM
答案 1 :(得分:0)
在交叉表中标记管理员不是一个好主意。如果特定组织的所有用户都没有被标记,或者同一组织中有多个用户被标记,会发生什么?一个好方法是使用单独的OrgAdmins表。
create table OrgAdmins(
UserID int not null,
OrgID int not null,
Assigned date not null,
constraint PK_OrgAdmins primary key( OrgID ),
constraint FK_OrgAdmins_OrgUser foreign key( UserID, OrgID )
references user_organization( user_id, organization_id )
);
使OrgID成为关键字段会限制每个组织的一个条目。制作UserID,OrgID引用交集表可确保管理员被正确定义为组织的用户。
类似的布局可以用于时间日志表。但是,那个时间是组织的每个用户的总时间,还是每个时间段的用户都会花费时间"在组织?如果是前者,那么(UserID,OrgID)对将是主键以及外键。如果是后者,这是一个"事件"通常没有主键的表 - 每个引用可能会出现多个条目,并按事件的日期和时间进行区分。