Union query with multiple selects post java 8

你。 提交于 2019-12-22 10:43:45

问题


Here is a query that I want to try out in MySQL

SELECT A.x
FROM A
WHERE A.y = 'P'
UNION
SELECT A.x
FROM A
WHERE A.y = 'Q'

The above is a cut-down, much simpler version of the original query that I am trying. In my original query, each SELECT statement involves multiple tables with INNER JOIN

If the possible number of values in 'y' column of table 'A' that I need to query upon is 'n', then my query will involve doing 'n-1' unions on 'n' SELECT statements

I know that JOOQ can do union of multiple SELECT statements. But is there a good way to do this post Java 8 style? maybe using Steam.collect()?

This is what I have but wondering if I could do better

String firstValueToQuery = valuesToQuery.get(0);
Select<Record5<UUID, UUID, String, Integer, String>> selectQuery =  getSelectQueryForValue(firstValueToQuery);
valuesToQuery.stream()
             .skip(1)
             .forEach(valueToQuery -> selectQuery.unionAll(getSelectQueryForValue(valueToQuery)));
selectQuery.fetchStream();

Here is how I implement getSelectQueryForValue

private Select<Record5<UUID, UUID, String, Integer, String>> getSelectQueryForValue(String valueToQuery) {
        return jooq.select(
                A.P,
                A.Q,
                A.R,
                A.S,
                A.T)
                .from(A)
                .where(A.Y.eq(valueToQuery));
    }

PS: I understand that I could rather use the 'IN' clause like below

SELECT A.x
FROM A
WHERE A.y IN ('P','Q',...)

But with my current data distribution in the database, MySQL is using a sub-optimal query plan. Thus using UNION so that the database implicitly prefers a faster query plan by making use of the right index


回答1:


The idiomatic approach here would be as follows (using JDK 9 API):

try (Stream<Record5<UUID, UUID, String, Integer, String>> stream = valuesToQuery
        .stream()
        .map(this::getSelectQueryForValue)
        .reduce(Select::union)
        .stream() // JDK 9 method
        .flatMap(Select::fetchStream)) {
    ...
}

It uses the useful Optional.stream() method, which was added in JDK 9. In JDK 8, you could do this instead:

valuesToQuery
    .stream()
    .map(this::getSelectQueryForValue)
    .reduce(Select::union)
    .ifPresent(s -> {
        try (Stream<Record5<UUID, UUID, String, Integer, String>> stream = 
             s.fetchStream()) {
            ...
        }
    })

I blogged about this in more detail here.



来源:https://stackoverflow.com/questions/48991918/union-query-with-multiple-selects-post-java-8

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!