我将如何使用java.util.Collections模拟SQL INNER JOIN操作?

时间:2018-12-03 16:51:11

标签: java mysql sql hashmap

我将如何使用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语句来填充地图。

不幸的是,根本不可能运行关系数据库建模系统。


我不了解如何组织“集合”或“地图”,以及如何将它们链接在一起以模仿“内部联接”操作?


提前感谢您的时间和能提供的任何帮助。

3 个答案:

答案 0 :(得分:1)

在您的示例中,人与物之间存在一对多的关系。对我来说,从数据库的角度考虑比从Java / OOP的角度考虑这种关系更困难。

在您的数据库中,将您的加入人员表添加到物联网表,以提供每个人拥有的物联网的列表。

这可能会以事物映射的方式进入您的应用程序,每个事物都有一个拥有每个事物的人员的列表,或者作为一个人类映射,每个都有其拥有的事物的列表。

因此,在Java中,您实质上是在问如何对此建模:

public class Person() {    
   private List<Thing> things;
}

...

public class SomeClass() {
    private List<Person> peopleWithThings;
}  

IMO,您可以通过两种方式执行此操作-

  1. 像上面一样,只需在您的域中使用普通的旧Java对象
  2. 使用类似Guava的多图的方法来创建字符串(人名)到事物列表的映射。

使用多图,您将得到类似的东西:

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