[#600] Add support for Oracle / SQL Standard linear regression functions

This commit is contained in:
Lukas Eder 2012-09-07 16:30:45 +02:00
parent 7f3e0fb63d
commit eeaa60bee8
4 changed files with 229 additions and 61 deletions

View File

@ -40,6 +40,7 @@ import static org.jooq.tools.reflect.Reflect.on;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.sql.Connection;
import java.sql.Date;
import java.sql.Time;
@ -696,6 +697,17 @@ public abstract class BaseTest<
catch (InterruptedException ignore) {}
}
/**
* Round all strings to a given scale, to avoid annoying floating point side-effects
*/
protected static String[] roundStrings(int n, String... strings) {
for (int i = 0; i < strings.length; i++) {
strings[i] = "" + new BigDecimal(strings[i]).setScale(n, RoundingMode.HALF_UP);
}
return strings;
}
/**
* Convenience method to create a new dummy book
*/

View File

@ -69,6 +69,15 @@ import static org.jooq.impl.Factory.minDistinct;
import static org.jooq.impl.Factory.ntile;
import static org.jooq.impl.Factory.percentRank;
import static org.jooq.impl.Factory.rank;
import static org.jooq.impl.Factory.regrAvgX;
import static org.jooq.impl.Factory.regrAvgY;
import static org.jooq.impl.Factory.regrCount;
import static org.jooq.impl.Factory.regrIntercept;
import static org.jooq.impl.Factory.regrR2;
import static org.jooq.impl.Factory.regrSXX;
import static org.jooq.impl.Factory.regrSXY;
import static org.jooq.impl.Factory.regrSYY;
import static org.jooq.impl.Factory.regrSlope;
import static org.jooq.impl.Factory.rowNumber;
import static org.jooq.impl.Factory.stddevPop;
import static org.jooq.impl.Factory.stddevSamp;
@ -79,6 +88,7 @@ import static org.jooq.impl.Factory.varPop;
import static org.jooq.impl.Factory.varSamp;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import org.jooq.Field;
@ -278,6 +288,68 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658,
}
}
@Test
public void testLinearRegressionFunctions() throws Exception {
switch (getDialect()) {
case CUBRID:
case DERBY:
case FIREBIRD:
case H2:
case HSQLDB:
case INGRES:
case MYSQL:
case SQLITE:
case SQLSERVER:
log.info("SKIPPING", "Skipping linear regression function tests");
return;
}
// [#600] As aggregate functions
Record record =
create().select(
regrAvgX(TBook_ID(), TBook_AUTHOR_ID()),
regrAvgY(TBook_ID(), TBook_AUTHOR_ID()),
regrCount(TBook_ID(), TBook_AUTHOR_ID()),
regrIntercept(TBook_ID(), TBook_AUTHOR_ID()),
regrR2(TBook_ID(), TBook_AUTHOR_ID()),
regrSlope(TBook_ID(), TBook_AUTHOR_ID()),
regrSXX(TBook_ID(), TBook_AUTHOR_ID()),
regrSXY(TBook_ID(), TBook_AUTHOR_ID()),
regrSYY(TBook_ID(), TBook_AUTHOR_ID()))
.from(TBook())
.fetchOne();
List<String> values = Arrays.asList("1.5", "2.5", "4.0", "-0.5", "0.8", "2.0", "1.0", "2.0", "5.0");
assertEquals(values, Arrays.asList(roundStrings(1, record.into(String[].class))));
switch (getDialect()) {
case DB2:
log.info("SKIPPING", "Skipping linear regression window function tests");
return;
}
// [#600] As window functions
Result<Record> result =
create().select(
regrAvgX(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrAvgY(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrCount(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrIntercept(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrR2(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrSlope(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrSXX(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrSXY(TBook_ID(), TBook_AUTHOR_ID()).over(),
regrSYY(TBook_ID(), TBook_AUTHOR_ID()).over())
.from(TBook())
.orderBy(TBook_ID())
.fetch();
assertEquals(values, Arrays.asList(roundStrings(1, result.get(0).into(String[].class))));
assertEquals(values, Arrays.asList(roundStrings(1, result.get(1).into(String[].class))));
assertEquals(values, Arrays.asList(roundStrings(1, result.get(2).into(String[].class))));
assertEquals(values, Arrays.asList(roundStrings(1, result.get(3).into(String[].class))));
}
@Test
public void testWindowFunctions() throws Exception {
switch (getDialect()) {

View File

@ -1371,6 +1371,16 @@ public abstract class jOOQAbstractTest<
new AggregateWindowFunctionTests(this).testAggregateFunctions();
}
@Test
public void testCountDistinct() throws Exception {
new AggregateWindowFunctionTests(this).testCountDistinct();
}
@Test
public void testLinearRegressionFunctions() throws Exception {
new AggregateWindowFunctionTests(this).testLinearRegressionFunctions();
}
@Test
public void testListAgg() throws Exception {
new AggregateWindowFunctionTests(this).testListAgg();

View File

@ -5129,13 +5129,6 @@ public class Factory implements FactoryOperations {
/**
* Get the median over a numeric field: median(field)
* <p>
* This is known to be supported in any of these RDBMS:
* <ul>
* <li>HSQLDB</li>
* <li>Oracle</li>
* <li>Sybase SQL Anywhere</li>
* </ul>
*/
@Support({ HSQLDB, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> median(Field<? extends Number> field) {
@ -5144,20 +5137,6 @@ public class Factory implements FactoryOperations {
/**
* Get the population standard deviation of a numeric field: stddev_pop(field)
* <p>
* This is known to be supported in any of these RDBMS:
* <ul>
* <li>DB2</li>
* <li>H2</li>
* <li>HSQLDB</li>
* <li>Ingres</li>
* <li>MySQL</li>
* <li>Oracle</li>
* <li>Postgres</li>
* <li>SQL Server (stdev)</li>
* <li>Sybase ASE</li>
* <li>Sybase SQL Anywhere</li>
* </ul>
*/
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
public static AggregateFunction<BigDecimal> stddevPop(Field<? extends Number> field) {
@ -5166,20 +5145,6 @@ public class Factory implements FactoryOperations {
/**
* Get the sample standard deviation of a numeric field: stddev_samp(field)
* <p>
* This is known to be supported in any of these RDBMS:
* <ul>
* <li>DB2</li>
* <li>H2</li>
* <li>HSQLDB</li>
* <li>Ingres</li>
* <li>MySQL</li>
* <li>Oracle</li>
* <li>Postgres</li>
* <li>SQL Server (stdev)</li>
* <li>Sybase ASE</li>
* <li>Sybase SQL Anywhere</li>
* </ul>
*/
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
public static AggregateFunction<BigDecimal> stddevSamp(Field<? extends Number> field) {
@ -5188,20 +5153,6 @@ public class Factory implements FactoryOperations {
/**
* Get the population variance of a numeric field: var_pop(field)
* <p>
* This is known to be supported in any of these RDBMS:
* <ul>
* <li>DB2</li>
* <li>H2</li>
* <li>HSQLDB</li>
* <li>Ingres</li>
* <li>MySQL</li>
* <li>Oracle</li>
* <li>Postgres</li>
* <li>SQL Server (stdev)</li>
* <li>Sybase ASE</li>
* <li>Sybase SQL Anywhere</li>
* </ul>
*/
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
public static AggregateFunction<BigDecimal> varPop(Field<? extends Number> field) {
@ -5210,24 +5161,147 @@ public class Factory implements FactoryOperations {
/**
* Get the sample variance of a numeric field: var_samp(field)
* <p>
* This is known to be supported in any of these RDBMS:
* <ul>
* <li>H2</li>
* <li>HSQLDB</li>
* <li>Ingres</li>
* <li>MySQL</li>
* <li>Oracle</li>
* <li>Postgres</li>
* <li>SQL Server (var)</li>
* <li>Sybase SQL Anywhere</li>
* </ul>
*/
@Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
public static AggregateFunction<BigDecimal> varSamp(Field<? extends Number> field) {
return new Function<BigDecimal>(Term.VAR_SAMP, SQLDataType.NUMERIC, nullSafe(field));
}
/**
* Get the <code>REGR_SLOPE</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrSlope(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_slope", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_INTERCEPT</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrIntercept(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_intercept", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_COUNT</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrCount(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_count", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_R2</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrR2(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_r2", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_AVGX</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrAvgX(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_avgx", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_AVGY</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrAvgY(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_avgy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_SXX</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrSXX(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_sxx", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_SYY</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrSYY(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_syy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the <code>REGR_SXY</code> linear regression function
* <p>
* The linear regression functions fit an ordinary-least-squares regression
* line to a set of number pairs. You can use them as both aggregate and
* window functions, where this is supported.
* <p>
* Note that {@link SQLDialect#DB2} does not support linear regression
* window functions.
*/
@Support({ DB2, POSTGRES, ORACLE, SYBASE })
public static AggregateFunction<BigDecimal> regrSXY(Field<? extends Number> y, Field<? extends Number> x) {
return new Function<BigDecimal>("regr_sxy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x));
}
/**
* Get the aggregated concatenation for a field.
* <p>