前言
首先说明一下场景啊,今天遇到个业务问题,就是通过一个主表,关联另一个表,主表中一条数据,关联出另外一张表多条数据,导致主表也生成了多条重复数据。但我页面展示的时候不希望展示出重复数据。这是我们的业务需求,现在我们来看看有多少方法来解决这个问题。
注:这块可不是数组去重,关于集合数组去重的方法参考。
为了便于理解,我先把模拟一下数据。
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(0) NOT NULL,
`equalDate1` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`equalDate2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`equalDate3` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`age` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (1, '相同数据1', '相同数据2', '相同数据3', '张三', 10);
INSERT INTO `student` VALUES (2, '相同数据1', '相同数据2', '相同数据3', '李四', 12);
INSERT INTO `student` VALUES (3, '相同数据1', '相同数据2', '相同数据3', '王五', 10);
INSERT INTO `student` VALUES (4, '相同数据1', '相同数据2', '相同数据3', '王麻子', 10);
INSERT INTO `student` VALUES (5, '相同数据11', '相同数据21', '相同数据31', '张三1', 10);
INSERT INTO `student` VALUES (6, '相同数据11', '相同数据21', '相同数据31', '张三2', 10);
SET FOREIGN_KEY_CHECKS = 1;
CREATE TABLE `student` (
`id` int NOT NULL,
`equalDate1` varchar(20) DEFAULT NULL,
`equalDate2` varchar(255) DEFAULT NULL,
`equalDate3` varchar(20) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
select * from student;
INSERT INTO student (id,equalDate1,equalDate2,equalDate3,`name`,age)
VALUES(1,"相同数据1", "相同数据2", "相同数据3","张三",10),
(2,"相同数据1", "相同数据2", "相同数据3","李四",12),
(3,"相同数据1", "相同数据2", "相同数据3","王五",10),
(4,"相同数据1", "相同数据2", "相同数据3","王麻子",10),
(5,"相同数据11", "相同数据21", "相同数据31","张三1",10),
(6,"相同数据11", "相同数据21", "相同数据31","张三2",10)
select equalDate1,equalDate2,equalDate3
,GROUP_CONCAT(`name`)as nameList,GROUP_CONCAT(`age`)as ageList
from student GROUP BY equalDate1,equalDate2,equalDate3
CREATE TABLE `studentleft` (
`id` int NOT NULL,
`tableid` int NOT NULL,
`name` varchar(20) DEFAULT NULL,
`age` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
select * from studentleft;
INSERT INTO studentleft (id,tableid,`name`,age)
VALUES(1,1, "张三",10),
(2,1,"李四",12),
(3,1,"王五",10),
(4,1,"王麻子",10),
(5,2,"张三1",10),
(6,2,"张三2",10)
select s.equalDate1,s.equalDate2,s.equalDate3 from student s where s.tableid = 1;
select l.`name`,l.age from studentleft l where l.tableid = 1;
select s.equalDate1,s.equalDate2,s.equalDate3,l.`name`,l.age
from student s ,studentleft l where s.tableid = l.tableid and s.tableid = 1
实现功能 主表一条数据关联后产生多条数据,现在就想要展示一条数据。
我们先说笨办法 list、map 方法。现实实现不建议这么玩,这里只是学习一下思维,这块还折腾了我前后4个来小时,还是记录一下编码过程
这块我没有连接数据库查,我就模仿了一下查到的集合数
package test;
import java.util.List;
/**
* @version: V1.0
* @author: p
* @description:
* @date:2022/4/1
*/
public class Student {
//这样相同数据 就展示一条 (把多条年龄、姓名用List接收)
public String equalDate1;//相同数据
public String equalDate2;//相同数据
public String equalDate3;//相同数据
public String name;
public int age;
public String stringAge;
public List ageList; //存放年龄集合
public List nameList; //拿到姓名集合
public Student() {
}
public Student(String equalDate1, String equalDate2, String equalDate3, String name, int age) {
this.equalDate1 = equalDate1;
this.equalDate2 = equalDate2;
this.equalDate3 = equalDate3;
this.name = name;
this.age = age;
}
public Student(String equalDate1, String equalDate2, String equalDate3, String name,String stringAge) {
this.equalDate1 = equalDate1;
this.equalDate2 = equalDate2;
this.equalDate3 = equalDate3;
this.name = name;
this.stringAge = stringAge;
}
public String getStringAge() {
return stringAge;
}
public void setStringAge(String stringAge) {
this.stringAge = stringAge;
}
public String getEqualDate1() {
return equalDate1;
}
public void setEqualDate1(String equalDate1) {
this.equalDate1 = equalDate1;
}
public String getEqualDate2() {
return equalDate2;
}
public void setEqualDate2(String equalDate2) {
this.equalDate2 = equalDate2;
}
public String getEqualDate3() {
return equalDate3;
}
public void setEqualDate3(String equalDate3) {
this.equalDate3 = equalDate3;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getAgeList() {
return ageList;
}
public void setAgeList(List ageList) {
this.ageList = ageList;
}
public List getNameList() {
return nameList;
}
public void setNameList(List nameList) {
this.nameList = nameList;
}
}
方法一: List 不建议使用
package test;
import java.util.ArrayList;
import java.util.List;
/**
* @version: V1.0
* @author: p
* @description:
* @date:2022/4/1
*/
public class TestCollByList {
public static void main(String[] args) {
//合并相同数据之 使用 list实现
//下面是模拟合并 代码调试了3个来小时,注意旗帜判断 跟 i-- 以及最后在保存一次 不容有失
Student student1 = new Student("相同数据1", "相同数据2", "相同数据3", "张三", 10);
Student student2 = new Student("相同数据1", "相同数据2", "相同数据3", "李四", 12);
Student student3 = new Student("相同数据1", "相同数据2", "相同数据3", "王五", 10);
Student student4 = new Student("相同数据1", "相同数据2", "相同数据3", "王麻子", 10);
Student student5 = new Student("相同数据11", "相同数据21", "相同数据31", "张三1", 10);
Student student6 = new Student("相同数据11", "相同数据21", "相同数据31", "张三2", 10);
//首先说明一下 前三个数据是一致的 不一致的只是后面2个 像上面6条数据 按照我们需求其实就两条数据 ,
// 也就是我们要合并前3项的结果为一条,后面两条变成一个两个List返回 也是我们的需求
List<Student> studentList = new ArrayList<>();
List<Student> studentListNew = new ArrayList<>();
studentList.add(student1);
studentList.add(student2);
studentList.add(student3);
studentList.add(student4);
studentList.add(student5);
studentList.add(student6);
String flag = "";
List listName = new ArrayList();
List listAge = new ArrayList();
int size = studentList.size();
for (int i = 0; i < size; i++) {
if (i == 0) {
flag = studentList.get(0).getEqualDate1();
}
//String falgType = studentList.get(i).getEqualDate1();
if (flag.equals(studentList.get(i).getEqualDate1())) {
listAge.add(studentList.get(i).getAge());
listName.add(studentList.get(i).getName());
//这里也必须放个旗帜判断
flag = studentList.get(i).getEqualDate1();
} else {
Student student = new Student();
student.setEqualDate1(studentList.get(i - 1).getEqualDate1());
student.setEqualDate2(studentList.get(i - 1).getEqualDate2());
student.setEqualDate3(studentList.get(i - 1).getEqualDate3());
student.setAgeList(listAge);
student.setNameList(listName);
studentListNew.add(student);
//下面必须清空上次保留的历史信息
listName = new ArrayList();
listAge = new ArrayList();
//这个旗帜判断必须放这里不被下面 i--影响
flag = studentList.get(i).getEqualDate1();
i--;//这步很关键,因为走else 就走不了if i又在自增,你满足if时就少一条
}
//这个是最后一步保存下来,
if (i == size-1) {
Student student = new Student();
student.setEqualDate1(studentList.get(i - 1).getEqualDate1());
student.setEqualDate2(studentList.get(i - 1).getEqualDate2());
student.setEqualDate3(studentList.get(i - 1).getEqualDate3());
student.setAgeList(listAge);
student.setNameList(listName);
studentListNew.add(student);
}
}
}
}
方法二: Map 不建议使用
package test;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* @version: V1.0
* @author: p
* @description:
* @date:2022/4/1
*/
public class TestCollByMap {
public static void main(String[] args) {
//合并相同数据之 使用 Map实现 map特点 同key覆盖 跟list逻辑一样
Student student1 = new Student("相同数据1", "相同数据2", "相同数据3", "张三", 10);
Student student2 = new Student("相同数据1", "相同数据2", "相同数据3", "李四", 12);
Student student3 = new Student("相同数据1", "相同数据2", "相同数据3", "王五", 10);
Student student4 = new Student("相同数据1", "相同数据2", "相同数据3", "王麻子", 10);
Student student5 = new Student("相同数据11", "相同数据21", "相同数据31", "张三1", 10);
Student student6 = new Student("相同数据11", "相同数据21", "相同数据31", "张三2", 10);
//首先说明一下 前三个数据是一致的 不一致的只是后面2个 像上面6条数据 按照我们需求其实就两条数据 ,
// 也就是我们要合并前3项的结果为一条,后面两条变成一个两个List返回 也是我们的需求
List<Student> studentList = new ArrayList<>();
Map map = new LinkedHashMap();//有序,保留原有顺序
List<Map> all = new ArrayList<>();
studentList.add(student1);
studentList.add(student2);
studentList.add(student3);
studentList.add(student4);
studentList.add(student5);
studentList.add(student6);
String flag = "";
List listName = new ArrayList();
List listAge = new ArrayList();
int size = studentList.size();
for (int i = 0; i < size; i++) {
if (i == 0) {
flag = studentList.get(0).getEqualDate1();
}
if (flag.equals(studentList.get(i).getEqualDate1())) {
listAge.add(studentList.get(i).getAge());
listName.add(studentList.get(i).getName());
//这里也必须放个旗帜判断
flag = studentList.get(i).getEqualDate1();
map.put("equalDate1",studentList.get(i).getEqualDate1());
map.put("equalDate2",studentList.get(i).getEqualDate2());
map.put("equalDate3",studentList.get(i).getEqualDate3());
map.put("ageList",listAge);
map.put("nameList",listName);
} else {
//下面必须清空上次保留的历史信息
listName = new ArrayList();
listAge = new ArrayList();
all.add(map);
map = new LinkedHashMap();//todo 防止同名覆盖问题 很关键
//这个旗帜判断必须放这里不被下面 i--影响
flag = studentList.get(i).getEqualDate1();
i--;//这步很关键,因为走else 就走不了if i又在自增,你满足if时就少一条
}
//这个是最后一步保存下来,
if (i == size-1) {
all.add(map);
}
}
}
}
方法三: sql实现 最简单 不用动脑、推荐使用
package test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @version: V1.0
* @author: p
* @description:
* @date:2022/4/1
*/
public class TestCollBySql {
public static void main(String[] args) {
//合并相同数据之 使用 sql实现 最简单 不用动脑
//我们通过sql中的 group_concat()函数,把数据直接干到一条, 把姓名,年龄 用,分割
//现在如果说前端来处理的话后端已经完事了,如果前端不想处理,让我们反对应的list
Student student1 = new Student("相同数据1", "相同数据2", "相同数据3", "张三,李四,王五,王麻子", "10,12,10,10");
Student student5 = new Student("相同数据11", "相同数据21", "相同数据31", "张三1,张三2", "10,10");
//首先说明一下 前三个数据是一致的 不一致的只是后面2个 像上面6条数据 按照我们需求其实就两条数据 ,
// 也就是我们要合并前3项的结果为一条,后面两条变成一个两个List返回 也是我们的需求
List<Student> studentList = new ArrayList<>();
studentList.add(student1);
studentList.add(student5);
for (Student student : studentList) {
String[] splitAge = student.getStringAge().split(",");
String[] splitName = student.getName().split(",");
student.setNameList(Arrays.asList(splitName));
student.setAgeList(Arrays.asList(splitAge));
}
System.out.println(studentList);
}
}
方法四,推荐使用
这块我不在再写具体操作,因为我就是用这个解决问题的,现在时间也很晚了就不再写了。
思想:我们两张表分开查,我们查出主表所有数据,我们前面说过,主表数据是不重复的,通过主表关联id去查另外一张表,查出它的集合,然后在 主表定义对应的list字段 来接受查出来的list。可能光这么描述看不太懂,我随后赋个截图吧。
select s.equalDate1,s.equalDate2,s.equalDate3
from student s where s.tableid = 1;
select l.`name`,l.age from studentleft l where l.tableid = 1;
一条数据拆分多条数据
(正常来说我们查出来的数据就是多条的,不需要做处理就是一对多)
既然有多对一,就有一对多,比如导出数据的时候,我就需要把你合并为1条的数据拆分好几条,然后再利用表格合并相同数据。
这块方法也很多,我就不 一 一 列举了,
上面这么写返回的参数形式有些恶心,进行如下优化
其实也不是多么恶心,只不过是都放在一个类中的对应list里,无伤大雅
同样是返回两条数据,这么看起来层次感就很好