引言:
今天在处理业务逻辑时,出现了一个问题:
需要做一个条件查询,分页显示的列表数据。但是,分页后查询出来的有些数据是重复的,需要去掉重复的记录。
因为,在关联表的时候,有几张的表的数据,一个id ,都是多条对应的数据。
(1)模拟实际问题:
(1)创建表结构
下面我来模拟这个实际情况:(真实的需求不能告诉你们QAQ)
其中,关联数据有三张表组成:
大致的流程是: 一篇文章,会被备份多次,即修改文章一次,备份文章一次。直到最后确定该文章不再被修改,就发表。
所以我们的备份的文章信息,肯定是一个ID(文章id),对应多条不同数据(比如我们第一次创建文章,只写了一个标题。第二次,修改了标题,写了一半内容。第三次,才真正完成,发布文章。那文章需要备份,肯定把 每一次修改记录都保存。),那我们可以设置每一次的修改为一个版本。
那我们查询的数据就是,个人中的所有文章信息的列表数据
下面模拟出来:
主文章表(TXT_INFO)
ID TXT_TYPE T_DATE
文章唯一id 文章现在状态(未编辑完毕,已编辑完毕) 文章更新时间
文章备份信息表(TXT_BFINFO)
ID IDNO TXTNAME TXTCONTENT
文章唯一id 一个文章的第几版数据 文章的名字 文章的内容
模拟一些数据:
主文章表(TXT_INFO)
文章备份信息表(TXT_BFINFO),其中我们会发现, 一个文章ID ,对应多个版本的文章数据
sql 文件:
TXTSQL.sql 保存成sql 文件,运行到 oracle 中即可使用。
prompt PL/SQL Developer import file
prompt Created on 2017年11月28日 by Administrator
set feedback off
set define off
prompt Disabling triggers for TXT_BFINFO...
alter table TXT_BFINFO disable all triggers;
prompt Disabling triggers for TXT_INFO...
alter table TXT_INFO disable all triggers;
prompt Deleting TXT_INFO...
delete from TXT_INFO;
commit;
prompt Deleting TXT_BFINFO...
delete from TXT_BFINFO;
commit;
prompt Loading TXT_BFINFO...
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('1', '1', '(1.1)Eclipse 修改背景图片(不是修改背景颜色)', '(1.1)由于近端时间,在用IDEA编辑器,在IDEA中是允许修改 背景图片的。 如:这样就可以将背景,改为这个图片背景。 在Eclipse中,好像并没有这样的设置,或者那个插件可以实现这个功能。不过,我们想实现这样的效果,那只能手动的修改Eclipse 中的设置。');
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('1', '2', '(1.2)Eclipse 修改背景图片(不是修改背景颜色)', '(2.1)由于近端时间,在用IDEA编辑器,在IDEA中是允许修改 背景图片的。 如:这样就可以将背景,改为这个图片背景。 在Eclipse中,好像并没有这样的设置,或者那个插件可以实现这个功能。不过,我们想实现这样的效果,那只能手动的修改Eclipse 中的设置。');
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('1', '3', '(1.3)Eclipse 修改背景图片(不是修改背景颜色)', '(3.1)由于近端时间,在用IDEA编辑器,在IDEA中是允许修改 背景图片的。 如:这样就可以将背景,改为这个图片背景。 在Eclipse中,好像并没有这样的设置,或者那个插件可以实现这个功能。不过,我们想实现这样的效果,那只能手动的修改Eclipse 中的设置。');
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('2', '1', '(2.1)如何开发微信小程序(一)个人开发者该如何测试开发小程序', '(2.1)微信小程序入门(一)论个人开发者怎么测试开发小程序 微信小程序,可谓最近比较火的话题,我也对小程序充满好奇,所以就准备试试怎么开发小程序。 【1】如何获得开发权限? 大家肯定想的是,进入微信小程序开发平台,然后注册就可以了,基本就是这样。 主要流程看百度经验这篇文章即可,但是其中你会发现,现在的微信小程序是不允许个人开...');
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('2', '2', '(2.2)如何开发微信小程序(一)个人开发者该如何测试开发小程序', '(2.2)微信小程序入门(一)论个人开发者怎么测试开发小程序 微信小程序,可谓最近比较火的话题,我也对小程序充满好奇,所以就准备试试怎么开发小程序。 【1】如何获得开发权限? 大家肯定想的是,进入微信小程序开发平台,然后注册就可以了,基本就是这样。 主要流程看百度经验这篇文章即可,但是其中你会发现,现在的微信小程序是不允许个人开...');
insert into TXT_BFINFO (id, idno, txtname, txtcontent)
values ('3', '1', '(3)如何开发微信小程序(一)个人开发者该如何测试开发小程序', '(3)微信小程序入门(一)论个人开发者怎么测试开发小程序 微信小程序,可谓最近比较火的话题,我也对小程序充满好奇,所以就准备试试怎么开发小程序。 【1】如何获得开发权限? 大家肯定想的是,进入微信小程序开发平台,然后注册就可以了,基本就是这样。 主要流程看百度经验这篇文章即可,但是其中你会发现,现在的微信小程序是不允许个人开...');
commit;
prompt 6 records loaded
prompt Loading TXT_INFO...
insert into TXT_INFO (id, txt_type, t_date)
values ('1', '未编辑完毕', to_date('01-11-2017', 'dd-mm-yyyy'));
insert into TXT_INFO (id, txt_type, t_date)
values ('2', '未编辑完毕', to_date('13-11-2017', 'dd-mm-yyyy'));
insert into TXT_INFO (id, txt_type, t_date)
values ('3', '已编辑完毕', to_date('14-11-2017', 'dd-mm-yyyy'));
commit;
prompt 3 records loaded
prompt Enabling triggers for TXT_BFINFO...
alter table TXT_BFINFO enable all triggers;
prompt Enabling triggers for TXT_INFO...
alter table TXT_INFO enable all triggers;
set feedback on
set define on
prompt Done.
(2)一般分页查询:
查询第一页的数据 1 到 10 行
SELECT
*
FROM
(
SELECT
ROWNUM AS RN,
A.ID,
A.TXT_TYPE,
B.TXTNAME,
B.TXTCONTENT
FROM
TXT_INFO A
LEFT JOIN TXT_BFINFO B ON A.ID = B.ID
)
WHERE
RN <= '10'
AND RN >= '1'
查看查询结果:出现重复元素。我们想要的元素,只有箭头指向记录。
我们只想获取最新一次修改过的文章信息。不需要显示以前的版本。
(2)解决思路:
第一种:使用 DISTINCT 来去除重复元素
第二种:使用 GROUP BY 分组,去除重复元素
DISTINCT :
通常只会对,所查字段,每个字段都重复的行,去除。
例子:
select distinct ID from TXT_BFINFO ;
我们只查 id 这个字段,的确把重复的除去 了。
那我们查询两个字段:ID 和TXTNAME(文章名称),依然不会除去重复元素
GROUP BY: 分组
如果只使用 GROUP BY 分组,的确会把分组的字段,重复的元素去掉。group by 在自然处理的时候,会自动去除重复元素。
那可以想一下,我们需要查询的就是 TXT_BFINFO(文章备份信息表) 的不重复的数据。 那我们可以根据 文章id 分组,但是group by, 查询的元素,必须是分组的字段,不能有其他字段。
例子:
select ID,MAX(IDNO) from TXT_BFINFO group by ID ;
这样写,没有问题。但是我们需要获取每一条完整的数据。就出现错误。这也就是上面说的,查询的元素,要么是分组的字段,要么是组函数(组函数,通常就是AVG(), MAX() , COUNT(), MIN(),SUM() 这样的多行函数)。
select ID,MAX(IDNO),TXTNAME from TXT_BFINFO group by ID ;
所以,改写这个,我们将分组的字段变为多个。但是,分组的字段改为了多个,所以它以 ID 和 TXTNAME 一起分组。肯定查询出的数据 ,不是我们想要的
select ID,MAX(IDNO),TXTNAME from TXT_BFINFO group by ID,TXTNAME;
或许需要换一个思路:
建议参考
我们可以先查询(TXT_BFINFO )文章备份信息表 重复元素的记录(只留一条),然后把查询结果当做一张表再与别的表关联,并且我们是多个字段才能确定一条记录,由ID(文章id) 和 IDNO(版本) 确定。
select * from TXT_BFINFO a where (a.Id,a.idno) in(select id,MAX(idno) from TXT_BFINFO group by Id having count(*) > 1)
查询结果:
还不太正确,因为这里查的只是重复记录(即有多条的记录),那么没有只有一条的记录没有。 只需要将 count(*) > =1 即可。
select * from TXT_BFINFO a where (a.Id,a.IDNO) in(select Id,MAX(Idno) from TXT_BFINFO group by Id having count(*) >= 1)
(3)最终查询
SELECT
*
FROM
(
SELECT
ROWNUM AS RN,
A.ID,
A.TXT_TYPE,
B.TXTNAME,
B.TXTCONTENT
FROM
TXT_INFO A
LEFT JOIN ( // 修改连接的表 为查询后的数据
SELECT
*
FROM
TXT_BFINFO a
WHERE
(a.Id, a.IDNO) IN (
SELECT
Id,
MAX(Idno)
FROM
TXT_BFINFO
GROUP BY
Id
HAVING
count(*) >= 1
)
) B ON A.ID = B.ID
)
WHERE
RN <= '10'
AND RN >= '1'
查询结果: