有个规则表,需要判断规则适用于星期几
是采用方式 1 这种反范式的方式,还是创建一张一对多关联表的方式
CREATE TABLE `xx_rule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT '' COMMENT '规则内容(这个字段不是重点)',
`week` varcahr(255) DEFAULT '' COMMENT '(重点字段)规则适用于星期几;逗号分割,如果星期一到星期天都适用则填:1,2,3,4,5,6,7',
PRIMARY KEY (`id`)
);
CREATE TABLE `xx_rule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` varchar(255) DEFAULT '' COMMENT '规则内容(这个字段不是重点)',
PRIMARY KEY (`id`)
);
CREATE TABLE `xx_rule_week` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`rule_id` int(11) DEFAULT 0 COMMENT '规则表 ID',
`week` int(11) DEFAULT 0 COMMENT '规则适用于星期几;填 1 表示星期一',
PRIMARY KEY (`id`)
);
1
ChoateYao 2021-04-20 11:44:46 +08:00 4
用位运算来存储星期,当需要检索是否包含某个星期的时候,先通过代码计算出所有包含该星期的数值,然后进行 IN 操作。
如果只是用于调试查询,可以在 SQL 中直接用位运算进行检索。 |
3
bluekz 2021-04-20 11:47:16 +08:00
你的业务需求有:
“查询适合星期 5 的所有规则”吗?如果有,方式 1 怎么办? |
4
yuann72 OP @bluekz
select * from xx_rule where FIND_IN_SET('5',week) select * from xx_rule where week like '%5%' |
5
ChoateYao 2021-04-20 11:54:07 +08:00 1
@yuann72 这是必然的,但是你可以用 bin 函数来解决这个问题,把 10 进制转换成二进制,然后看非 0 的位置这样子就能快速直观的了解到是否包含某个星期了,跟你第一个方案一样。
|
6
yuann72 OP @bluekz
一般每个代理商下的规则行数都是个位数, 经过 where agent_id=1 条件过滤后的行数是个位数,所以我认为性能不会太慢,我自己还是倾向方式一 select * from xx_rule where agent_id=1 AND week like '%5%' 完整一点的表结构是这样的: 多出来一个 agent_id CREATE TABLE `xx_rule` ( `id` int(11) NOT NULL AUTO_INCREMENT, `agent_id` int(11) DEFAULT 0 COMMENT '代理商的 ID', `content` varchar(255) DEFAULT '' COMMENT '规则内容(这个字段不是重点)', `week` varcahr(255) DEFAULT '' COMMENT '(重点字段)规则适用于星期几;逗号分割,如果星期一到星期天都适用则填:1,2,3,4,5,6,7', PRIMARY KEY (`id`) ); |
7
markgor 2021-04-20 12:06:10 +08:00
如果是答题的话,我觉得 1 是最佳的选择。
如果是实际应用的话,我觉得 2 是最好的选择。 当哪一天规则改变的时候,2 的扩展代价相对低。 |
8
Rache1 2021-04-20 12:43:02 +08:00
就要看这个表增长了,如果表增长快,那第一种方案走不到索引上去,可就难受了
|
9
EscYezi 2021-04-20 12:46:53 +08:00 via iPhone
还有个方法是,建七个字段表示 1-7,比位运算看起来直观些,就是字段太多🌚
|
10
pkupyx 2021-04-20 13:31:41 +08:00
第一种就不能整个 byte,按 bit 来判断星期几么。。。
|
11
raaaaaar 2021-04-20 13:39:40 +08:00 via Android
怎么说呢,其实两种都能行,主要看你对这个的操作还有表的规模,如果对规则内容操作得少的话,第二种应该要好点
|
12
buster 2021-04-20 13:40:17 +08:00
实际存储可以使用 Bit 位或者 1,....,7 来做都行,倒是可以在从 DB 取到数据之后映射入实体对象类,新建一个属性(枚举类,list 。。。),针对这个数据再解析出星期的数据
|
13
liuky 2021-04-20 13:41:20 +08:00
第一方案, week 换乘 int, 周一到周日改成 2^n 表示(1,2,4,8,16,32,64,128), 然后按位(& | ^)进行运算就好了, 数据库也是支持位运算的
|
14
liuky 2021-04-20 13:47:19 +08:00 1
@liuky
select * from xx_rule where week & 2 = 2 , 就可以查出是否具有 2 这个权限 1 | 2 | 4 | 8 等于 15 select * from xx_rule where week & 15 = 15 , 就可以查出是否具有 1 | 2 | 4 | 8 这个权限 同理添加也是一样 update xx_rule set week = week | 2 就可以添加 2 这个权限 |
15
maocat 2021-04-20 13:47:57 +08:00
和上面一样的想法,七位二进制,1111111, 每一位为 1 表示对应的天数是存在的
|
16
SjwNo1 2021-04-20 14:02:13 +08:00
如果你的操作仅限于单条数据判断,可以用二进制,否则 find_in_set 较好一点感觉
|
17
play78 2021-04-20 14:03:04 +08:00
主要靠是否经常查询和变动。也可以写成这样
``` create table xx_rule( id int, content varchar, sun int(2), mon int(2), tue int(2), wed int(2), thu int(2), fri int(2), sat int(2) ); ``` |
19
bluekz 2021-04-20 17:39:27 +08:00
@yuann72
一般每个代理商下的规则行数都是个位数, 经过 where agent_id=1 条件过滤后的行数是个位数,所以我认为性能不会太慢,我自己还是倾向方式一 这样的话,方案 1 我是觉得没什么致命大错。 就是不"方便扩展"。 |
20
25OHd2qObJmJ6P10 2021-04-20 18:25:09 +08:00
大兄弟,
EVERYDAY(0,"每天"), MONDAY(1,"星期一"), TUESDAY(2,"星期二"), WEDNESDAY(4,"星期三"), THURSDAY(8,"星期四"), FRIDAY(16,"星期五"), SATURDAY(32,"星期六"), SUNDAY(64,"星期天"), 一个枚举解决,定时任务每天获取当前是星期几,然后和数据库与预算,匹配到就需要做任务 |
21
nine 2021-04-20 19:43:20 +08:00
换 PostgreSQL 吧,array 类型解决你烦恼。
|
22
akira 2021-04-20 22:01:33 +08:00
CREATE TABLE `xx_rule_week` (
`id` int(11) NOT NULL AUTO_INCREMENT, `rule_id` int(11) DEFAULT 0 COMMENT '规则表 ID', `sunday` int(11) DEFAULT 0 COMMENT '周日规则是否启用', `monday` int(11) DEFAULT 0 COMMENT 周一'规则是否启用', `tuesday` int(11) DEFAULT 0 COMMENT '周二规则是否启用', ... `satday` int(11) DEFAULT 0 COMMENT '周六规则是否启用', PRIMARY KEY (`id`) ); |