【mysql】GROUP_CONCAT列转行更新FIND_IN_SET多表查询数据

 

前两天遇到这么一种情况,线上有两张表,一张xt_role(角色表),一张xt_menu(菜单表)。显而易见,一个角色可以有多个菜单,一个菜单也可以给多个角色,多对多关系。正常应该是这样:

fee4c8f0cac9406da48f747791b917c8.png

但实际情况:

角色表:

1e21b2e643944b6b888c609aac76d6cf.png

菜单表:

f51de2c393624995a6c112bfaaf18705.png

ER图:

cf1ae96d9ef04f40bf00fa77acf9a0b1.png

冗余存储,数据用逗号隔开。页面查询角色(xt_role)展示角色拥有的菜单,数据取的角色表菜单名称(xt_role.menu_nams),没去关联查询菜单表(xt_menu)

一切都在有条不紊的进行,直到某一天有人打破了这种平衡。修改了菜单名称,角色里面的名称怎么没有变,好家伙,这么多年的项目现在角色里面的名称全错了。。。

方法有很多,下点心思重构,权限模型很简答套用就行,功能也不复杂。再简单些,查出来角色,再去匹配查询菜单,快速解决问题,也不会有人发现。

2d233d90b4f74e989b025b62cbaf2caa.jpeg

那我们这个数据已经出现了,虽然数据意义不大,但你发现了这事仿佛就看见它开始在那偷偷闪光。行吧,好机会写写sql 盘了。

三步走,开冰箱,放大象,关冰箱。 

步骤一:  

先将两个表进行关联查询。

 FIND_IN_SET:MySQL 中的函数,‌用于在字符串列表中查找一个字符串的位置

SELECT
	xm.id 菜单表id ,
	xm.`name` 菜单表名称,
	xr.id 角色表 ,
	xr.NAME 角色表名称,
	xr.menu_ids 角色表菜单id ,
	xr.menu_names 角色表菜单名称
FROM
	xt_role xr
	LEFT JOIN xt_menu xm ON FIND_IN_SET( xm.id, xr.menu_ids ) > 0 order by xr.id

4ca76d78560a4d26bfff52ca416c3b1d.png

结果很清晰,角色2001(管理员)有四个菜单(1001,1003,1003,1004),角色2002(工单审核员)有两个菜单(1001,1002)

步骤二:

要更新xt_role.menu_names(角色表菜单名称),[工单审核]为[工单审核名称变了],那就要先把数据变成一行(工单审核名称变了,已完结工单,工单流程设置,字典配置)才能更新。

GROUP_CONCAT 是 MySQL 中的一个聚合函数,‌用于将多个列的字段值连接为一个字符串结果。‌

SELECT
	xr.id 角色表id,
	GROUP_CONCAT( xm.NAME ORDER BY xm.id ASC SEPARATOR ',' ) 菜单表名称
FROM
	xt_role xr
	LEFT JOIN xt_menu xm ON FIND_IN_SET( xm.id, xr.menu_ids ) > 0 
GROUP BY
	xr.id

d223522fd26c43928800bddc27144149.png

好了,现在我们要的结果已经出来了。可以用菜单表名称去刷新角色表了。

步骤三:

第三步就是update关联更新,将步骤二作为一个结果集就可以了。

UPDATE xt_role a 
SET a.menu_names = (
	SELECT
		mname 
	FROM
		(
		SELECT
			xr.id mid,
			GROUP_CONCAT( xm.NAME ORDER BY xm.id ASC SEPARATOR ',' ) mname 
		FROM
			xt_role xr
			LEFT JOIN xt_menu xm ON FIND_IN_SET( xm.id, xr.menu_ids ) > 0 
		GROUP BY
			xr.id 
		) mview 
	WHERE
		mview.mid = a.id 
	)

2c96224bfb344478a2e7b8ad6773e03c.png

 更新成功!

啰嗦了。。会玩的就是直接一个sql,这里分开写,像这种多表关联更新、GROUP_CONCAT、FIND_IN_SET函数应该就能掌握了。

附数据库:

DROP TABLE IF EXISTS `xt_menu`;
CREATE TABLE `xt_menu`  (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'uuid',
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称',
  `deleted` bit(1) NULL DEFAULT NULL COMMENT '是否删除',
  `status` int(11) NULL DEFAULT NULL COMMENT '状态:禁用 启用',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `UQ_menu_id`(`id`) USING BTREE,
  INDEX `isdeleted`(`deleted`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色信息表 说明:该表属于字典表,用于存储 角色类型 的信息' ROW_FORMAT = DYNAMIC;

-- ----------------------------
INSERT INTO `xt_menu` VALUES ('1001', '工单审核名称变了', b'0', NULL);
INSERT INTO `xt_menu` VALUES ('1002', '已完结工单', b'0', NULL);
INSERT INTO `xt_menu` VALUES ('1003', '工单流程设置', b'0', NULL);
INSERT INTO `xt_menu` VALUES ('1004', '字典配置', b'0', NULL);
-- ----------------------------
DROP TABLE IF EXISTS `xt_role`;
CREATE TABLE `xt_role`  (
  `id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'uuid',
  `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '组名',
  `menu_ids` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '包含菜单的id集合',
  `menu_names` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '包含菜单名称的集合',
  `status` int(11) NULL DEFAULT NULL COMMENT '状态:禁用 启用',
  `deleted` bit(1) NULL DEFAULT NULL COMMENT '是否已删除',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE INDEX `UQ_role_id`(`id`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户组信息表 说明:该表存储用户所属哪一 角色组 的基本信息' ROW_FORMAT = DYNAMIC;
-- ----------------------------
INSERT INTO `xt_role` VALUES ('2001', '管理员', '1001,1002,1003,1004', '工单审核,已完结工单,工单流程设置,字典配置', NULL, b'0');
INSERT INTO `xt_role` VALUES ('2002', '工单审核员', '1001,1002', '工单审核,已完结工单', NULL, b'0');

 

 

 

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mrk_java

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值