test: cover firstValueAndLastValueRespectAnExplicitFrameInsteadOfTheP...
This commit is contained in:
1 parent
c90e6c12e1
commit
bfd93c3811
1 file changed
+156
@@ -462,3 +462,159 @@ class WindowFunctionTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun firstValueAndLastValueRespectAnExplicitFrameInsteadOfThePeerGroupDefault() {
|
||||||
|
seed()
|
||||||
|
val result = select(
|
||||||
|
"SELECT id, " +
|
||||||
|
"FIRST_VALUE(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS f, " +
|
||||||
|
"LAST_VALUE(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS l " +
|
||||||
|
"FROM employees ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
listOf(int(1), int(400), int(400)),
|
||||||
|
listOf(int(2), int(400), int(300)),
|
||||||
|
listOf(int(3), int(400), int(300)),
|
||||||
|
listOf(int(4), int(200), int(200)),
|
||||||
|
listOf(int(5), int(200), int(100)),
|
||||||
|
listOf(int(6), int(200), int(100))
|
||||||
|
),
|
||||||
|
result.rows
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rowsFrameShorthandWithoutBetweenEndsAtCurrentRow() {
|
||||||
|
seed()
|
||||||
|
val explicit = select(
|
||||||
|
"SELECT id, SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS 1 PRECEDING) AS s " +
|
||||||
|
"FROM employees ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
val spelledOut = select(
|
||||||
|
"SELECT id, SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS s " +
|
||||||
|
"FROM employees ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(spelledOut.rows, explicit.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rowsFrameOffsetMustNotBeNegative() {
|
||||||
|
seed()
|
||||||
|
val error = assertFailsWith<KestrelException> {
|
||||||
|
run("SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN -1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("negative"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rowsFrameOffsetMustBeAnInteger() {
|
||||||
|
seed()
|
||||||
|
val error = assertFailsWith<KestrelException> {
|
||||||
|
run("SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN 1.5 PRECEDING AND CURRENT ROW) FROM employees")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("integer"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rowsFrameIsRejectedOnRankingAndOffsetWindowFunctions() {
|
||||||
|
seed()
|
||||||
|
val error = assertFailsWith<KestrelException> {
|
||||||
|
run("SELECT ROW_NUMBER() OVER (ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM employees")
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("frame"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun windowFunctionNestedInsideAFrameOffsetIsRejected() {
|
||||||
|
seed()
|
||||||
|
val error = assertFailsWith<KestrelException> {
|
||||||
|
run(
|
||||||
|
"SELECT SUM(salary) OVER (ORDER BY id ROWS BETWEEN ROW_NUMBER() OVER (ORDER BY id) PRECEDING AND CURRENT ROW) " +
|
||||||
|
"FROM employees"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
assertTrue(error.message!!.contains("nested"), error.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun explicitFrameSurvivesViewDefinitionRoundTrip() {
|
||||||
|
seed()
|
||||||
|
run(
|
||||||
|
"CREATE VIEW movingTotals AS SELECT id, " +
|
||||||
|
"SUM(salary) OVER (PARTITION BY deptId ORDER BY id ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS s " +
|
||||||
|
"FROM employees"
|
||||||
|
)
|
||||||
|
val result = select("SELECT id, s FROM movingTotals ORDER BY id ASC")
|
||||||
|
assertEquals(
|
||||||
|
listOf(400L, 800L, 700L, 200L, 400L, 300L),
|
||||||
|
result.rows.map { (it[1] as Value.IntegerValue).value }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** amount is monotonic in id (10, 20, 20, 30, 50) so `ORDER BY id` and `ORDER BY amount` agree, with a tie at 20. */
|
||||||
|
private fun seedSales() {
|
||||||
|
run("CREATE TABLE sales (id INTEGER PRIMARY KEY, amount INTEGER)")
|
||||||
|
run("INSERT INTO sales VALUES (1, 10), (2, 20), (3, 20), (4, 30), (5, 50)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeBetweenPrecedingAndFollowingIncludesRowsWithinValueDistanceRegardlessOfPhysicalRowCount() {
|
||||||
|
seedSales()
|
||||||
|
val result = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(50L, 80L, 80L, 70L, 50L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameGivesTheSameRowSetRegardlessOfOrderDirectionForASymmetricWindow() {
|
||||||
|
seedSales()
|
||||||
|
val ascending = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount ASC RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
val descending = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount DESC RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(ascending.rows, descending.rows)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeBetweenPrecedingAndFollowingOnADescendingOrderByFlipsWhichDirectionIsPreceding() {
|
||||||
|
seedSales()
|
||||||
|
val result = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount DESC RANGE BETWEEN 15 PRECEDING AND 5 FOLLOWING) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(50L, 70L, 70L, 30L, 50L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeCurrentRowExpandsToTheWholePeerGroupUnlikeRowsCurrentRow() {
|
||||||
|
seedSales()
|
||||||
|
val range = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
val rows = select(
|
||||||
|
"SELECT id, SUM(amount) OVER (ORDER BY amount ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS s " +
|
||||||
|
"FROM sales ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(10L, 50L, 50L, 80L, 130L), range.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
assertEquals(listOf(10L, 30L, 50L, 80L, 130L), rows.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun rangeFrameMeasuresDistanceOnADecimalColumn() {
|
||||||
|
run("CREATE TABLE prices (id INTEGER PRIMARY KEY, price DECIMAL(10, 2))")
|
||||||
|
run("INSERT INTO prices VALUES (1, 1.00), (2, 1.40), (3, 1.50), (4, 2.00)")
|
||||||
|
val result = select(
|
||||||
|
"SELECT id, COUNT(*) OVER (ORDER BY price RANGE BETWEEN 0.5 PRECEDING AND 0.5 FOLLOWING) AS c " +
|
||||||
|
"FROM prices ORDER BY id ASC"
|
||||||
|
)
|
||||||
|
assertEquals(listOf(3L, 3L, 4L, 2L), result.rows.map { (it[1] as Value.IntegerValue).value })
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user