[#1273] Simulate GROUP_CONCAT() aggregate function using Oracle's LISTAGG() function, where available
This commit is contained in:
parent
8a5d3ae639
commit
ca32a0fa39
@ -48,6 +48,7 @@ import static org.jooq.impl.Factory.countDistinct;
|
||||
import static org.jooq.impl.Factory.cumeDist;
|
||||
import static org.jooq.impl.Factory.denseRank;
|
||||
import static org.jooq.impl.Factory.firstValue;
|
||||
import static org.jooq.impl.Factory.groupConcat;
|
||||
import static org.jooq.impl.Factory.lag;
|
||||
import static org.jooq.impl.Factory.lead;
|
||||
import static org.jooq.impl.Factory.listAgg;
|
||||
@ -746,7 +747,13 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
Result<?> result1 = create().select(
|
||||
TAuthor_FIRST_NAME(),
|
||||
TAuthor_LAST_NAME(),
|
||||
listAgg(TBook_ID(), ", ").withinGroupOrderBy(TBook_ID().desc()).as("books"))
|
||||
listAgg(TBook_ID(), ", ")
|
||||
.withinGroupOrderBy(TBook_ID().desc())
|
||||
.as("books1"),
|
||||
groupConcat(TBook_ID())
|
||||
.orderBy(TBook_ID().desc())
|
||||
.separator(", ")
|
||||
.as("books2"))
|
||||
.from(TAuthor())
|
||||
.join(TBook()).on(TAuthor_ID().equal(TBook_AUTHOR_ID()))
|
||||
.groupBy(
|
||||
@ -759,8 +766,10 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
assertEquals(2, result1.size());
|
||||
assertEquals(AUTHOR_FIRST_NAMES, result1.getValues(TAuthor_FIRST_NAME()));
|
||||
assertEquals(AUTHOR_LAST_NAMES, result1.getValues(TAuthor_LAST_NAME()));
|
||||
assertEquals("2, 1", result1.getValue(0, "books"));
|
||||
assertEquals("4, 3", result1.getValue(1, "books"));
|
||||
assertEquals("2, 1", result1.getValue(0, "books1"));
|
||||
assertEquals("2, 1", result1.getValue(0, "books2"));
|
||||
assertEquals("4, 3", result1.getValue(1, "books1"));
|
||||
assertEquals("4, 3", result1.getValue(1, "books2"));
|
||||
|
||||
switch (getDialect()) {
|
||||
case CUBRID:
|
||||
|
||||
75
jOOQ/src/main/java/org/jooq/GroupConcatOrderByStep.java
Normal file
75
jOOQ/src/main/java/org/jooq/GroupConcatOrderByStep.java
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.ORACLE;
|
||||
import static org.jooq.SQLDialect.SYBASE;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.impl.Factory;
|
||||
|
||||
|
||||
/**
|
||||
* MySQL's <code>GROUP_CONCAT</code> function.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see Factory#listAgg(Field)
|
||||
*/
|
||||
public interface GroupConcatOrderByStep extends GroupConcatSeparatorStep {
|
||||
|
||||
/**
|
||||
* Add an <code>ORDER BY</code> clause to the query
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
GroupConcatSeparatorStep orderBy(Field<?>... fields);
|
||||
|
||||
/**
|
||||
* Add an <code>ORDER BY</code> clause to the query
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
GroupConcatSeparatorStep orderBy(SortField<?>... fields);
|
||||
|
||||
/**
|
||||
* Add an <code>ORDER BY</code> clause to the query
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
GroupConcatSeparatorStep orderBy(Collection<SortField<?>> fields);
|
||||
}
|
||||
60
jOOQ/src/main/java/org/jooq/GroupConcatSeparatorStep.java
Normal file
60
jOOQ/src/main/java/org/jooq/GroupConcatSeparatorStep.java
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.H2;
|
||||
import static org.jooq.SQLDialect.HSQLDB;
|
||||
import static org.jooq.SQLDialect.MYSQL;
|
||||
import static org.jooq.SQLDialect.ORACLE;
|
||||
import static org.jooq.SQLDialect.SYBASE;
|
||||
|
||||
import org.jooq.impl.Factory;
|
||||
|
||||
/**
|
||||
* MySQL's <code>GROUP_CONCAT</code> function.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see Factory#listAgg(Field)
|
||||
*/
|
||||
public interface GroupConcatSeparatorStep extends AggregateFunction<String> {
|
||||
|
||||
/**
|
||||
* Specify the separator on the <code>GROUP_CONCAT</code> function
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
AggregateFunction<String> separator(String separator);
|
||||
}
|
||||
@ -94,6 +94,7 @@ import org.jooq.ExecuteListener;
|
||||
import org.jooq.FactoryOperations;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.FieldProvider;
|
||||
import org.jooq.GroupConcatOrderByStep;
|
||||
import org.jooq.Insert;
|
||||
import org.jooq.InsertQuery;
|
||||
import org.jooq.InsertSetStep;
|
||||
@ -4258,6 +4259,8 @@ public class Factory implements FactoryOperations {
|
||||
* <li> {@link SQLDialect#MYSQL}: Using <code>GROUP_CONCAT()</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #groupConcat(Field)
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field) {
|
||||
@ -4276,13 +4279,62 @@ public class Factory implements FactoryOperations {
|
||||
* <li> {@link SQLDialect#MYSQL}: Using <code>GROUP_CONCAT</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #groupConcat(Field, String)
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field, String delimiter) {
|
||||
Field<String> literal = literal("'" + delimiter.replace("'", "''") + "'");
|
||||
public static OrderedAggregateFunction<String> listAgg(Field<?> field, String separator) {
|
||||
Field<String> literal = literal("'" + separator.replace("'", "''") + "'");
|
||||
return new Function<String>(Term.LIST_AGG, SQLDataType.VARCHAR, nullSafe(field), literal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aggregated concatenation for a field.
|
||||
* <p>
|
||||
* This is natively supported by
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#CUBRID}</li>
|
||||
* <li> {@link SQLDialect#H2}</li>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#MYSQL}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* It is simulated by the following dialects:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#ORACLE}: Using <code>LISTAGG()</code></li>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #listAgg(Field)
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, ORACLE, SYBASE })
|
||||
public static GroupConcatOrderByStep groupConcat(Field<?> field) {
|
||||
return new GroupConcat(nullSafe(field));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the aggregated concatenation for a field.
|
||||
* <p>
|
||||
* This is natively supported by
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#CUBRID}</li>
|
||||
* <li> {@link SQLDialect#H2}</li>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#MYSQL}</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* It is simulated by the following dialects:
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#SYBASE}: Using <code>LIST()</code></li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #listAgg(Field)
|
||||
*/
|
||||
@Support({ CUBRID, H2, HSQLDB, MYSQL, SYBASE })
|
||||
public static GroupConcatOrderByStep groupConcatDistinct(Field<?> field) {
|
||||
return new GroupConcat(nullSafe(field), true);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Window functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@ -75,9 +75,11 @@ import org.jooq.WindowRowsStep;
|
||||
*/
|
||||
class Function<T> extends AbstractField<T> implements
|
||||
|
||||
// Cascading interface implementations for aggregate and window function behaviour
|
||||
// Cascading interface implementations for aggregate function behaviour
|
||||
OrderedAggregateFunction<T>,
|
||||
AggregateFunction<T>,
|
||||
|
||||
// and for window function behaviour
|
||||
WindowIgnoreNullsStep<T>,
|
||||
WindowPartitionByStep<T>,
|
||||
WindowRowsStep<T>,
|
||||
|
||||
121
jOOQ/src/main/java/org/jooq/impl/GroupConcat.java
Normal file
121
jOOQ/src/main/java/org/jooq/impl/GroupConcat.java
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed to you under the Apache License, Version 2.0
|
||||
* (the "License"); You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* . Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* . Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* . Neither the name "jOOQ" nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.literal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.AggregateFunction;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.GroupConcatOrderByStep;
|
||||
import org.jooq.GroupConcatSeparatorStep;
|
||||
import org.jooq.SortField;
|
||||
import org.jooq.WindowPartitionByStep;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class GroupConcat extends AbstractFunction<String> implements GroupConcatOrderByStep {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -6884415527559632960L;
|
||||
|
||||
private final Field<?> field;
|
||||
private final boolean distinct;
|
||||
private final SortFieldList orderBy;
|
||||
private String separator;
|
||||
|
||||
GroupConcat(Field<?> field) {
|
||||
this(field, false);
|
||||
}
|
||||
|
||||
GroupConcat(Field<?> field, boolean distinct) {
|
||||
super("group_concat", SQLDataType.VARCHAR);
|
||||
|
||||
this.field = field;
|
||||
this.distinct = distinct;
|
||||
this.orderBy = new SortFieldList();
|
||||
}
|
||||
|
||||
@Override
|
||||
final Field<String> getFunction0(Configuration configuration) {
|
||||
Function<String> result;
|
||||
|
||||
if (separator == null) {
|
||||
result = new Function<String>(Term.LIST_AGG, distinct, SQLDataType.VARCHAR, field);
|
||||
}
|
||||
else {
|
||||
Field<String> literal = literal("'" + separator.replace("'", "''") + "'");
|
||||
result = new Function<String>(Term.LIST_AGG, distinct, SQLDataType.VARCHAR, field, literal);
|
||||
}
|
||||
|
||||
return result.withinGroupOrderBy(orderBy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WindowPartitionByStep<String> over() {
|
||||
throw new UnsupportedOperationException("OVER() not supported on GROUP_CONCAT aggregate function");
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AggregateFunction<String> separator(String s) {
|
||||
this.separator = s;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GroupConcatSeparatorStep orderBy(Field<?>... fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GroupConcatSeparatorStep orderBy(SortField<?>... fields) {
|
||||
orderBy.addAll(Arrays.asList(fields));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final GroupConcatSeparatorStep orderBy(Collection<SortField<?>> fields) {
|
||||
orderBy.addAll(fields);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user