diff --git a/jOOQ-test/src/org/jooq/test/BaseTest.java b/jOOQ-test/src/org/jooq/test/BaseTest.java index 99c3ff9af0..61b35f9a13 100644 --- a/jOOQ-test/src/org/jooq/test/BaseTest.java +++ b/jOOQ-test/src/org/jooq/test/BaseTest.java @@ -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 */ diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java index a9d4e75b78..54a9e827f2 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/AggregateWindowFunctionTests.java @@ -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 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 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()) { diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 0dcf2ed35c..b2c528733c 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -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(); diff --git a/jOOQ/src/main/java/org/jooq/impl/Factory.java b/jOOQ/src/main/java/org/jooq/impl/Factory.java index 63da1187b0..99ec8a0476 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Factory.java +++ b/jOOQ/src/main/java/org/jooq/impl/Factory.java @@ -5129,13 +5129,6 @@ public class Factory implements FactoryOperations { /** * Get the median over a numeric field: median(field) - *

- * This is known to be supported in any of these RDBMS: - *

*/ @Support({ HSQLDB, ORACLE, SYBASE }) public static AggregateFunction median(Field field) { @@ -5144,20 +5137,6 @@ public class Factory implements FactoryOperations { /** * Get the population standard deviation of a numeric field: stddev_pop(field) - *

- * This is known to be supported in any of these RDBMS: - *

    - *
  • DB2
  • - *
  • H2
  • - *
  • HSQLDB
  • - *
  • Ingres
  • - *
  • MySQL
  • - *
  • Oracle
  • - *
  • Postgres
  • - *
  • SQL Server (stdev)
  • - *
  • Sybase ASE
  • - *
  • Sybase SQL Anywhere
  • - *
*/ @Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) public static AggregateFunction stddevPop(Field field) { @@ -5166,20 +5145,6 @@ public class Factory implements FactoryOperations { /** * Get the sample standard deviation of a numeric field: stddev_samp(field) - *

- * This is known to be supported in any of these RDBMS: - *

    - *
  • DB2
  • - *
  • H2
  • - *
  • HSQLDB
  • - *
  • Ingres
  • - *
  • MySQL
  • - *
  • Oracle
  • - *
  • Postgres
  • - *
  • SQL Server (stdev)
  • - *
  • Sybase ASE
  • - *
  • Sybase SQL Anywhere
  • - *
*/ @Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) public static AggregateFunction stddevSamp(Field field) { @@ -5188,20 +5153,6 @@ public class Factory implements FactoryOperations { /** * Get the population variance of a numeric field: var_pop(field) - *

- * This is known to be supported in any of these RDBMS: - *

    - *
  • DB2
  • - *
  • H2
  • - *
  • HSQLDB
  • - *
  • Ingres
  • - *
  • MySQL
  • - *
  • Oracle
  • - *
  • Postgres
  • - *
  • SQL Server (stdev)
  • - *
  • Sybase ASE
  • - *
  • Sybase SQL Anywhere
  • - *
*/ @Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) public static AggregateFunction varPop(Field field) { @@ -5210,24 +5161,147 @@ public class Factory implements FactoryOperations { /** * Get the sample variance of a numeric field: var_samp(field) - *

- * This is known to be supported in any of these RDBMS: - *

    - *
  • H2
  • - *
  • HSQLDB
  • - *
  • Ingres
  • - *
  • MySQL
  • - *
  • Oracle
  • - *
  • Postgres
  • - *
  • SQL Server (var)
  • - *
  • Sybase SQL Anywhere
  • - *
*/ @Support({ ASE, CUBRID, DB2, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) public static AggregateFunction varSamp(Field field) { return new Function(Term.VAR_SAMP, SQLDataType.NUMERIC, nullSafe(field)); } + /** + * Get the REGR_SLOPE linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrSlope(Field y, Field x) { + return new Function("regr_slope", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_INTERCEPT linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrIntercept(Field y, Field x) { + return new Function("regr_intercept", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_COUNT linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrCount(Field y, Field x) { + return new Function("regr_count", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_R2 linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrR2(Field y, Field x) { + return new Function("regr_r2", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_AVGX linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrAvgX(Field y, Field x) { + return new Function("regr_avgx", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_AVGY linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrAvgY(Field y, Field x) { + return new Function("regr_avgy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_SXX linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrSXX(Field y, Field x) { + return new Function("regr_sxx", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_SYY linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrSYY(Field y, Field x) { + return new Function("regr_syy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + + /** + * Get the REGR_SXY linear regression function + *

+ * 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. + *

+ * Note that {@link SQLDialect#DB2} does not support linear regression + * window functions. + */ + @Support({ DB2, POSTGRES, ORACLE, SYBASE }) + public static AggregateFunction regrSXY(Field y, Field x) { + return new Function("regr_sxy", SQLDataType.NUMERIC, nullSafe(y), nullSafe(x)); + } + /** * Get the aggregated concatenation for a field. *