说,User
有很多Devices
。也就是Device.user_id references User.id
。
我们需要为用户 - 设备关系添加“活动”状态。这意味着User
只能有一个“有效”Device
。
- 附录
似乎我必须澄清事情。
User
可能没有Device
,一个Device
或几个Device
; Device
可以拥有User
但不得拥有; Device.user_id references User.id
; User.id
和Device.id
是唯一的PK,不得更改(因此,没有复合PK); User
可以不超过一个'有效'Device
,但它可以是NULL
,但如果不是NULL
,它必须引用Device
所拥有的User
之一。- 结束附录
我可以想象两种方法,都很简单:
active_device_id
字段添加到User
,即User.active_device_id references Device.id
; Boolean
实体添加Device
- 类型标记。最常见的查询是:
Device
; User
Device
; User
是否有效
很少使用,但非常重要的是:
Device
(并使其他User
的设备处于非活动状态)激活某个User
; Device
的所有权。第一种方法有两点需要注意:
user1
将有效设备设置为device1
,但device1
拥有user2
; user1
和user2
都有相同的有效device
(虽然可以通过字段User.active_device_id
上的唯一约束轻松修复。 2d方法可以为一个Device
带来几个有效User
个。
这两种方法的其他缺点是什么?
......我应该选择什么?为什么? :)
答案 0 :(得分:1)
我肯定会选择第一种方法 - active_device_id。
它可以保证每个用户只有一个活动设备,正如您所说,允许所有用户可选择保证活动设备ID的唯一性。
使用此方法,所有查询都非常简单。
答案 1 :(得分:1)
你没有提到你的DBMS,但是大多数DBMS都有可能创建部分索引,这对他们来说似乎是一个完美的用例。
我对设备表的外观有点困惑,但假设结构:
create table device
(
device_id integer not null,
user_id integer not null,
is_active_for_user boolean,
primary key (device_id, user_id)
);
您可以使用以下索引确保每个用户只有一个活动设备(Postgres语法,其他DBMS有其他语法来定义部分索引):
create unique index idx_unique_active_device
on device (user_id)
where is_active_for_user;
答案 2 :(得分:0)
如果您尝试为每个用户强制实施一个唯一设备,则您需要的只是deviceId
表中引用的user
列的唯一约束。没有标志。
device ------ id user ------ id deviceId (fk, unique constraint)
如果您遵循David's方法,则无法保证每个用户只能使用一个活动设备。您必须具有UNIQUE
约束才能保证每个用户使用一台设备:
这将允许重复的设备:
CREATE TABLE device (
`id` int,
PRIMARY KEY(`id`)
) ENGINE=INNODB;
INSERT INTO device (`id`)
VALUES (1), (2);
CREATE TABLE user (
`id` int,
`active_device_id` int,
INDEX (`active_device_id`),
FOREIGN KEY (`active_device_id`)
REFERENCES `device`(`id`)
) ENGINE=INNODB;
INSERT INTO user (`id`, `active_device_id`)
VALUES (1, 1), (2, 1);
添加UNIQUE
保证每个用户都有唯一的设备。
CREATE TABLE device (
`id` int,
PRIMARY KEY(`id`)
) ENGINE=INNODB;
INSERT INTO device (`id`)
VALUES (1), (2);
CREATE TABLE user (
`id` int,
`active_device_id` int,
INDEX (`active_device_id`),
UNIQUE (`active_device_id`),
FOREIGN KEY (`active_device_id`)
REFERENCES `device`(`id`)
) ENGINE=INNODB;
INSERT INTO user (`id`, `active_device_id`)
VALUES (1, 1), (2, 1);
-- Duplicate entry '1' for key 'active_device_id_2':
答案 3 :(得分:0)
您可以使用以下型号......
......确保:
ActiveDeviceNo
与用户位于同一行。ActiveDeviceNo
NOT NULL)。UserId
的识别关系来实现的,然后将其带回用户并且"合并"使用原始UserId
。此模型非常clustering - 非常友好。如果将PK用作集群密钥,则获取给定用户的所有设备将导致最小的I / O,因为同一用户的设备在物理上靠近在一起存储在数据库中。它自然也代表了设备的每用户顺序(如果这非常重要)。
这很简单,节省空间,但却在关键设计中强制进行某些权衡:
DeviceId
),然后从其他表中引用 it 。DeviceNo
使用自动增量,但这不是完全最优的,并且可以生成大于必要数量的数字(如果DBMS支持数字的可变长度表示,则会产生浪费空间)。 OTOH,在并发环境中找到DeviceNo
的最佳值可能有些麻烦。除此之外,您可以使用过滤/部分唯一索引,其中"是活动的" flag(正如其他人所建议的那样),或者如果你的DBMS不支持,你可以这样做:
CREATE TABLE Device (
DeviceId INT PRIMARY KEY,
UserId INT REFERENCES User (UserId),
ActiveUserId INT UNIQUE,
CHECK (ActiveUserId IS NULL OR ActiveUserId = UserId)
);
这是有效的,因为UNIQUE约束会忽略NULL值(假设您的DBMS正确处理了NULL)。