java实现类SQL的join操作
SQL是结构化查询语⾔的简称,给数据库操作带来很⼤的⽅便。
随着⼤数据的流⾏,hive、spark、flink都开始⽀持SQL的操作。
但在java内部并没有对SQL操作的⽀持,使⽤java stream API进⾏数据关联操作的代码惨不忍睹。
因此,我基于Google guava的Table,封装了常⽤的join操作。分享并记录在这⾥。
⽬前⽀持的join类型包括如下⼏类,基本上常见的join都已经覆盖到了。
public enum JoinStrategy {
INNER_JOIN,//内连接
LEFT_JOIN,//左连接
RIGHT_JOIN,//右连接
LEFT_SEMI_JOIN,//左半连接,结果只取左表,连接条件是左表和右表的交集
LEFT_ANTI_JOIN,//左半连接,结果只取左表,连接条件是左表与右表的差集
FULL_JOIN;//全连接
}
闲⾔少叙,下⾯就是JoinUtils的硬代码
⼀、构造Table对象
由于⼤部分⼈拿到的数据要么并不是Table类型,所以我⾸先提供了从这两个对象转Table对象的⽅法
由于从jdbc查出来的数据,默认格式就是⼀个List<Map<>>,下⾯这个createTable⽅法可以将List<Map<>>⽣成⼀个Table对象因为我们后⾯要进⾏join操作,所以需要提供⼀个id作为每⼀⾏的rowKey.
/**
* 基于List<Map>创建⼀个表对象,将使⽤⽤户提供的id的在map中对应的value值作为rowKey
*
* @param listMap
* @param id
* @param <R>
* @param <C>
* @param <V>
* @return
*/
public static <R, C, V> Table<R, C, V> createTable(List<Map<C, V>> listMap, R id) {
Table<R, C, V> table = ate();
for (Map<C, V> map : listMap) {
for (Map.Entry<C, V> entry : Set()) {
table.put((R) (id), Key(), Value());
}
}
return table;
}
有些情况下,我们的数据并不是List<Map<>>,⽽是别⼈给我们传递的⼀组对象,这个情况我也考虑到了。
下⾯是⼀个从List<T>对象⽣成Table对象的⽅法。
public static <T, R, C, V> Table<R, C, V> createTable(List<T> objects, Class<T> aClass, String primaryKey) {
Table<R, C, V> table = ate();
List<String> fieldNames = getFieldNames(aClass);
for (T t : objects) {
Object primaryKeyValue = getFieldValue(aClass, t, primaryKey);
for (String field : fieldNames) {
Object fieldValue = getFieldValue(aClass, t, field);
table.put((R) primaryKeyValue, (C) field, (V) fieldValue);
}
}
return table;
}
⼆、join操作
对外我暴露了⼀个join⼯⼚⽅法,⽤来基于⽤户提供的策略选择不同的底层实现来操作。
public static <R, C, V> Table<R, C, V> join(Table<R, C, V> left, Table<R, C, V> right, JoinStrategy strategy) {
switch (strategy) {
case LEFT_JOIN:
return leftJoin(left, right);
case LEFT_SEMI_JOIN:
return leftSemiJoin(left, right);
case LEFT_ANTI_JOIN:
return leftAntiJoin(left, right);
case FULL_JOIN:
return fullJoin(left, right);
default:
return innerJoin(left, right);
}
}
测试⼀下
//测试代码:
class JoinUtilsTest {
private Table<String, String, Object> leftTable;
private Table<String, String, Object> rightTable;
@BeforeEach
void createTable() {
Map<String, Object> map = new HashMap<>();
Map<String, Object> map1 = new HashMap<>();
Map<String, Object> map2 = new HashMap<>();
map.put("id", "a");
map.put("name", "x");
map1.put("id", "b");
map1.put("name", "y");
map2.put("id", "c");
map2.put("name", "z");
List<Map<String, Object>> list = new ArrayList<>();
list.add(map);
list.add(map1);
list.add(map2);
leftTable = ateTable(list, "id");
Map<String, Object> map3 = new HashMap<>();
Map<String, Object> map4 = new HashMap<>();
Map<String, Object> map5 = new HashMap<>();
map3.put("id", "a");
map3.put("val", "o");
map4.put("id", "b");
map4.put("val", "p");
map5.put("id", "d");
map5.put("val", "q");
List<Map<String, Object>> list2 = new ArrayList<>();
list2.add(map3);
list2.add(map4);
list2.add(map5);
rightTable = ateTable(list2, "id");
System.out.println("LeftTable");
JoinUtils.printTable(leftTable);
System.out.println("RightTable");
JoinUtils.printTable(rightTable);
}
@Test
void testCreateTable2() {
User tom = new User(1, "tom", false);
User john = new User(2, "john", true);
User pet = new User(3, "pet", true);
ArrayList<User> users = new ArrayList<>();
users.add(tom);
users.add(john);
users.add(pet);
Table<Integer, String, Object> userTable = ateTable(users, User.class, "name"); JoinUtils.printTable(userTable);
}
@Test
void testStrategy() {
JoinStrategy[] values = JoinStrategy.values();
for (JoinStrategy strategy : values) {
System.out.println(strategy);
JoinUtils.printTable(JoinUtils.join(leftTable, rightTable, strategy));
}
}
}
输出:
name id
a x a
b y b
c z c
RightTable
val id
a o a
b p b
d q d
INNER_JOIN
name val id
a x o a
b y p b
LEFT_JOIN
name val id
a x o a
b y p b
c z null c
RIGHT_JOIN
val name id
a o x a
b p y b
d q null d
LEFT_SEMI_JOIN
name id
a x a
b y b
LEFT_ANTI_JOIN
name id
c z c
FULL_JOIN
name val id
a x o a
b y p b
c z null c
d null q d
具体join操作的实现代码,功能肯定是没问题的,性能还没有完全测试。
如果你有更靠谱的实现,请留⾔告诉我。
/**
* 未指定连接key的内连接,以rowKey作为连接键
*
* @param left
* @param right
* @return
*/
private static <R, C, V> Table<R, C, V> innerJoin(Table<R, C, V> left, Table<R, C, V> right) { Table<R, C, V> result = ate();
Set<R> leftRowKey = wKeySet());
Set<R> rightRowKey = wKeySet());
for (R key : leftRowKey) {
Map<C, V> leftRow = w(key);
Map<C, V> rightRow = w(key);
for (Map.Entry<C, V> leftEntry : Set()) {
result.put(key, Key(), Value());
}
for (Map.Entry<C, V> rightEntry : Set()) {
result.put(key, Key(), Value());
}
}
return result;
}
private static <R, C, V> Table<R, C, V> leftJoin(Table<R, C, V> left, Table<R, C, V> right) { Table<R, C, V> result = ate();
Set<R> leftRowKey = wKeySet());
for (R key : leftRowKey) {
Map<C, V> leftRow = w(key);
Map<C, V> rightRow = w(key);
for (Map.Entry<C, V> leftEntry : Set()) {
result.put(key, Key(), Value());
for (Map.Entry<C, V> rightEntry : Set()) {
result.put(key, Key(), Value());
}
}
return result;
}
private static <R, C, V> Table<R, C, V> rightJoin(Table<R, C, V> left, Table<R, C, V> right) { return leftJoin(right, left);
}
private static <R, C, V> Table<R, C, V> leftSemiJoin(Table<R, C, V> left, Table<R, C, V> right) { Table<R, C, V> result = ate();
Set<R> leftRowKey = wKeySet());
Set<R> rightRowKey = wKeySet());
for (R key : leftRowKey) {
Map<C, V> leftRow = w(key);
for (Map.Entry<C, V> leftEntry : Set()) {
result.put(key, Key(), Value());
}
}
return result;
}
private static <R, C, V> Table<R, C, V> leftAntiJoin(Table<R, C, V> left, Table<R, C, V> right) { Table<R, C, V> result = ate();
Set<R> leftRowKey = wKeySet());
Set<R> rightRowKey = wKeySet());
for (R key : leftRowKey) {
if (!ains(key)) {
Map<C, V> leftRow = w(key);
for (Map.Entry<C, V> leftEntry : Set()) {
result.put(key, Key(), Value());
}
}
}
return result;
}
private static <R, C, V> Table<R, C, V> fullJoin(Table<R, C, V> left, Table<R, C, V> right) {
Table<R, C, V> result = ate();
Set<R> leftRowKey = wKeySet());
Set<R> rightRowKey = wKeySet());
Set<R> union = new HashSet<>(leftRowKey);
union.addAll(rightRowKey);
sql left join 多表连接for (R key : union) {
Map<C, V> leftRow = w(key);
Map<C, V> rightRow = w(key);
for (Map.Entry<C, V> leftEntry : Set()) {
result.put(key, Key(), Value());
}
for (Map.Entry<C, V> rightEntry : Set()) {
result.put(key, Key(), Value());
}
}
return result;
}
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论