如何使用java.util.collections来模拟sql内部连接操作?

xpszyzbs  于 2021-06-18  发布在  Mysql
关注(0)|答案(3)|浏览(321)

如何使用java集合来模拟sql内部联接操作?
在数据库中,我有:
餐桌上的人

KEY  NAME
11   Senor
other non-important entries...

餐桌用品

KEY  ITEM
AA   Moustache
BB   Sombrero
CC   HotSauce
other non-important entries...

餐桌用品

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

我想把每个表放在一个javaMap中。
我已将这些表导出到insert table语句中。
我将通过循环insert table语句来填充Map。
不幸的是,运行关系数据库建模系统根本不可能。
我不明白的是如何组织集合或Map,以及如何将它们链接在一起以模拟内部连接操作?
提前感谢您的时间和您能给予的任何帮助。

ybzsozfc

ybzsozfc1#

在集合论中,内连接本质上是一个交集运算。java集合没有完全相同的内置集合论函数,但是它们有相似的union(addall)和intersection(retainal)函数。有关如何使用集合或其他集合实现内部联接/交集的更多详细信息,请参见此问题。
这里使用集合论的主要挑战是存在三种不同的对象类型,它们都不能相互继承,这是人们在适当的关系模型中所期望的。例如,如果将persontothing作为父类继承给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);

如果覆盖对象的 equals() 函数来检查您的密钥,您可以按自己的喜好执行连接,包括此处的senor name过滤器,或添加实用程序函数以使其更易于重用和用户友好的设计:

@Override
public boolean equals(Object personToThing) {
    if (personToThing.getPersonKey() != null) {
        return personKey.equals(personToThing.getPersonKey());
    else
        return thingKey.equals(personToThing.getThingKey());
}

这是因为set使用 equals() 检查两个物体是否相同。这样,当它这样做的时候,我们就像连接一样比较键。
我留下了selectallfrom()函数摘要的细节,因为您没有提供任何特定于数据库的样板代码,但是它应该很容易实现。

igsr9ssn

igsr9ssn2#

嗯,这看起来不容易,但这是可能的。
首先做一些准备-我正在使用项目lombok,以便使用简单的注解生成getter/setter和constructor,只需创建一个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
xzabzqsa

xzabzqsa3#

在你的例子中,人和物之间有一对多的关系。对我来说,从数据库的Angular 考虑这种关系比从java/oop的Angular 考虑更难。
在数据库中,将person表连接到thing表,以提供每个人拥有的东西的列表。
这可以作为一张事物Map进入你的应用程序,每一张Map都有一个拥有每一事物的人的列表,或者作为一张人的Map,每一张Map都有一个他们拥有的事物的列表。
所以,在java中,基本上是在问如何建模:

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

...

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

依我看,你可以用两种方法-
只需像我上面所做的那样在您的域中使用普通的旧java对象
使用像guava的multimap这样的东西来创建一个字符串(人名)到一个事物列表的Map。
使用多重Map,您将得到如下结果:

String key = "Senor";
Multimap<String, Thing> map = ArrayListMultimap.create();

map.put(key, thing1);
map.put(key, thing2);

assertEquals(2, map.size());

相关问题