一个多表联合查询引发的思考

朋友做一个项目,遇到一个多表联合查询的需求。

  • A表SYSTEM_ID和B表SYSTEM_ID关联;
  • C表中ROLE_LIST字段,存储多个B表中的ROLE_ID值;

需要一个sql,当A表中SYSTEM_ID值为123时,找到B表和C表的关联,当B表满足SYSTEM_ID值为123时,包含其中的ROLE_ID数据,显示C表中NAME数据。例如查询结果为:james、lucy.

T_TABLE_A表

ID SYSTEM_ID
1 123
2 234

T_TABLE_B表

ID SYSTEM_ID ROLE_ID
1 222 667
2 123 555
3 123 777
4 234 567
5 234 231

T_TABLE_C表

ID NAME ROLE_LIST
1 james 667,777
2 lucy 223,555,823
3 tom 253,231
4 max 123,712
5 min 123,567

最终提供的sql如下:

select name from t_table_c c
where exists (
    select 1 from t_table_a a
    inner join t_table_b b on a.system_id = b.system_id
    where a.system_id = 123
    and c.role_list like '%' || b.role_id || '%'
)

上面的查询sql采用的exists子句的方式,采用连接的方式也能完成相同的功能,具体实现见文末附录Sql.

从给的脱敏数据可以推测出各个表的功能。

  • A表是权限(资源)表;
  • B表是角色权限(资源)表;
  • C表用户表;

一般使用单独的表来存储用户和角色的关联信息,这里很巧妙的采用以逗号分隔的方式存储多个角色编号。采用这种方式可以减少表连接,但处理存储和查询的复杂度更高。

单纯从数据上来看,由于采用的模糊查询,有可能出现错误的查询结果。

假设C表中存在以下数据。

ID NAME ROLE_LIST
6 kim 1777,2211
7 kenv 220,1555,800

重新执行sql,你会发现查询结果里面包含:kim和kenv. 造成这个结果的原因是,模糊查询可以匹配ROLE_LIST列中部分数据,1777和1555分别包含777和555.

通过这个简单示例,可以发现存储多个值时确实包含一些局限性。我们既想一列存储多个数值,又想消除歧义,那么怎么解决这个问题呢?

给存储的值添加一个前缀,也许是一个好办法,比如:r555,r777,r1777,r1555,前缀采用代表特定含义的单词或字母,加上实际的数值,可以构造出一个特殊的字符串。条件子语句:like ‘%r555‘. 可以避免示例数据中的错误查询结果问题。

等等,好像还是有点问题。如果字符串为:r55,r555,r1555,何解。

当然如果存在这种情况,我们还有一个终极解决办法(适用于任何情况):前缀+值+后缀

前缀+值+后缀

列存储示例:[55],[555],[1555]
条件子语句:like '%[55]%',这里前缀='['、值='55'、后缀=']'

一般情况下,使用特定单词或字母作为特殊前缀加取值可以满级绝大多数情况,这种方式可读信更高。而需要严格意义上的避免误查询,可以采用:前缀+值+后缀。

--附录Sql

create table t_table_a
(
    id int primary key,
    system_id int
);

create table t_table_b
(
    id int primary key,
    system_id int,
    role_id int
);

create table t_table_c
(
    id int primary key,
    name varchar2(20),
    role_list varchar2(200)
);

insert into t_table_a values(1, 123);
insert into t_table_a values(2, 234);
insert into t_table_a values(3, 100);

insert into t_table_b values(1, 222, 667);
insert into t_table_b values(2, 123, 555);
insert into t_table_b values(3, 123, 777);
insert into t_table_b values(4, 234, 567);
insert into t_table_b values(5, 234, 231);

insert into t_table_c values(1, 'james', '667,777');
insert into t_table_c values(2, 'lucy', '223,555,823');
insert into t_table_c values(3, 'tom', '253,231');
insert into t_table_c values(4, 'max', '123,712');
insert into t_table_c values(5, 'min', '123,567');
insert into t_table_c values(6, 'kim', '1777,2211');
insert into t_table_c values(7, 'kenv', '220,1555,800');

select name from t_table_c c
where exists (
    select 1 from t_table_a a
    inner join t_table_b b on a.system_id = b.system_id
    where a.system_id = 123
    and c.role_list like '%' || b.role_id || '%'
);

select c.name, b.id from t_table_a a
inner join t_table_b b on a.system_id = b.system_id
inner join t_table_c c on c.role_list like '%' || b.role_id || '%'
where a.system_id = 123;

On more thing.

这sql在Oracle中跑起来,没有什么问题。但是朋友拿去改造后在mysql中运行,出现的查询结果不正常。排查了很长一段时间,才找到原因:在mysql中 ‘%‘ || ‘S001‘ || ‘%‘ 显示打印为:1. 正确的方式是使用concat函数。所以如果你在mysql中运行,需要这样构造sql.

select c.name, b.id from t_table_a a
inner join t_table_b b on a.system_id = b.system_id
inner join t_table_c c on c.role_list like concat('%', b.role_id, '%')
where a.system_id = 123;

原文地址:https://www.cnblogs.com/amour/p/12305600.html

时间: 2024-08-29 07:27:57

一个多表联合查询引发的思考的相关文章

MyBatis 多表联合查询及优化

序 这篇文章我打算来简单的谈谈 mybatis 的多表联合查询.起初是觉得挺简单的,没必要拿出来写,毕竟 mybatis 这东西现在是个开发的都会用,而且网上的文章也是一搜罗一大堆,根本就用不着我来重复.但是吧,就我前几天在做一个多表联合查询的时候,竟然出了很多意想不到的问题,而且这些问题的出现,并不是对 mybatis 不了解,而是在用的过程中会或多或少的忽略一些东西,导致提示各种错误. 背景 老规矩,开始之前,还是要先说说这件事的背景.也就是最近几天,公司要做一个后台的管理平台,由于之前的一

两个表联合查询获取聊天表中用户最新的一条聊天数据

一个用户表,一个聊天记录表,两个表联合查询获取聊天表中用户最新的一条聊天数据 select c.contentfrom sixin as c where c.tid = a.user_idorder by ctime desc limit 0,1) as content,(select c.statusfrom sixin as c where c.tid = a.user_idorder by ctime desc limit 0,1) as status from users as a, s

MVC5+EF6简单实例---以原有SQLServer数据库两表联合查询为例

工具:VS.net2013.EF6.MVC5.SQLServer2008 参考出处: http://www.cnblogs.com/slark/p/mvc-5-get-started-create-project.html http://www.cnblogs.com/miro/p/4288184.html http://www.cnblogs.com/dotnetmvc/p/3732029.html 一.准备工作 在SqlServer上创建数据库:Element 模拟两个表并插入数据:SysU

hibernate实现多表联合查询

以前用sql实现联合查询 是非常简单的事,只需要写sql语句就可以,第一次遇到hibernate要实现多表联合查询的时候还楞了一下.最后看了下资料,才恍然大悟,hibernate实现多表联合查询跟SQL没多大差别. hibernate很多实现都是靠喜欢配关系,但是如果两张表,数据量都非常大的时候,并不合适配关系. 例如:student表和score表需要做联合查询. 1)sql: select s.id,s.name,sc.score from student as s,score as sc

Dynamic CRM 2013学习笔记(九)CrmFetchKit.js介绍:Fetchxml、多表联合查询, 批量更新

CrmFetchKit.js是一个跨浏览器的一个类库,允许通过JavaScript来执行fetch xml的查询,还可以实现批量更新,分页查询等.目前已支持Chrome 25, Firefox 19 和 IE9/10 . 它的最大优势是可以通过fetchxml 来查询,这样我们就可以实现真正的多表联合查询,虽然可以用OData终结点的$expand来进行多表的联合查询,但这种方式没办法过滤多表的条件,它只能过滤主表的条件. 下面来看下简单的多表查询的例子: 1.首先定义一个fetchxml: 1

获取多表联合查询的存储过程。

USE [NopV3.3Test] GO /****** Object: StoredProcedure [dbo].[GetPostList] Script Date: 06/18/2014 15:27:19 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: 于留洋 -- Create date: 2014/06

MyBatis 多表联合查询及优化 以及自定义返回结果集

下面就来说一下 mybatis 是通过什么来实现多表联合查询的.首先看一下表关系,如图: 这 里,我已经搭好了开发的环境,用到的是 SpringMVC + Spring + MyBatis,当然,为了简单期间,你可以不用搭前端的框架,只使用 Spring + MyBatis 就可以,外加 junit 测试即可.环境我就不带大家搭了,这里只说涉及到联合查询的操作. 设计好表之后,我用到了 mybatis 的自动生成工具 mybatis generator 生成的实体类.mapper 接口.以及 m

【Oracle】曾经的Oracle学习笔记(4-7)多表联合查询,子查询,动态条件查询

一.多表联合查询 二.子查询 三.动态条件查询 LESSON 4 Displaying Data from Multiple Tables-------------------------------------------------------- 查询s_emp表中最大的工资数,并且显示出这个最大工资数的员工名字 select last_name,max(salary)from s_emp; 多表查询 查询多张表的时候会产生笛卡尔积 为了防止笛卡尔积的产生,我们需要使用某些条件把两张表或多张

MyBatis之三:多表联合查询

在这篇文章里面主要讲解如何在mybatis里面使用一对一.一对多.多表联合查询(类似视图)操作的例子. 注:阅读本文前请先大概看一下之前两篇文章. 一.表结构 班级表class,学生表student,班级学生关系表ClassStudent. 这里一个学生只会在一个班级里面,也就是一对一的关系:一个班级有多个学生,也就是一对多的关系. 结构如下: CREATE TABLE [dbo].[Class]( [class_id] [int] NOT NULL, [class_name] [varchar