我的数据库中有一个表,该表存储有关用户可用性的信息,其中有21个可用性插槽:每周的每一天3。看起来这样:
CREATE TABLE user_availability(
id int(11) primary key increments,
user_id int(11),/*foreign key*/
day_mon tinyint(1),
day_tues tinyint(1),
day_wed tinyint(1),
day_thurs tinyint(1),
day_fri tinyint(1),
day_sat tinyint(1),
day_sun tinyint(1),
eve_mon tinyint(1),
eve_tues tinyint(1),
eve_wed tinyint(1),
eve_thurs tinyint(1),
eve_fri tinyint(1),
eve_sat tinyint(1),
eve_sun tinyint(1),
late_mon tinyint(1),
late_tues tinyint(1),
late_wed tinyint(1),
late_thurs tinyint(1),
late_fri tinyint(1),
late_sat tinyint(1),
late_sun tinyint(1)
);
这似乎是一个好主意要在应用程序而不是数据库中处理。
我的新设计是有2个表:
create table user_availabilty(
id int(11) primary key increments,
user_id int(11),/*foreign key*/
time_slot tinyint(2)/*foreign key*/
);
create table time_slots(
id tinyint(2) primary key,
name varchar(20)
);
这有什么问题吗?如果我的梦想成真,而我有成千上万的用户是每个用户中有21行的问题?
根据您的评论,我认为您可以有利地将位和位运算符用于数据。
如果您的查询看起来像是"找到我的一些时间插槽中可用的用户"或"找到所有这些时间插槽中可用的用户",那么您可以使用位置来获得该用户 - 和。
在MySQL中,位运算符是经典C运算符:&
,|
和^
。
您可以通过枚举时间插槽来构造位面具:
mon_day = 0
mon_eve = 1
mon_late = 2
tue_day = 3
tue_eve = 4
tue_late = 5
:
然后使用 (1 << X)
构建一个bitmask,其中x是任何枚举值。钻头或它们一起:
#pseudo-code
desired_times = 0
for timeslot in all-timeslots
begin
desired_times = desired_times | (1 << timeslot)
end
然后您的查询是一个位操作:
SELECT * FROM users u
WHERE
(u.availability & desired_times) = desired_times
与所需的时间(计划?(的时间完全匹配,或:
SELECT * FROM users u
WHERE
(u.availability & desired_times) != 0
检查是否完全可用。
这里的好处是它是一个快速选择,它是紧凑的(您的表定义中只有一行(,它很小(行中只有32位(,并且它是一个非常直接的映射,用于您的" Live中的类似编码"数据结构,如果有一个。完全相同的操作给出了完全相同的结果。
我的ording是不同的。让我与您分享;
create table user_availabilty(
id int(11) primary increments,
user_id int(11),/*foreign key*/
time_slot_id tinyint(2)/*foreign key*/
);
create table time_slots(
time_slot_id tinyint(2) primary,
user_id , //foreign key
type tinyint(2), // day,eve or late
day_name varchar(10) // days of week
);