问题痛点:
不妨假设有如下三个表:
A表
aid | number |
aname | varchar(100) |
aweight | number |
B表
bid | number |
bname | varchar(100) |
bweight | number |
C表
cid | number |
cname | varchar(100) |
cweight | number |
我们需要如下查询语句:
select * from A full join B on a.aid = b.bid full join C on a.aid=c.cid
由于使用full join所以肯定存在A表有数据B表没有数据或者B表有数据A表没有数据的情况。
如果我们希望A表有数据时取A的aid,如果A没有数据取B的bid,如果A、B表都没有数据取C表的cid
此处一般需要采用case when等语句进行处理。
现在欲在代码层面进行处理,同时避免full join语句
1.SQL语句改为:
select 1 as num, A.aid, A.aname as n,A.aweight as amount from A
union all
select 2 as num, B.* from B
union all
select 3 as num, C.* from C
语句查询后出现记录应该有:
num | aid | n | amount | 备注 |
1 | 1000 | 测试 | 12 | A表记录 |
2 | 1000 | 测试 | 123 | B表记录 |
3 | 1000 | 测试 | 2344 | C表记录 |
............
List
经过上面转换后变为:
aid: 1000 n1:测试 amount1:12
aid:1000 n2:测试 amount2:123
aid:1000 n3:测试 amount3:2344
............
//结果集合并
Set set = new HashSet();
resultList = middleChangeList.stream().collect(Collectors.groupingBy(o -> {
// 暂存所有key
set.addAll(o.keySet());
for (int index = 1; index < 4; index++) {
set.add("n" + index); //方便对没有数据的记录补0
set.add("amount" + index); //方便对没有数据的记录补0
}
return o.get("aid");
})).entrySet().stream().map(o -> {
// 合并
Map map = o.getValue().stream().flatMap(m -> {
return m.entrySet().stream();
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b));
// 为没有key的赋值0
set.stream().forEach(k -> {
if (!map.containsKey(k))
map.put(k, 0);
});
return map;
}).sorted((map1, map2) -> {
return map1.get("aid").toString().compareTo(map2.get("aid").toString()); //根据aid进行排序
}).collect(Collectors.toList());
经过上面转换后:
aid:1000 n1:测试 amount1:12 n2:测试 amount2:123 n3:测试 amount3:2344
........................................
此时基本达到要求了。
提高:
添加每一列合计代码:
Map totalMap = new HashMap();
for (int index = 1; index < 3; index++) {
final int dIndex = index;
totalMap.put("amount" + index, resultList.stream().collect(Collectors.summingDouble(
e -> Double.parseDouble(e.get("amount" + dIndex).toString()))));
}
totalMap.put("topic", "总计");
//添加合并结果集
resultList.add(totalMap);