我将如何使用Java集合来模拟SQL INNER JOIN操作?
在数据库中,我有:
TABLE人
KEY NAME
11 Senor
other non-important entries...
TABLE物品
KEY ITEM
AA Moustache
BB Sombrero
CC HotSauce
other non-important entries...
TABLE PersonToThing
PERSON_KEY THING_KEY HAS
11 AA Y
11 BB N
11 CC Y
other non-important entries...
我要模拟SQL语句:
SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS
FROM Person
INNER JOIN PersonToThing ON Person.KEY=PersonToThing.PERSON_PKEY
INNER JOIN Thing ON Thing.KEY=PersonToThing.THING_KEY
WHERE Person.NAME="Senor";
哪个产生结果集:
NAME ITEM HAS
Senor Moustache Y
Senor Sombrero N
Senor HotSauce Y
我想将每个表放在Java Map中。
我已将表导出到INSERT TABLE语句中。
我将通过遍历INSERT TABLE语句来填充地图。
不幸的是,根本不可能运行关系数据库建模系统。
我不了解如何组织“集合”或“地图”,以及如何将它们链接在一起以模仿“内部联接”操作?
提前感谢您的时间和能提供的任何帮助。
答案 0 :(得分:1)
在您的示例中,人与物之间存在一对多的关系。对我来说,从数据库的角度考虑比从Java / OOP的角度考虑这种关系更困难。
在您的数据库中,将您的加入人员表添加到物联网表,以提供每个人拥有的物联网的列表。
这可能会以事物映射的方式进入您的应用程序,每个事物都有一个拥有每个事物的人员的列表,或者作为一个人类映射,每个都有其拥有的事物的列表。
因此,在Java中,您实质上是在问如何对此建模:
public class Person() {
private List<Thing> things;
}
...
public class SomeClass() {
private List<Person> peopleWithThings;
}
IMO,您可以通过两种方式执行此操作-
使用多图,您将得到类似的东西:
String key = "Senor";
Multimap<String, Thing> map = ArrayListMultimap.create();
map.put(key, thing1);
map.put(key, thing2);
assertEquals(2, map.size());
答案 1 :(得分:0)
在集合论中,内部联接本质上是一个 intersection 操作。 Java集合没有内置完全相同的集合论函数,但是它们对于联合(addAll)和交集(retainAll)具有相似的函数。有关如何使用Set或其他集合实现inner-join / intersection的更多详细信息,请参见this question。
使用集合论的主要挑战是存在三种不同的对象类型,它们都不相互继承,这可能是在适当的关系模型中所期望的。例如,如果Person和Thing都从PersonToThing作为父类继承,那么它将大大简化事情:
class Person extends PersonToThing {
// ...
}
class Thing extends PersonToThing {
// ...
}
class PersonToThing {
// now Person_Key and Thing_Key can be inherited
String personKey;
String thingKey;
// etc...
}
使用此模型,我们现在可以具有PersonToThing对象的集合,并正确地说明了一对多关系:
Set<PersonToThing> people = selectAllFrom("Person");
Set<PersonToThing> thing = selectAllFrom("Thing");
Set<PersonToThing> innerJoin = people;
people.addAll(thing);
innerJoin.retainAll(thing);
如果您重写Object的equals()
函数来检查密钥,则可以根据需要执行连接,包括在其中包括Senor名称过滤器,或添加实用程序函数以使其更可重用且易于使用。 :
@Override
public boolean equals(Object personToThing) {
if (personToThing.getPersonKey() != null) {
return personKey.equals(personToThing.getPersonKey());
else
return thingKey.equals(personToThing.getThingKey());
}
之所以这样做是因为Set使用equals()
来检查两个对象是否相同。这样,当这样做时,我们就可以像连接一样比较键。
由于您未提供任何特定于数据库的样板代码,因此我保留了selectAllFrom()函数摘要的详细信息,但是无论您需要执行什么,它都应该很简单。
答案 2 :(得分:0)
好吧,这似乎并不容易,但是有可能。
首先进行一些准备-我正在使用Project Lombok,以便使用简单的注释生成getter / setter和构造函数,只需创建一个Maven项目并将此依赖项添加到其中:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
下面是带有数据的类和表的定义:
@AllArgsConstructor @Getter
public static class Person {
private String key, name;
}
@AllArgsConstructor @Getter
public static class Thing {
private String key, item;
}
@AllArgsConstructor @Getter
public static class PersonToThing {
private String personKey, thingKey, has;
}
static Collection<Person> tablePerson = Arrays.asList(
new Person("11", "Senor"),
new Person("22", "Tom"));
static Collection<Thing> tableThing = Arrays.asList(
new Thing("AA", "Moustache"),
new Thing("BB", "Sombrero"),
new Thing("CC", "HotSauce"),
new Thing("XX", "Not important")
);
static Collection<PersonToThing> tablePerson2Thing = Arrays.asList(
new PersonToThing("11", "AA","Y"),
new PersonToThing("11", "BB","N"),
new PersonToThing("11", "CC","Y"));
现在有一段代码可以对这三个集合进行联接。
@AllArgsConstructor(staticName = "of") @Getter
public static class Tuple<V1,V2>{
private V1 v1;
private V2 v2;
}
@AllArgsConstructor(staticName = "of") @Getter
public static class Triple<V1,V2,V3>{
private V1 v1;
private V2 v2;
private V3 v3;
}
public static void main(String[] args) {
tablePerson.stream()
// WHERE Person.NAME="Senor";
.filter(x->x.getName()=="Senor")
// INNER JOIN PersonToThing
.flatMap( p -> tablePerson2Thing.stream()
.map(p2t-> Tuple.of(p,p2t))
// ON Person.KEY=PersonToThing.PERSON_PKEY
.filter(t->t.getV1().getKey()==t.getV2().getPersonKey())
)
// INNER JOIN Thing
.flatMap( p2t-> tableThing.stream()
.map(t-> Triple.of(p2t.getV1(),p2t.getV2(),t))
// ON Thing.KEY=PersonToThing.THING_KEY
.filter(t->t.getV2().getThingKey()==t.getV3().getKey())
)
// SELECT Person.NAME, Thing.ITEM, PersonToThing.HAS
.forEach(x->System.out.println(x.getV1().getName()+ " / " + x.getV3().getItem() + " / " + x.getV2().getHas()));
}
结果是:
Senor / Moustache / Y
Senor / Sombrero / N
Senor / HotSauce / Y