Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
4f23bb18
Unverified
提交
4f23bb18
authored
6 年前
作者:
Evgenij Ryazanov
提交者:
GitHub
6 年前
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1456 from katzyn/window
Add experimental implementation of remaining types of window frames
上级
a1314402
1b33a3de
显示空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
746 行增加
和
173 行删除
+746
-173
help.csv
h2/src/docsrc/help/help.csv
+26
-5
Parser.java
h2/src/main/org/h2/command/Parser.java
+84
-40
AbstractAggregate.java
...c/main/org/h2/expression/aggregate/AbstractAggregate.java
+1
-1
Window.java
h2/src/main/org/h2/expression/aggregate/Window.java
+5
-0
WindowFrame.java
h2/src/main/org/h2/expression/aggregate/WindowFrame.java
+253
-122
WindowFrameBound.java
...rc/main/org/h2/expression/aggregate/WindowFrameBound.java
+70
-0
WindowFrameBoundType.java
...ain/org/h2/expression/aggregate/WindowFrameBoundType.java
+54
-0
WindowFrameExclusion.java
...ain/org/h2/expression/aggregate/WindowFrameExclusion.java
+51
-0
WindowFrameUnits.java
...rc/main/org/h2/expression/aggregate/WindowFrameUnits.java
+40
-0
WindowFunction.java
h2/src/main/org/h2/expression/aggregate/WindowFunction.java
+3
-3
array-agg.sql
...est/org/h2/test/scripts/functions/aggregate/array-agg.sql
+157
-0
nth_value.sql
...c/test/org/h2/test/scripts/functions/window/nth_value.sql
+2
-2
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
4f23bb18
...
...
@@ -2550,11 +2550,8 @@ They also may require a lot of memory for large queries.
"
"Other Grammar","Window frame","
[RANGE BETWEEN {
UNBOUNDED PRECEDING AND CURRENT ROW
|CURRENT ROW AND UNBOUNDED FOLLOWING
|UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
}]
ROWS|RANGE|GROUP
{windowFramePreceding|BETWEEN windowFrameBound AND windowFrameBound}
[EXCLUDE {CURRENT ROW|GROUP|TIES|NO OTHERS}]
","
A window frame clause.
...
...
@@ -2563,6 +2560,30 @@ Is currently supported only in aggregates and FIRST_VALUE(), LAST_VALUE(), and N
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCLUDE GROUP
"
"Other Grammar","Window frame preceding","
UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
","
A window frame preceding clause.
If value is specified it should be non-negative value or parameter.
","
UNBOUNDED PRECEDING
1 PRECEDING
CURRENT ROW
"
"Other Grammar","Window frame bound","
UNBOUNDED PRECEDING|value PRECEDING|CURRENT ROW
|value FOLLOWING|UNBOUNDED FOLLOWING
","
A window frame bound clause.
If value is specified it should be non-negative value or parameter.
","
UNBOUNDED PRECEDING
UNBOUNDED FOLLOWING
1 FOLLOWING
CURRENT ROW
"
"Other Grammar","Term","
value
| columnName
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/command/Parser.java
浏览文件 @
4f23bb18
...
...
@@ -176,8 +176,10 @@ import org.h2.expression.aggregate.Aggregate.AggregateType;
import
org.h2.expression.aggregate.JavaAggregate
;
import
org.h2.expression.aggregate.Window
;
import
org.h2.expression.aggregate.WindowFrame
;
import
org.h2.expression.aggregate.WindowFrame.SimpleExtent
;
import
org.h2.expression.aggregate.WindowFrame.WindowFrameExclusion
;
import
org.h2.expression.aggregate.WindowFrameBound
;
import
org.h2.expression.aggregate.WindowFrameBoundType
;
import
org.h2.expression.aggregate.WindowFrameExclusion
;
import
org.h2.expression.aggregate.WindowFrameUnits
;
import
org.h2.expression.aggregate.WindowFunction
;
import
org.h2.expression.aggregate.WindowFunction.WindowFunctionType
;
import
org.h2.index.Index
;
...
...
@@ -3074,8 +3076,7 @@ public class Parser {
frame
=
readWindowFrame
();
break
;
default
:
frame
=
new
WindowFrame
(
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW
,
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
);
frame
=
null
;
}
}
else
{
frame
=
readWindowFrame
();
...
...
@@ -3092,29 +3093,27 @@ public class Parser {
}
private
WindowFrame
readWindowFrame
()
{
SimpleExtent
extent
;
WindowFrameExclusion
exclusion
=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
;
if
(
readIf
(
"RANGE"
))
{
read
(
"BETWEEN"
);
if
(
readIf
(
"UNBOUNDED"
))
{
read
(
"PRECEDING"
);
read
(
"AND"
);
if
(
readIf
(
"CURRENT"
))
{
read
(
"ROW"
);
extent
=
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW
;
WindowFrameUnits
units
;
if
(
readIf
(
"ROWS"
))
{
units
=
WindowFrameUnits
.
ROWS
;
}
else
if
(
readIf
(
"RANGE"
))
{
units
=
WindowFrameUnits
.
RANGE
;
}
else
if
(
readIf
(
"GROUPS"
))
{
units
=
WindowFrameUnits
.
GROUPS
;
}
else
{
read
(
"UNBOUNDED"
);
read
(
"FOLLOWING"
);
extent
=
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING
;
return
null
;
}
}
else
{
read
(
"CURRENT"
);
read
(
"ROW"
);
WindowFrameBound
starting
,
following
;
if
(
readIf
(
"BETWEEN"
))
{
starting
=
readWindowFrameRange
(
);
read
(
"AND"
);
read
(
"UNBOUNDED"
);
read
(
"FOLLOWING"
);
extent
=
SimpleExtent
.
RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING
;
following
=
readWindowFrameRange
();
}
else
{
starting
=
readWindowFrameStarting
();
following
=
null
;
}
int
idx
=
lastParseIndex
;
WindowFrameExclusion
exclusion
=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
;
if
(
readIf
(
"EXCLUDE"
))
{
if
(
readIf
(
"CURRENT"
))
{
read
(
"ROW"
);
...
...
@@ -3128,10 +3127,55 @@ public class Parser {
read
(
"OTHERS"
);
}
}
}
else
{
extent
=
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW
;
WindowFrame
frame
=
new
WindowFrame
(
units
,
starting
,
following
,
exclusion
);
if
(!
frame
.
isValid
())
{
throw
DbException
.
getSyntaxError
(
sqlCommand
,
idx
);
}
return
frame
;
}
private
WindowFrameBound
readWindowFrameStarting
()
{
if
(
readIf
(
"UNBOUNDED"
))
{
read
(
"PRECEDING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
,
null
);
}
if
(
readIf
(
"CURRENT"
))
{
read
(
"ROW"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
Expression
value
=
readValueOrParameter
();
read
(
"PRECEDING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
private
WindowFrameBound
readWindowFrameRange
()
{
if
(
readIf
(
"UNBOUNDED"
))
{
if
(
readIf
(
"PRECEDING"
))
{
return
new
WindowFrameBound
(
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
,
null
);
}
read
(
"FOLLOWING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
,
null
);
}
if
(
readIf
(
"CURRENT"
))
{
read
(
"ROW"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
CURRENT_ROW
,
null
);
}
Expression
value
=
readValueOrParameter
();
if
(
readIf
(
"PRECEDING"
))
{
return
new
WindowFrameBound
(
WindowFrameBoundType
.
PRECEDING
,
value
);
}
read
(
"FOLLOWING"
);
return
new
WindowFrameBound
(
WindowFrameBoundType
.
FOLLOWING
,
value
);
}
private
Expression
readValueOrParameter
()
{
int
index
=
parseIndex
;
Expression
value
=
readExpression
();
if
(!(
value
instanceof
ValueExpression
)
&&
!(
value
instanceof
Parameter
))
{
parseIndex
=
index
;
throw
getSyntaxError
();
}
return
new
WindowFrame
(
extent
,
exclusion
)
;
return
value
;
}
private
AggregateType
getAggregateType
(
String
name
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/AbstractAggregate.java
浏览文件 @
4f23bb18
...
...
@@ -445,7 +445,7 @@ public abstract class AbstractAggregate extends Expression {
int
size
=
ordered
.
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
aggregateData
=
createAggregateData
();
for
(
Iterator
<
Value
[]>
iter
=
frame
.
iterator
(
ordered
,
getOverOrderBySort
(),
i
,
false
);
iter
for
(
Iterator
<
Value
[]>
iter
=
frame
.
iterator
(
session
,
ordered
,
getOverOrderBySort
(),
i
,
false
);
iter
.
hasNext
();)
{
updateFromExpressions
(
session
,
aggregateData
,
iter
.
next
());
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/Window.java
浏览文件 @
4f23bb18
...
...
@@ -64,6 +64,11 @@ public final class Window {
public
Window
(
ArrayList
<
Expression
>
partitionBy
,
ArrayList
<
SelectOrderBy
>
orderBy
,
WindowFrame
frame
)
{
this
.
partitionBy
=
partitionBy
;
this
.
orderBy
=
orderBy
;
if
(
frame
==
null
)
{
frame
=
new
WindowFrame
(
WindowFrameUnits
.
RANGE
,
new
WindowFrameBound
(
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
,
null
),
null
,
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
);
}
this
.
frame
=
frame
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFrame.java
浏览文件 @
4f23bb18
...
...
@@ -11,6 +11,10 @@ import java.util.Collections;
import
java.util.Iterator
;
import
java.util.NoSuchElementException
;
import
org.h2.engine.Session
;
import
org.h2.expression.BinaryOperation
;
import
org.h2.expression.BinaryOperation.OpType
;
import
org.h2.expression.ValueExpression
;
import
org.h2.message.DbException
;
import
org.h2.result.SortOrder
;
import
org.h2.value.Value
;
...
...
@@ -20,92 +24,6 @@ import org.h2.value.Value;
*/
public
final
class
WindowFrame
{
/**
* Simple extent.
*/
public
enum
SimpleExtent
{
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW frame specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW
(
"RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"
),
/**
* RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING frame specification.
*/
RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING
(
"RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING"
),
/**
* RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING frame
* specification.
*/
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING
(
"RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING"
),
;
private
final
String
sql
;
private
SimpleExtent
(
String
sql
)
{
this
.
sql
=
sql
;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
return
sql
;
}
}
/**
* Window frame exclusion clause.
*/
public
enum
WindowFrameExclusion
{
/**
* EXCLUDE CURRENT ROW exclusion clause.
*/
EXCLUDE_CURRENT_ROW
(
"EXCLUDE CURRENT ROW"
),
/**
* EXCLUDE GROUP exclusion clause.
*/
EXCLUDE_GROUP
(
"EXCLUDE GROUP"
),
/**
* EXCLUDE TIES exclusion clause.
*/
EXCLUDE_TIES
(
"EXCLUDE TIES"
),
/**
* EXCLUDE NO OTHERS exclusion clause.
*/
EXCLUDE_NO_OTHERS
(
"EXCLUDE NO OTHERS"
),
;
private
final
String
sql
;
private
WindowFrameExclusion
(
String
sql
)
{
this
.
sql
=
sql
;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
return
sql
;
}
}
private
abstract
class
Itr
implements
Iterator
<
Value
[]>
{
final
ArrayList
<
Value
[]>
orderedRows
;
...
...
@@ -231,30 +149,100 @@ public final class WindowFrame {
}
private
final
SimpleExtent
extent
;
private
final
WindowFrameUnits
units
;
private
final
WindowFrameBound
starting
;
private
final
WindowFrameBound
following
;
private
final
WindowFrameExclusion
exclusion
;
private
static
int
toGroupStart
(
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
offset
,
int
minOffset
)
{
Value
[]
row
=
orderedRows
.
get
(
offset
);
while
(
offset
>
minOffset
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
offset
-
1
))
==
0
)
{
offset
--;
}
return
offset
;
}
private
static
int
toGroupEnd
(
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
offset
,
int
maxOffset
)
{
Value
[]
row
=
orderedRows
.
get
(
offset
);
while
(
offset
<
maxOffset
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
offset
+
1
))
==
0
)
{
offset
++;
}
return
offset
;
}
private
static
int
getIntOffset
(
WindowFrameBound
bound
,
Session
session
)
{
int
value
=
bound
.
getValue
().
getValue
(
session
).
getInt
();
if
(
value
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
);
}
return
value
;
}
private
static
Value
[]
getCompareRow
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
add
)
{
int
sortIndex
=
sortOrder
.
getQueryColumnIndexes
()[
0
];
OpType
opType
=
add
^
(
sortOrder
.
getSortTypes
()[
0
]
&
SortOrder
.
DESCENDING
)
!=
0
?
OpType
.
PLUS
:
OpType
.
MINUS
;
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
Value
[]
newRow
=
row
.
clone
();
newRow
[
sortIndex
]
=
new
BinaryOperation
(
opType
,
//
ValueExpression
.
get
(
row
[
sortIndex
]),
ValueExpression
.
get
(
getValueOffset
(
bound
,
session
)))
//
.
optimize
(
session
).
getValue
(
session
);
return
newRow
;
}
private
static
Value
getValueOffset
(
WindowFrameBound
bound
,
Session
session
)
{
Value
value
=
bound
.
getValue
().
getValue
(
session
);
if
(
value
.
getSignum
()
<
0
)
{
throw
DbException
.
getInvalidValueException
(
"unsigned"
,
value
.
getTraceSQL
());
}
return
value
;
}
/**
* Creates new instance of window frame clause.
*
* @param extent
* window frame extent
* @param units
* units
* @param starting
* starting clause
* @param following
* following clause
* @param exclusion
*
window frame exclusion
*
exclusion clause
*/
public
WindowFrame
(
SimpleExtent
extent
,
WindowFrameExclusion
exclusion
)
{
this
.
extent
=
extent
;
public
WindowFrame
(
WindowFrameUnits
units
,
WindowFrameBound
starting
,
WindowFrameBound
following
,
WindowFrameExclusion
exclusion
)
{
this
.
units
=
units
;
this
.
starting
=
starting
;
if
(
following
!=
null
&&
following
.
getType
()
==
WindowFrameBoundType
.
CURRENT_ROW
)
{
following
=
null
;
}
this
.
following
=
following
;
this
.
exclusion
=
exclusion
;
}
/**
* Checks validity of this frame.
*
* @return whether bounds of this frame valid
*/
public
boolean
isValid
()
{
WindowFrameBoundType
s
=
starting
.
getType
(),
f
=
following
!=
null
?
following
.
getType
()
:
WindowFrameBoundType
.
CURRENT_ROW
;
return
s
!=
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
&&
f
!=
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
&&
s
.
compareTo
(
f
)
<=
0
;
}
/**
* Returns whether window frame specification can be omitted.
*
* @return whether window frame specification can be omitted
*/
public
boolean
isDefault
()
{
return
extent
==
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW
return
starting
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
&&
following
==
null
&&
exclusion
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
;
}
...
...
@@ -265,13 +253,16 @@ public final class WindowFrame {
* @return whether window frame specification contains all rows in partition
*/
public
boolean
isFullPartition
()
{
return
extent
==
SimpleExtent
.
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING
return
starting
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_PRECEDING
&&
following
!=
null
&&
following
.
getType
()
==
WindowFrameBoundType
.
UNBOUNDED_FOLLOWING
&&
exclusion
==
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
;
}
/**
* Returns iterator.
*
* @param session
* the session
* @param orderedRows
* ordered rows
* @param sortOrder
...
...
@@ -280,27 +271,26 @@ public final class WindowFrame {
* index of the current row
* @param reverse
* whether iterator should iterate in reverse order
*
* @return iterator
*/
public
Iterator
<
Value
[]>
iterator
(
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
boolean
reverse
)
{
public
Iterator
<
Value
[]>
iterator
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
boolean
reverse
)
{
int
startIndex
=
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
starting
,
false
);
int
endIndex
=
following
!=
null
?
getIndex
(
session
,
orderedRows
,
sortOrder
,
currentRow
,
following
,
true
)
:
currentRow
;
if
(
endIndex
<
startIndex
)
{
return
Collections
.
emptyIterator
();
}
int
size
=
orderedRows
.
size
();
final
int
startIndex
,
endIndex
;
switch
(
extent
)
{
case
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_CURRENT_ROW:
startIndex
=
0
;
endIndex
=
currentRow
;
break
;
case
RANGE_BETWEEN_CURRENT_ROW_AND_UNBOUNDED_FOLLOWING:
startIndex
=
currentRow
;
endIndex
=
size
-
1
;
break
;
case
RANGE_BETWEEN_UNBOUNDED_PRECEDING_AND_UNBOUNDED_FOLLOWING:
if
(
startIndex
>=
size
||
endIndex
<
0
)
{
return
Collections
.
emptyIterator
();
}
if
(
startIndex
<
0
)
{
startIndex
=
0
;
}
if
(
endIndex
>=
size
)
{
endIndex
=
size
-
1
;
break
;
default
:
throw
DbException
.
getUnsupportedException
(
"window frame extent ="
+
extent
);
}
if
(
exclusion
!=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
return
complexIterator
(
orderedRows
,
sortOrder
,
currentRow
,
startIndex
,
endIndex
,
reverse
);
...
...
@@ -309,6 +299,148 @@ public final class WindowFrame {
:
new
PlainItr
(
orderedRows
,
startIndex
,
endIndex
);
}
private
int
getIndex
(
Session
session
,
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
WindowFrameBound
bound
,
boolean
forFollowing
)
{
int
size
=
orderedRows
.
size
();
int
last
=
size
-
1
;
int
index
;
switch
(
bound
.
getType
())
{
case
UNBOUNDED_PRECEDING:
index
=
-
1
;
break
;
case
PRECEDING:
switch
(
units
)
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
index
=
value
>
currentRow
?
-
1
:
currentRow
-
value
;
break
;
}
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
if
(!
forFollowing
)
{
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
0
);
while
(
value
>
0
&&
index
>
0
)
{
value
--;
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
index
-
1
,
0
);
}
if
(
value
>
0
)
{
index
=
-
1
;
}
}
else
{
if
(
value
==
0
)
{
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
last
);
}
else
{
index
=
currentRow
;
while
(
value
>
0
&&
index
>=
0
)
{
value
--;
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
index
,
0
)
-
1
;
}
}
}
break
;
}
case
RANGE:
{
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
false
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
index
>=
0
)
{
if
(!
forFollowing
)
{
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
index
--;
}
}
else
{
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
index
++;
}
}
}
else
{
index
=
~
index
;
if
(!
forFollowing
)
{
if
(
index
==
0
)
{
index
=
-
1
;
}
}
else
{
index
--;
}
}
break
;
}
default
:
throw
DbException
.
getUnsupportedException
(
"units="
+
units
);
}
break
;
case
CURRENT_ROW:
index
=
currentRow
;
break
;
case
FOLLOWING:
switch
(
units
)
{
case
ROWS:
{
int
value
=
getIntOffset
(
bound
,
session
);
int
rem
=
last
-
currentRow
;
index
=
value
>
rem
?
size
:
currentRow
+
value
;
break
;
}
case
GROUPS:
{
int
value
=
getIntOffset
(
bound
,
session
);
if
(
forFollowing
)
{
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
last
);
while
(
value
>
0
&&
index
<
last
)
{
value
--;
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
index
+
1
,
last
);
}
if
(
value
>
0
)
{
index
=
size
;
}
}
else
{
if
(
value
==
0
)
{
index
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
0
);
}
else
{
index
=
currentRow
;
while
(
value
>
0
&&
index
<=
last
)
{
value
--;
index
=
toGroupEnd
(
orderedRows
,
sortOrder
,
index
,
last
)
+
1
;
}
}
}
break
;
}
case
RANGE:
{
index
=
currentRow
;
Value
[]
row
=
getCompareRow
(
session
,
orderedRows
,
sortOrder
,
index
,
bound
,
true
);
index
=
Collections
.
binarySearch
(
orderedRows
,
row
,
sortOrder
);
if
(
index
>=
0
)
{
if
(
forFollowing
)
{
while
(
index
<
last
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
+
1
))
==
0
)
{
index
++;
}
}
else
{
while
(
index
>
0
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
index
-
1
))
==
0
)
{
index
--;
}
}
}
else
{
index
=
~
index
;
if
(
forFollowing
)
{
if
(
index
!=
size
)
{
index
--;
}
}
}
break
;
}
default
:
throw
DbException
.
getUnsupportedException
(
"units="
+
units
);
}
break
;
case
UNBOUNDED_FOLLOWING:
index
=
size
;
break
;
default
:
throw
DbException
.
getUnsupportedException
(
"window frame bound type="
+
bound
.
getType
());
}
return
index
;
}
private
Iterator
<
Value
[]>
complexIterator
(
ArrayList
<
Value
[]>
orderedRows
,
SortOrder
sortOrder
,
int
currentRow
,
int
startIndex
,
int
endIndex
,
boolean
reverse
)
{
int
size
=
orderedRows
.
size
();
...
...
@@ -320,15 +452,8 @@ public final class WindowFrame {
break
;
case
EXCLUDE_GROUP:
case
EXCLUDE_TIES:
{
int
exStart
=
currentRow
;
Value
[]
row
=
orderedRows
.
get
(
currentRow
);
while
(
exStart
>
startIndex
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
exStart
-
1
))
==
0
)
{
exStart
--;
}
int
exEnd
=
currentRow
;
while
(
exEnd
<
endIndex
&&
sortOrder
.
compare
(
row
,
orderedRows
.
get
(
exEnd
+
1
))
==
0
)
{
exEnd
++;
}
int
exStart
=
toGroupStart
(
orderedRows
,
sortOrder
,
currentRow
,
startIndex
);
int
exEnd
=
toGroupEnd
(
orderedRows
,
sortOrder
,
currentRow
,
endIndex
);
set
.
clear
(
exStart
,
exEnd
+
1
);
if
(
exclusion
==
WindowFrameExclusion
.
EXCLUDE_TIES
)
{
set
.
set
(
currentRow
);
...
...
@@ -350,11 +475,17 @@ public final class WindowFrame {
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
String
sql
=
extent
.
getSQL
();
StringBuilder
builder
=
new
StringBuilder
();
builder
.
append
(
units
.
getSQL
());
if
(
following
==
null
)
{
builder
.
append
(
' '
).
append
(
starting
.
getSQL
(
false
));
}
else
{
builder
.
append
(
" BETWEEN "
).
append
(
starting
.
getSQL
(
false
)).
append
(
" AND "
).
append
(
following
.
getSQL
(
true
));
}
if
(
exclusion
!=
WindowFrameExclusion
.
EXCLUDE_NO_OTHERS
)
{
sql
=
sql
+
' '
+
exclusion
.
getSQL
(
);
builder
.
append
(
' '
).
append
(
exclusion
.
getSQL
()
);
}
return
sql
;
return
builder
.
toString
()
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFrameBound.java
0 → 100644
浏览文件 @
4f23bb18
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
expression
.
aggregate
;
import
org.h2.expression.Expression
;
/**
* Window frame bound.
*/
public
class
WindowFrameBound
{
private
final
WindowFrameBoundType
type
;
private
final
Expression
value
;
/**
* Creates new instance of window frame bound.
*
* @param type
* bound type
* @param value
* bound value, if any
*/
public
WindowFrameBound
(
WindowFrameBoundType
type
,
Expression
value
)
{
this
.
type
=
type
;
if
(
type
==
WindowFrameBoundType
.
PRECEDING
||
type
==
WindowFrameBoundType
.
FOLLOWING
)
{
this
.
value
=
value
;
}
else
{
this
.
value
=
null
;
}
}
/**
* Returns the type
*
* @return the type
*/
public
WindowFrameBoundType
getType
()
{
return
type
;
}
/**
* Returns the value.
*
* @return the value
*/
public
Expression
getValue
()
{
return
value
;
}
/**
* Returns SQL representation.
*
* @param following
* if false return SQL for starting clause, if true return SQL
* for following clause
* @return SQL representation.
* @see Expression#getSQL()
*/
public
String
getSQL
(
boolean
following
)
{
if
(
type
==
WindowFrameBoundType
.
PRECEDING
||
type
==
WindowFrameBoundType
.
FOLLOWING
)
{
return
value
.
getSQL
()
+
' '
+
type
.
getSQL
();
}
return
type
.
getSQL
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFrameBoundType.java
0 → 100644
浏览文件 @
4f23bb18
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
expression
.
aggregate
;
/**
* Window frame bound type.
*/
public
enum
WindowFrameBoundType
{
/**
* UNBOUNDED PRECEDING clause.
*/
UNBOUNDED_PRECEDING
(
"UNBOUNDED PRECEDING"
),
/**
* PRECEDING clause.
*/
PRECEDING
(
"PRECEDING"
),
/**
* CURRENT_ROW clause.
*/
CURRENT_ROW
(
"CURRENT_ROW"
),
/**
* FOLLOWING clause.
*/
FOLLOWING
(
"FOLLOWING"
),
/**
* UNBOUNDED FOLLOWING clause.
*/
UNBOUNDED_FOLLOWING
(
"UNBOUNDED FOLLOWING"
);
private
final
String
sql
;
private
WindowFrameBoundType
(
String
sql
)
{
this
.
sql
=
sql
;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
return
sql
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFrameExclusion.java
0 → 100644
浏览文件 @
4f23bb18
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
expression
.
aggregate
;
/**
* Window frame exclusion clause.
*/
public
enum
WindowFrameExclusion
{
/**
* EXCLUDE CURRENT ROW exclusion clause.
*/
EXCLUDE_CURRENT_ROW
(
"EXCLUDE CURRENT ROW"
),
/**
* EXCLUDE GROUP exclusion clause.
*/
EXCLUDE_GROUP
(
"EXCLUDE GROUP"
),
/**
* EXCLUDE TIES exclusion clause.
*/
EXCLUDE_TIES
(
"EXCLUDE TIES"
),
/**
* EXCLUDE NO OTHERS exclusion clause.
*/
EXCLUDE_NO_OTHERS
(
"EXCLUDE NO OTHERS"
),
;
private
final
String
sql
;
private
WindowFrameExclusion
(
String
sql
)
{
this
.
sql
=
sql
;
}
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
return
sql
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFrameUnits.java
0 → 100644
浏览文件 @
4f23bb18
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
expression
.
aggregate
;
/**
* Window frame units.
*/
public
enum
WindowFrameUnits
{
/**
* ROWS unit.
*/
ROWS
,
/**
* RANGE unit.
*/
RANGE
,
/**
* GROUPS unit.
*/
GROUPS
,
;
/**
* Returns SQL representation.
*
* @return SQL representation.
* @see org.h2.expression.Expression#getSQL()
*/
public
String
getSQL
()
{
return
name
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/expression/aggregate/WindowFunction.java
浏览文件 @
4f23bb18
...
...
@@ -321,11 +321,11 @@ public class WindowFunction extends AbstractAggregate {
Value
v
;
switch
(
type
)
{
case
FIRST_VALUE:
{
v
=
getNthValue
(
frame
.
iterator
(
ordered
,
getOverOrderBySort
(),
i
,
false
),
0
,
ignoreNulls
);
v
=
getNthValue
(
frame
.
iterator
(
session
,
ordered
,
getOverOrderBySort
(),
i
,
false
),
0
,
ignoreNulls
);
break
;
}
case
LAST_VALUE:
v
=
getNthValue
(
frame
.
iterator
(
ordered
,
getOverOrderBySort
(),
i
,
true
),
0
,
ignoreNulls
);
v
=
getNthValue
(
frame
.
iterator
(
session
,
ordered
,
getOverOrderBySort
(),
i
,
true
),
0
,
ignoreNulls
);
break
;
case
NTH_VALUE:
{
int
n
=
row
[
1
].
getInt
();
...
...
@@ -333,7 +333,7 @@ public class WindowFunction extends AbstractAggregate {
throw
DbException
.
getInvalidValueException
(
"nth row"
,
n
);
}
n
--;
Iterator
<
Value
[]>
iter
=
frame
.
iterator
(
ordered
,
getOverOrderBySort
(),
i
,
fromLast
);
Iterator
<
Value
[]>
iter
=
frame
.
iterator
(
session
,
ordered
,
getOverOrderBySort
(),
i
,
fromLast
);
v
=
getNthValue
(
iter
,
n
,
ignoreNulls
);
break
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/scripts/functions/aggregate/array-agg.sql
浏览文件 @
4f23bb18
...
...
@@ -275,3 +275,160 @@ SELECT
DROP
TABLE
TEST
;
>
ok
CREATE
TABLE
TEST
(
ID
INT
,
VALUE
INT
);
>
ok
INSERT
INTO
TEST
VALUES
(
1
,
1
),
(
2
,
1
),
(
3
,
5
),
(
4
,
8
),
(
5
,
8
),
(
6
,
8
),
(
7
,
9
),
(
8
,
9
);
>
update
count
:
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
ROWS
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
R_ID
,
ARRAY_AGG
(
VALUE
)
OVER
(
ORDER
BY
VALUE
ROWS
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
R_V
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
V_ID
,
ARRAY_AGG
(
VALUE
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
V_V
,
ARRAY_AGG
(
VALUE
)
OVER
(
ORDER
BY
VALUE
DESC
RANGE
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
V_V_R
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
G_ID
,
ARRAY_AGG
(
VALUE
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
1
PRECEDING
AND
1
FOLLOWING
)
G_V
FROM
TEST
;
>
ID
VALUE
R_ID
R_V
V_ID
V_V
V_V_R
G_ID
G_V
>
-- ----- --------- --------- --------------- --------------- --------------- ------------------ ------------------
>
1
1
(
1
,
2
)
(
1
,
1
)
(
1
,
2
)
(
1
,
1
)
(
1
,
1
)
(
1
,
2
,
3
)
(
1
,
1
,
5
)
>
2
1
(
1
,
2
,
3
)
(
1
,
1
,
5
)
(
1
,
2
)
(
1
,
1
)
(
1
,
1
)
(
1
,
2
,
3
)
(
1
,
1
,
5
)
>
3
5
(
2
,
3
,
4
)
(
1
,
5
,
8
)
(
3
)
(
5
)
(
5
)
(
1
,
2
,
3
,
4
,
5
,
6
)
(
1
,
1
,
5
,
8
,
8
,
8
)
>
4
8
(
3
,
4
,
5
)
(
5
,
8
,
8
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
(
9
,
9
,
8
,
8
,
8
)
(
3
,
4
,
5
,
6
,
7
,
8
)
(
5
,
8
,
8
,
8
,
9
,
9
)
>
5
8
(
4
,
5
,
6
)
(
8
,
8
,
8
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
(
9
,
9
,
8
,
8
,
8
)
(
3
,
4
,
5
,
6
,
7
,
8
)
(
5
,
8
,
8
,
8
,
9
,
9
)
>
6
8
(
5
,
6
,
7
)
(
8
,
8
,
9
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
(
9
,
9
,
8
,
8
,
8
)
(
3
,
4
,
5
,
6
,
7
,
8
)
(
5
,
8
,
8
,
8
,
9
,
9
)
>
7
9
(
6
,
7
,
8
)
(
8
,
9
,
9
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
(
9
,
9
,
8
,
8
,
8
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
>
8
9
(
7
,
8
)
(
9
,
9
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
(
9
,
9
,
8
,
8
,
8
)
(
4
,
5
,
6
,
7
,
8
)
(
8
,
8
,
8
,
9
,
9
)
>
rows
(
ordered
):
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
ROWS
-
1
PRECEDING
)
FROM
TEST
;
>
exception
INVALID_VALUE_2
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
FROM
TEST
FETCH
FIRST
4
ROWS
ONLY
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
>
-- ----- -------------------------------------------------------------------------
>
1
1
null
>
2
1
(
1
)
>
3
5
(
1
,
2
)
>
4
8
(
2
,
3
)
>
rows
(
ordered
):
4
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
FROM
TEST
OFFSET
4
ROWS
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
ROWS
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
>
-- ----- -------------------------------------------------------------------------
>
5
8
(
6
,
7
)
>
6
8
(
7
,
8
)
>
7
9
(
8
)
>
8
9
null
>
rows
(
ordered
):
4
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
FROM
TEST
FETCH
FIRST
4
ROWS
ONLY
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
>
-- ----- --------------------------------------------------------------------------
>
1
1
null
>
2
1
(
1
)
>
3
5
(
1
,
2
)
>
4
8
(
2
,
3
)
>
rows
(
ordered
):
4
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
FROM
TEST
OFFSET
4
ROWS
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
>
-- ----- --------------------------------------------------------------------------
>
5
8
(
6
,
7
)
>
6
8
(
7
,
8
)
>
7
9
(
8
)
>
8
9
null
>
rows
(
ordered
):
4
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
UNBOUNDED
PRECEDING
AND
1
PRECEDING
)
U_P
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
P
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
F
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
1
FOLLOWING
AND
UNBOUNDED
FOLLOWING
)
U_F
FROM
TEST
;
>
ID
VALUE
U_P
P
F
U_F
>
-- ----- ------------------ ------------ --------------- ------------------
>
1
1
null
null
(
3
,
4
,
5
,
6
)
(
3
,
4
,
5
,
6
,
7
,
8
)
>
2
1
null
null
(
3
,
4
,
5
,
6
)
(
3
,
4
,
5
,
6
,
7
,
8
)
>
3
5
(
1
,
2
)
(
1
,
2
)
(
4
,
5
,
6
,
7
,
8
)
(
4
,
5
,
6
,
7
,
8
)
>
4
8
(
1
,
2
,
3
)
(
1
,
2
,
3
)
(
7
,
8
)
(
7
,
8
)
>
5
8
(
1
,
2
,
3
)
(
1
,
2
,
3
)
(
7
,
8
)
(
7
,
8
)
>
6
8
(
1
,
2
,
3
)
(
1
,
2
,
3
)
(
7
,
8
)
(
7
,
8
)
>
7
9
(
1
,
2
,
3
,
4
,
5
,
6
)
(
3
,
4
,
5
,
6
)
null
null
>
8
9
(
1
,
2
,
3
,
4
,
5
,
6
)
(
3
,
4
,
5
,
6
)
null
null
>
rows
(
ordered
):
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
1
PRECEDING
AND
0
PRECEDING
)
P
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
GROUPS
BETWEEN
0
FOLLOWING
AND
1
FOLLOWING
)
F
FROM
TEST
;
>
ID
VALUE
P
F
>
-- ----- --------------- ---------------
>
1
1
(
1
,
2
)
(
1
,
2
,
3
)
>
2
1
(
1
,
2
)
(
1
,
2
,
3
)
>
3
5
(
1
,
2
,
3
)
(
3
,
4
,
5
,
6
)
>
4
8
(
3
,
4
,
5
,
6
)
(
4
,
5
,
6
,
7
,
8
)
>
5
8
(
3
,
4
,
5
,
6
)
(
4
,
5
,
6
,
7
,
8
)
>
6
8
(
3
,
4
,
5
,
6
)
(
4
,
5
,
6
,
7
,
8
)
>
7
9
(
4
,
5
,
6
,
7
,
8
)
(
7
,
8
)
>
8
9
(
4
,
5
,
6
,
7
,
8
)
(
7
,
8
)
>
rows
(
ordered
):
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
ID
RANGE
BETWEEN
CURRENT
ROW
AND
1
PRECEDING
)
FROM
TEST
;
>
exception
SYNTAX_ERROR_1
DROP
TABLE
TEST
;
>
ok
CREATE
TABLE
TEST
(
ID
INT
,
VALUE
INT
);
>
ok
INSERT
INTO
TEST
VALUES
(
1
,
1
),
(
2
,
1
),
(
3
,
2
),
(
4
,
2
),
(
5
,
3
),
(
6
,
3
),
(
7
,
4
),
(
8
,
4
);
>
update
count
:
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
FROM
TEST
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
2
PRECEDING
AND
1
PRECEDING
)
>
-- ----- -----------------------------------------------------------------------------
>
1
1
null
>
2
1
null
>
3
2
(
1
,
2
)
>
4
2
(
1
,
2
)
>
5
3
(
1
,
2
,
3
,
4
)
>
6
3
(
1
,
2
,
3
,
4
)
>
7
4
(
3
,
4
,
5
,
6
)
>
8
4
(
3
,
4
,
5
,
6
)
>
rows
(
ordered
):
8
SELECT
*
,
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
FROM
TEST
;
>
ID
VALUE
ARRAY_AGG
(
ID
)
OVER
(
ORDER
BY
VALUE
RANGE
BETWEEN
1
FOLLOWING
AND
2
FOLLOWING
)
>
-- ----- -----------------------------------------------------------------------------
>
1
1
(
3
,
4
,
5
,
6
)
>
2
1
(
3
,
4
,
5
,
6
)
>
3
2
(
5
,
6
,
7
,
8
)
>
4
2
(
5
,
6
,
7
,
8
)
>
5
3
(
7
,
8
)
>
6
3
(
7
,
8
)
>
7
4
null
>
8
4
null
>
rows
(
ordered
):
8
DROP
TABLE
TEST
;
>
ok
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/scripts/functions/window/nth_value.sql
浏览文件 @
4f23bb18
...
...
@@ -139,8 +139,8 @@ SELECT ID, CATEGORY,
NTH_VALUE
(
CATEGORY
,
2
)
OVER
(
ORDER
BY
CATEGORY
RANGE
BETWEEN
UNBOUNDED
PRECEDING
AND
CURRENT
ROW
)
C
,
NTH_VALUE
(
CATEGORY
,
2
)
OVER
(
ORDER
BY
CATEGORY
RANGE
BETWEEN
UNBOUNDED
PRECEDING
AND
CURRENT
ROW
EXCLUDE
CURRENT
ROW
)
FROM
TEST
FETCH
FIRST
3
ROWS
ONLY
;
>
ID
CATEGORY
C
NTH_VALUE
(
CATEGORY
,
2
)
OVER
(
ORDER
BY
CATEGORY
RANGE
BETWEEN
UNBOUNDED
PRECEDING
AND
CURRENT
ROW
EXCLUDE
CURRENT
ROW
)
>
-- -------- ---- ---------------------------------------------------------------------------------------------
------------------------
>
ID
CATEGORY
C
NTH_VALUE
(
CATEGORY
,
2
)
OVER
(
ORDER
BY
CATEGORY
RANGE
UNBOUNDED
PRECEDING
EXCLUDE
CURRENT
ROW
)
>
-- -------- ---- ---------------------------------------------------------------------------------------------
>
1
1
null
null
>
2
1
1
null
>
3
1
1
1
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论