Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
d08cab6c
提交
d08cab6c
authored
9月 17, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Add ROW_NUMBER(), RANK(), and DENSE_RANK() window functions
上级
a306265c
显示空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
550 行增加
和
49 行删除
+550
-49
help.csv
h2/src/docsrc/help/help.csv
+95
-22
functions.html
h2/src/docsrc/html/functions.html
+49
-0
Parser.java
h2/src/main/org/h2/command/Parser.java
+33
-12
Function.java
h2/src/main/org/h2/expression/Function.java
+0
-5
AbstractAggregate.java
...c/main/org/h2/expression/aggregate/AbstractAggregate.java
+23
-2
Aggregate.java
h2/src/main/org/h2/expression/aggregate/Aggregate.java
+5
-0
JavaAggregate.java
h2/src/main/org/h2/expression/aggregate/JavaAggregate.java
+5
-0
Window.java
h2/src/main/org/h2/expression/aggregate/Window.java
+1
-1
WindowFunction.java
h2/src/main/org/h2/expression/aggregate/WindowFunction.java
+247
-0
package.html
h2/src/main/org/h2/expression/aggregate/package.html
+1
-1
TestScript.java
h2/src/test/org/h2/test/scripts/TestScript.java
+5
-2
rownum.sql
h2/src/test/org/h2/test/scripts/functions/system/rownum.sql
+1
-1
row_number.sql
.../test/org/h2/test/scripts/functions/window/row_number.sql
+79
-0
testScript.sql
h2/src/test/org/h2/test/scripts/testScript.sql
+3
-3
GenerateDoc.java
h2/src/tools/org/h2/build/doc/GenerateDoc.java
+2
-0
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+1
-0
没有找到文件。
h2/src/docsrc/help/help.csv
浏览文件 @
d08cab6c
...
...
@@ -2533,6 +2533,19 @@ The column list of the resulting table is C1, C2, and so on.
SELECT * FROM (VALUES(1, 'Hello'), (2, 'World')) AS V;
"
"Other Grammar","Window specification","
([PARTITION BY expression [,...])] [ORDER BY order [,...]])
","
A window specification for a window function or aggregate.
Window functions are currently experimental in H2 and should be used with caution.
They also may require a lot of memory for large queries.
","
()
(ORDER BY ID)
(PARTITION BY CATEGORY)
(PARTITION BY CATEGORY ORDER BY NAME, ID)
"
"Other Grammar","Term","
value
| columnName
...
...
@@ -3251,7 +3264,8 @@ INTERVAL MINUTE TO SECOND
"
"Functions (Aggregate)","AVG","
AVG ( [ DISTINCT ] { numeric } ) [ FILTER ( WHERE expression ) ]
AVG ( [ DISTINCT ] { numeric } )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The average (mean) value.
If no rows are selected, the result is NULL.
...
...
@@ -3262,7 +3276,8 @@ AVG(X)
"
"Functions (Aggregate)","BIT_AND","
BIT_AND(expression) [ FILTER ( WHERE expression ) ]
BIT_AND(expression)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The bitwise AND of all non-null values.
If no rows are selected, the result is NULL.
...
...
@@ -3272,7 +3287,8 @@ BIT_AND(ID)
"
"Functions (Aggregate)","BIT_OR","
BIT_OR(expression) [ FILTER ( WHERE expression ) ]
BIT_OR(expression)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The bitwise OR of all non-null values.
If no rows are selected, the result is NULL.
...
...
@@ -3282,7 +3298,8 @@ BIT_OR(ID)
"
"Functions (Aggregate)","BOOL_AND","
BOOL_AND(boolean) [ FILTER ( WHERE expression ) ]
BOOL_AND(boolean)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
Returns true if all expressions are true.
If no rows are selected, the result is NULL.
...
...
@@ -3292,7 +3309,8 @@ BOOL_AND(ID>10)
"
"Functions (Aggregate)","BOOL_OR","
BOOL_OR(boolean) [ FILTER ( WHERE expression ) ]
BOOL_OR(boolean)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
Returns true if any expression is true.
If no rows are selected, the result is NULL.
...
...
@@ -3302,7 +3320,8 @@ BOOL_OR(NAME LIKE 'W%')
"
"Functions (Aggregate)","COUNT","
COUNT( { * | { [ DISTINCT ] expression } } ) [ FILTER ( WHERE expression ) ]
COUNT( { * | { [ DISTINCT ] expression } } )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The count of all row, or of the non-null values.
This method returns a long.
...
...
@@ -3315,7 +3334,8 @@ COUNT(*)
"Functions (Aggregate)","GROUP_CONCAT","
GROUP_CONCAT ( [ DISTINCT ] string
[ ORDER BY { expression [ ASC | DESC ] } [,...] ]
[ SEPARATOR expression ] ) [ FILTER ( WHERE expression ) ]
[ SEPARATOR expression ] )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
Concatenates strings with a separator.
The default separator is a ',' (without space).
...
...
@@ -3329,7 +3349,7 @@ GROUP_CONCAT(NAME ORDER BY ID SEPARATOR ', ')
"Functions (Aggregate)","ARRAY_AGG","
ARRAY_AGG ( [ DISTINCT ] string
[ ORDER BY { expression [ ASC | DESC ] } [,...] ] )
[
FILTER ( WHERE expression )
]
[
FILTER (WHERE expression)] [OVER windowSpecification
]
","
Aggregate the value into an array.
This method returns an array.
...
...
@@ -3340,7 +3360,8 @@ ARRAY_AGG(NAME ORDER BY ID)
"
"Functions (Aggregate)","MAX","
MAX(value) [ FILTER ( WHERE expression ) ]
MAX(value)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The highest value.
If no rows are selected, the result is NULL.
...
...
@@ -3351,7 +3372,8 @@ MAX(NAME)
"
"Functions (Aggregate)","MIN","
MIN(value) [ FILTER ( WHERE expression ) ]
MIN(value)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The lowest value.
If no rows are selected, the result is NULL.
...
...
@@ -3362,7 +3384,8 @@ MIN(NAME)
"
"Functions (Aggregate)","SUM","
SUM( [ DISTINCT ] { numeric } ) [ FILTER ( WHERE expression ) ]
SUM( [ DISTINCT ] { numeric } )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The sum of all values.
If no rows are selected, the result is NULL.
...
...
@@ -3374,7 +3397,8 @@ SUM(X)
"
"Functions (Aggregate)","SELECTIVITY","
SELECTIVITY(value) [ FILTER ( WHERE expression ) ]
SELECTIVITY(value)
[FILTER (WHERE expression)] [OVER windowSpecification]
","
Estimates the selectivity (0-100) of a value.
The value is defined as (100 * distinctCount / rowCount).
...
...
@@ -3386,7 +3410,8 @@ SELECT SELECTIVITY(FIRSTNAME), SELECTIVITY(NAME) FROM TEST WHERE ROWNUM()<20000
"
"Functions (Aggregate)","STDDEV_POP","
STDDEV_POP( [ DISTINCT ] numeric ) [ FILTER ( WHERE expression ) ]
STDDEV_POP( [ DISTINCT ] numeric )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The population standard deviation.
This method returns a double.
...
...
@@ -3397,7 +3422,8 @@ STDDEV_POP(X)
"
"Functions (Aggregate)","STDDEV_SAMP","
STDDEV_SAMP( [ DISTINCT ] numeric ) [ FILTER ( WHERE expression ) ]
STDDEV_SAMP( [ DISTINCT ] numeric )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The sample standard deviation.
This method returns a double.
...
...
@@ -3408,7 +3434,8 @@ STDDEV(X)
"
"Functions (Aggregate)","VAR_POP","
VAR_POP( [ DISTINCT ] numeric ) [ FILTER ( WHERE expression ) ]
VAR_POP( [ DISTINCT ] numeric )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The population variance (square of the population standard deviation).
This method returns a double.
...
...
@@ -3419,7 +3446,8 @@ VAR_POP(X)
"
"Functions (Aggregate)","VAR_SAMP","
VAR_SAMP( [ DISTINCT ] numeric ) [ FILTER ( WHERE expression ) ]
VAR_SAMP( [ DISTINCT ] numeric )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The sample variance (square of the sample standard deviation).
This method returns a double.
...
...
@@ -3430,7 +3458,8 @@ VAR_SAMP(X)
"
"Functions (Aggregate)","MEDIAN","
MEDIAN( [ DISTINCT ] value ) [ FILTER ( WHERE expression ) ]
MEDIAN( [ DISTINCT ] value )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
The value separating the higher half of a values from the lower half.
Returns the middle value or an interpolated value between two middle values if number of values is even.
...
...
@@ -3445,7 +3474,7 @@ MEDIAN(X)
"Functions (Aggregate)","MODE","
{ MODE( value ) [ ORDER BY expression [ ASC | DESC ] ] }
| { MODE() WITHIN GROUP(ORDER BY expression [ ASC | DESC ]) }
[
FILTER ( WHERE expression )
]
[
FILTER (WHERE expression)] [OVER windowSpecification
]
","
Returns the value that occurs with the greatest frequency.
If there are multiple values with the same frequency only one value will be returned.
...
...
@@ -3464,7 +3493,8 @@ MODE() WITHIN GROUP(ORDER BY X)
"
"Functions (Aggregate)","ENVELOPE","
ENVELOPE( value ) [ FILTER ( WHERE expression ) ]
ENVELOPE( value )
[FILTER (WHERE expression)] [OVER windowSpecification]
","
Returns the minimum bounding box that encloses all specified GEOMETRY values.
Only 2D coordinate plane is supported.
...
...
@@ -4931,14 +4961,14 @@ READONLY()
"
"Functions (System)","ROWNUM","
{ ROWNUM() } | { ROW_NUMBER() OVER() }
ROWNUM()
","
Returns the number of the current row.
This method returns a
long
.
This method returns a
n integer value
.
It is supported for SELECT statements, as well as for DELETE and UPDATE.
The first row has the row number 1, and is calculated before ordering and grouping the result set,
but after evaluating index conditions (even when the index conditions are specified in an outer query).
To get the row number after ordering and grouping, use a subquery
.
Use the ROW_NUMBER() OVER () function to get row numbers after grouping or in specified order
.
","
SELECT ROWNUM(), * FROM TEST;
SELECT ROWNUM(), * FROM (SELECT * FROM TEST ORDER BY NAME);
...
...
@@ -5036,6 +5066,49 @@ Returns the H2 version as a String.
H2VERSION()
"
"Functions (Window)","ROW_NUMBER","
ROW_NUMBER() OVER windowSpecification
","
Returns the number of the current row starting with 1.
Window functions are currently experimental in H2 and should be used with caution.
They also may require a lot of memory for large queries.
","
SELECT ROW_NUMBER() OVER (), * FROM TEST;
SELECT ROW_NUMBER() OVER (ORDER BY ID), * FROM TEST;
SELECT ROW_NUMBER() OVER (PARTITION BY CATEGORY ORDER BY ID), * FROM TEST;
"
"Functions (Window)","RANK","
RANK() OVER windowSpecification
","
Returns the rank of the current row.
The rank of a row is the number of rows that precede this row plus 1.
If two or more rows have the same values in ORDER BY columns, these rows get the same rank from the first row with the same values.
It means that gaps in ranks are possible.
Window functions are currently experimental in H2 and should be used with caution.
They also may require a lot of memory for large queries.
","
SELECT RANK() OVER (ORDER BY ID), * FROM TEST;
SELECT RANK() OVER (PARTITION BY CATEGORY ORDER BY ID), * FROM TEST;
"
"Functions (Window)","DENSE_RANK","
DENSE_RANK() OVER windowSpecification
","
Returns the dense rank of the current row.
The rank of a row is the number of groups of rows with the same values in ORDER BY columns that precede group with this row plus 1.
If two or more rows have the same values in ORDER BY columns, these rows get the same rank.
Gaps in ranks are not possible.
Window functions are currently experimental in H2 and should be used with caution.
They also may require a lot of memory for large queries.
","
SELECT RANK() OVER (ORDER BY ID), * FROM TEST;
SELECT RANK() OVER (PARTITION BY CATEGORY ORDER BY ID), * FROM TEST;
"
"System Tables","Information Schema","
INFORMATION_SCHEMA
","
...
...
h2/src/docsrc/html/functions.html
浏览文件 @
d08cab6c
...
...
@@ -159,6 +159,34 @@ syntax-end -->
</table>
<!-- railroad-end -->
<h3>
Window Functions
</h3>
<!-- syntax-start
<p class="notranslate">
<c:forEach var="item" items="functionsWindow">
<a href="#${item.link}" >${item.topic}</a><br />
</c:forEach>
</p>
syntax-end -->
<!-- railroad-start -->
<table
class=
"notranslate index"
>
<tr>
<td
class=
"index"
>
<c:forEach
var=
"item"
items=
"functionsWindow-0"
>
<a
href=
"#${item.link}"
>
${item.topic}
</a><br
/>
</c:forEach>
</td><td
class=
"index"
>
<c:forEach
var=
"item"
items=
"functionsWindow-1"
>
<a
href=
"#${item.link}"
>
${item.topic}
</a><br
/>
</c:forEach>
</td><td
class=
"index"
>
<c:forEach
var=
"item"
items=
"functionsWindow-2"
>
<a
href=
"#${item.link}"
>
${item.topic}
</a><br
/>
</c:forEach>
</td>
</tr>
</table>
<!-- railroad-end -->
<!-- railroad-start -->
<h2>
Details
</h2>
<p>
Click on the header to switch between railroad diagram and BNF.
</p>
...
...
@@ -269,6 +297,27 @@ syntax-end -->
<p
class=
"notranslate"
>
${item.example}
</p>
</c:forEach>
<h2>
Window Functions
</h2>
<c:forEach
var=
"item"
items=
"functionsWindow"
>
<h3
id=
"${item.link}"
class=
"notranslate"
onclick=
"switchBnf(this)"
>
${item.topic}
</h3>
<!-- railroad-start -->
<pre
name=
"bnf"
style=
"display: none"
>
${item.syntax}
</pre>
<div
name=
"railroad"
>
${item.railroad}
</div>
<!-- railroad-end -->
<!-- syntax-start
<pre>
${item.syntax}
</pre>
syntax-end -->
<p>
${item.text}
</p>
<p>
Example:
</p>
<p
class=
"notranslate"
>
${item.example}
</p>
</c:forEach>
<!--[if lte IE 7]><script language="javascript">switchBnf(null);</script><![endif]-->
<!-- [close] { -->
</div></td></tr></table>
<!-- } --><!-- analytics -->
</body></html>
...
...
h2/src/main/org/h2/command/Parser.java
浏览文件 @
d08cab6c
...
...
@@ -175,6 +175,8 @@ import org.h2.expression.aggregate.Aggregate;
import
org.h2.expression.aggregate.Aggregate.AggregateType
;
import
org.h2.expression.aggregate.JavaAggregate
;
import
org.h2.expression.aggregate.Window
;
import
org.h2.expression.aggregate.WindowFunction
;
import
org.h2.expression.aggregate.WindowFunction.WindowFunctionType
;
import
org.h2.index.Index
;
import
org.h2.message.DbException
;
import
org.h2.result.SortOrder
;
...
...
@@ -3032,13 +3034,15 @@ public class Parser {
}
private
void
readFilterAndOver
(
AbstractAggregate
aggregate
)
{
if
(
readIf
(
"FILTER"
))
{
boolean
isAggregate
=
aggregate
.
isAggregate
();
if
(
isAggregate
&&
readIf
(
"FILTER"
))
{
read
(
OPEN_PAREN
);
read
(
WHERE
);
Expression
filterCondition
=
readExpression
();
read
(
CLOSE_PAREN
);
aggregate
.
setFilterCondition
(
filterCondition
);
}
Window
over
=
null
;
if
(
readIf
(
"OVER"
))
{
read
(
OPEN_PAREN
);
ArrayList
<
Expression
>
partitionBy
=
null
;
...
...
@@ -3054,10 +3058,15 @@ public class Parser {
if
(
readIf
(
ORDER
))
{
read
(
"BY"
);
orderBy
=
parseSimpleOrderList
();
}
else
if
(!
isAggregate
)
{
orderBy
=
new
ArrayList
<>(
0
);
}
read
(
CLOSE_PAREN
);
aggregate
.
setOverCondition
(
new
Window
(
partitionBy
,
orderBy
));
over
=
new
Window
(
partitionBy
,
orderBy
);
aggregate
.
setOverCondition
(
over
);
currentSelect
.
setWindowQuery
();
}
else
if
(!
isAggregate
)
{
throw
getSyntaxError
();
}
else
{
currentSelect
.
setGroupQuery
();
}
...
...
@@ -3088,6 +3097,10 @@ public class Parser {
}
Function
function
=
Function
.
getFunction
(
database
,
name
);
if
(
function
==
null
)
{
WindowFunction
windowFunction
=
readWindowFunction
(
name
);
if
(
windowFunction
!=
null
)
{
return
windowFunction
;
}
UserAggregate
aggregate
=
database
.
findAggregate
(
name
);
if
(
aggregate
!=
null
)
{
return
readJavaAggregate
(
aggregate
);
...
...
@@ -3233,16 +3246,6 @@ public class Parser {
tf
.
setColumns
(
columns
);
break
;
}
case
Function
.
ROW_NUMBER
:
read
(
CLOSE_PAREN
);
read
(
"OVER"
);
read
(
OPEN_PAREN
);
read
(
CLOSE_PAREN
);
if
(
currentSelect
==
null
&&
currentPrepared
==
null
)
{
throw
getSyntaxError
();
}
return
new
Rownum
(
currentSelect
==
null
?
currentPrepared
:
currentSelect
);
default
:
if
(!
readIf
(
CLOSE_PAREN
))
{
int
i
=
0
;
...
...
@@ -3255,6 +3258,24 @@ public class Parser {
return
function
;
}
private
WindowFunction
readWindowFunction
(
String
name
)
{
if
(!
database
.
getSettings
().
databaseToUpper
)
{
// if not yet converted to uppercase, do it now
name
=
StringUtils
.
toUpperEnglish
(
name
);
}
WindowFunctionType
type
=
WindowFunctionType
.
get
(
name
);
if
(
type
==
null
)
{
return
null
;
}
if
(
currentSelect
==
null
)
{
throw
getSyntaxError
();
}
read
(
CLOSE_PAREN
);
WindowFunction
function
=
new
WindowFunction
(
type
,
currentSelect
);
readFilterAndOver
(
function
);
return
function
;
}
private
Expression
readFunctionWithoutParameters
(
String
name
)
{
if
(
database
.
isAllowBuiltinAliasOverride
())
{
FunctionAlias
functionAlias
=
database
.
getSchema
(
session
.
getCurrentSchemaName
()).
findFunction
(
name
);
...
...
h2/src/main/org/h2/expression/Function.java
浏览文件 @
d08cab6c
...
...
@@ -146,8 +146,6 @@ public class Function extends Expression implements FunctionCall {
*/
public
static
final
int
H2VERSION
=
231
;
public
static
final
int
ROW_NUMBER
=
300
;
protected
static
final
int
VAR_ARGS
=
-
1
;
private
static
final
long
PRECISION_UNKNOWN
=
-
1
;
...
...
@@ -470,9 +468,6 @@ public class Function extends Expression implements FunctionCall {
addFunctionWithNull
(
"TABLE_DISTINCT"
,
TABLE_DISTINCT
,
VAR_ARGS
,
Value
.
RESULT_SET
);
// pseudo function
addFunctionWithNull
(
"ROW_NUMBER"
,
ROW_NUMBER
,
0
,
Value
.
LONG
);
// ON DUPLICATE KEY VALUES function
addFunction
(
"VALUES"
,
VALUES
,
1
,
Value
.
NULL
,
false
,
true
,
false
);
}
...
...
h2/src/main/org/h2/expression/aggregate/AbstractAggregate.java
浏览文件 @
d08cab6c
...
...
@@ -25,7 +25,7 @@ import org.h2.value.ValueArray;
import
org.h2.value.ValueInt
;
/**
* A base class for aggregates.
* A base class for aggregates
and window functions
.
*/
public
abstract
class
AbstractAggregate
extends
Expression
{
...
...
@@ -65,7 +65,11 @@ public abstract class AbstractAggregate extends Expression {
* FILTER condition
*/
public
void
setFilterCondition
(
Expression
filterCondition
)
{
if
(
isAggregate
())
{
this
.
filterCondition
=
filterCondition
;
}
else
{
throw
DbException
.
getUnsupportedException
(
"Window function"
);
}
}
/**
...
...
@@ -78,6 +82,23 @@ public abstract class AbstractAggregate extends Expression {
this
.
over
=
over
;
}
/**
* Checks whether this expression is an aggregate function.
*
* @return true if this is an aggregate function (including aggregates with
* OVER clause), false if this is a window function
*/
public
abstract
boolean
isAggregate
();
/**
* Returns the sort order for OVER clause.
*
* @return the sort order for OVER clause
*/
SortOrder
getOverOrderBySort
()
{
return
overOrderBySort
;
}
@Override
public
void
mapColumns
(
ColumnResolver
resolver
,
int
level
)
{
if
(
filterCondition
!=
null
)
{
...
...
h2/src/main/org/h2/expression/aggregate/Aggregate.java
浏览文件 @
d08cab6c
...
...
@@ -251,6 +251,11 @@ public class Aggregate extends AbstractAggregate {
return
AGGREGATES
.
get
(
name
);
}
@Override
public
boolean
isAggregate
()
{
return
true
;
}
/**
* Set the order for ARRAY_AGG() or GROUP_CONCAT() aggregate.
*
...
...
h2/src/main/org/h2/expression/aggregate/JavaAggregate.java
浏览文件 @
d08cab6c
...
...
@@ -40,6 +40,11 @@ public class JavaAggregate extends AbstractAggregate {
this
.
args
=
args
;
}
@Override
public
boolean
isAggregate
()
{
return
true
;
}
@Override
public
int
getCost
()
{
int
cost
=
5
;
...
...
h2/src/main/org/h2/expression/aggregate/Window.java
浏览文件 @
d08cab6c
...
...
@@ -33,7 +33,7 @@ public final class Window {
* ORDER BY clause, or null
*/
static
void
appendOrderBy
(
StringBuilder
builder
,
ArrayList
<
SelectOrderBy
>
orderBy
)
{
if
(
orderBy
!=
null
)
{
if
(
orderBy
!=
null
&&
!
orderBy
.
isEmpty
()
)
{
builder
.
append
(
" ORDER BY "
);
for
(
int
i
=
0
;
i
<
orderBy
.
size
();
i
++)
{
SelectOrderBy
o
=
orderBy
.
get
(
i
);
...
...
h2/src/main/org/h2/expression/aggregate/WindowFunction.java
0 → 100644
浏览文件 @
d08cab6c
/*
* 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.command.dml.Select
;
import
org.h2.engine.Session
;
import
org.h2.expression.ExpressionVisitor
;
import
org.h2.message.DbException
;
import
org.h2.value.Value
;
import
org.h2.value.ValueInt
;
/**
* A window function.
*/
public
class
WindowFunction
extends
AbstractAggregate
{
/**
* A type of a window function.
*/
public
enum
WindowFunctionType
{
/**
* The type for ROW_NUMBER() window function.
*/
ROW_NUMBER
,
/**
* The type for RANK() window function.
*/
RANK
,
/**
* The type for DENSE_RANK() window function.
*/
DENSE_RANK
,
;
/**
* Returns the type of window function with the specified name, or null.
*
* @param name
* name of a window function
* @return the type of window function, or null.
*/
public
static
WindowFunctionType
get
(
String
name
)
{
switch
(
name
)
{
case
"ROW_NUMBER"
:
return
WindowFunctionType
.
ROW_NUMBER
;
case
"RANK"
:
return
RANK
;
case
"DENSE_RANK"
:
return
WindowFunctionType
.
DENSE_RANK
;
default
:
return
null
;
}
}
}
private
static
class
RowNumberData
{
int
number
;
RowNumberData
()
{
}
}
private
static
final
class
RankData
extends
RowNumberData
{
Value
[]
previousRow
;
int
previousNumber
;
RankData
()
{
}
}
private
WindowFunctionType
type
;
/**
* Creates new instance of a window function.
*
* @param type
* the type
* @param select
* the select statement
*/
public
WindowFunction
(
WindowFunctionType
type
,
Select
select
)
{
super
(
select
,
false
);
this
.
type
=
type
;
}
@Override
public
boolean
isAggregate
()
{
return
false
;
}
@Override
protected
void
updateAggregate
(
Session
session
,
Object
aggregateData
)
{
switch
(
type
)
{
case
ROW_NUMBER:
((
RowNumberData
)
aggregateData
).
number
++;
break
;
case
RANK:
case
DENSE_RANK:
{
RankData
data
=
(
RankData
)
aggregateData
;
data
.
number
++;
data
.
previousNumber
++;
break
;
}
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
}
@Override
protected
void
updateGroupAggregates
(
Session
session
,
int
stage
)
{
// Nothing to do
}
@Override
protected
int
getNumExpressions
()
{
return
0
;
}
@Override
protected
void
rememberExpressions
(
Session
session
,
Value
[]
array
)
{
// Nothing to do
}
@Override
protected
void
updateFromExpressions
(
Session
session
,
Object
aggregateData
,
Value
[]
array
)
{
switch
(
type
)
{
case
ROW_NUMBER:
((
RowNumberData
)
aggregateData
).
number
++;
break
;
case
RANK:
case
DENSE_RANK:
{
RankData
data
=
(
RankData
)
aggregateData
;
data
.
number
++;
Value
[]
previous
=
data
.
previousRow
;
if
(
previous
==
null
)
{
data
.
previousNumber
++;
}
else
{
if
(
getOverOrderBySort
().
compare
(
previous
,
array
)
!=
0
)
{
if
(
type
==
WindowFunctionType
.
RANK
)
{
data
.
previousNumber
=
data
.
number
;
}
else
/* DENSE_RANK */
{
data
.
previousNumber
++;
}
}
}
data
.
previousRow
=
array
;
break
;
}
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
}
@Override
protected
Object
createAggregateData
()
{
switch
(
type
)
{
case
ROW_NUMBER:
return
new
RowNumberData
();
case
RANK:
case
DENSE_RANK:
return
new
RankData
();
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
}
@Override
protected
Value
getAggregatedValue
(
Session
session
,
Object
aggregateData
)
{
switch
(
type
)
{
case
ROW_NUMBER:
return
ValueInt
.
get
(((
RowNumberData
)
aggregateData
).
number
);
case
RANK:
case
DENSE_RANK:
return
ValueInt
.
get
(((
RankData
)
aggregateData
).
previousNumber
);
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
}
@Override
public
int
getType
()
{
return
Value
.
INT
;
}
@Override
public
int
getScale
()
{
return
0
;
}
@Override
public
long
getPrecision
()
{
return
ValueInt
.
PRECISION
;
}
@Override
public
int
getDisplaySize
()
{
return
ValueInt
.
DISPLAY_SIZE
;
}
@Override
public
String
getSQL
()
{
String
text
;
switch
(
type
)
{
case
ROW_NUMBER:
text
=
"ROW_NUMBER"
;
break
;
case
RANK:
text
=
"RANK"
;
break
;
case
DENSE_RANK:
text
=
"DENSE_RANK"
;
break
;
default
:
throw
DbException
.
throwInternalError
(
"type="
+
type
);
}
StringBuilder
builder
=
new
StringBuilder
().
append
(
text
).
append
(
"()"
);
return
appendTailConditions
(
builder
).
toString
();
}
@Override
public
boolean
isEverything
(
ExpressionVisitor
visitor
)
{
if
(
visitor
.
getType
()
==
ExpressionVisitor
.
OPTIMIZABLE_MIN_MAX_COUNT_ALL
)
{
return
false
;
}
return
true
;
}
@Override
public
int
getCost
()
{
int
cost
=
1
;
return
cost
;
}
}
h2/src/main/org/h2/expression/aggregate/package.html
浏览文件 @
d08cab6c
...
...
@@ -9,6 +9,6 @@ Initial Developer: H2 Group
Javadoc package documentation
</title></head><body
style=
"font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"
><p>
Aggregate functions.
Aggregate
and window
functions.
</p></body></html>
\ No newline at end of file
h2/src/test/org/h2/test/scripts/TestScript.java
浏览文件 @
d08cab6c
...
...
@@ -136,9 +136,9 @@ public class TestScript extends TestDb {
for
(
String
s
:
new
String
[]
{
"help"
})
{
testScript
(
"other/"
+
s
+
".sql"
);
}
for
(
String
s
:
new
String
[]
{
"avg"
,
"bit-and"
,
"bit-or"
,
"count"
,
"envelope"
,
for
(
String
s
:
new
String
[]
{
"a
rray-agg"
,
"a
vg"
,
"bit-and"
,
"bit-or"
,
"count"
,
"envelope"
,
"group-concat"
,
"max"
,
"median"
,
"min"
,
"mode"
,
"selectivity"
,
"stddev-pop"
,
"stddev-samp"
,
"sum"
,
"var-pop"
,
"var-samp"
,
"array-agg"
})
{
"stddev-samp"
,
"sum"
,
"var-pop"
,
"var-samp"
})
{
testScript
(
"functions/aggregate/"
+
s
+
".sql"
);
}
for
(
String
s
:
new
String
[]
{
"abs"
,
"acos"
,
"asin"
,
"atan"
,
"atan2"
,
...
...
@@ -179,6 +179,9 @@ public class TestScript extends TestDb {
"parsedatetime"
,
"quarter"
,
"second"
,
"truncate"
,
"week"
,
"year"
,
"date_trunc"
})
{
testScript
(
"functions/timeanddate/"
+
s
+
".sql"
);
}
for
(
String
s
:
new
String
[]
{
"row_number"
})
{
testScript
(
"functions/window/"
+
s
+
".sql"
);
}
deleteDb
(
"script"
);
System
.
out
.
flush
();
...
...
h2/src/test/org/h2/test/scripts/functions/system/rownum.sql
浏览文件 @
d08cab6c
...
...
@@ -7,7 +7,7 @@
create
table
test
as
(
select
char
(
x
)
as
str
from
system_range
(
48
,
90
));
>
ok
select
row
_number
()
over
()
as
rnum
,
str
from
test
where
str
=
'A'
;
select
row
num
()
as
rnum
,
str
from
test
where
str
=
'A'
;
>
RNUM
STR
>
---- ---
>
1
A
...
...
h2/src/test/org/h2/test/scripts/functions/window/row_number.sql
0 → 100644
浏览文件 @
d08cab6c
-- 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
--
CREATE
TABLE
TEST
(
ID
INT
PRIMARY
KEY
,
CATEGORY
INT
,
VALUE
INT
);
>
ok
INSERT
INTO
TEST
VALUES
(
1
,
1
,
11
),
(
2
,
1
,
12
),
(
3
,
1
,
13
),
(
4
,
2
,
21
),
(
5
,
2
,
22
),
(
6
,
3
,
31
),
(
7
,
3
,
32
),
(
8
,
3
,
33
);
>
update
count
:
8
SELECT
*
,
ROW_NUMBER
()
OVER
()
RN
,
RANK
()
OVER
()
RK
,
DENSE_RANK
()
OVER
()
DR
,
ROW_NUMBER
()
OVER
(
ORDER
BY
ID
)
RNO
,
RANK
()
OVER
(
ORDER
BY
ID
)
RKO
,
DENSE_RANK
()
OVER
(
ORDER
BY
ID
)
DRO
FROM
TEST
;
>
ID
CATEGORY
VALUE
RN
RK
DR
RNO
RKO
DRO
>
-- -------- ----- -- -- -- --- --- ---
>
1
1
11
1
1
1
1
1
1
>
2
1
12
2
1
1
2
2
2
>
3
1
13
3
1
1
3
3
3
>
4
2
21
4
1
1
4
4
4
>
5
2
22
5
1
1
5
5
5
>
6
3
31
6
1
1
6
6
6
>
7
3
32
7
1
1
7
7
7
>
8
3
33
8
1
1
8
8
8
>
rows
(
ordered
):
8
SELECT
*
,
ROW_NUMBER
()
OVER
(
ORDER
BY
CATEGORY
)
RN
,
RANK
()
OVER
(
ORDER
BY
CATEGORY
)
RK
,
DENSE_RANK
()
OVER
(
ORDER
BY
CATEGORY
)
DR
FROM
TEST
;
>
ID
CATEGORY
VALUE
RN
RK
DR
>
-- -------- ----- -- -- --
>
1
1
11
1
1
1
>
2
1
12
2
1
1
>
3
1
13
3
1
1
>
4
2
21
4
4
2
>
5
2
22
5
4
2
>
6
3
31
6
6
3
>
7
3
32
7
6
3
>
8
3
33
8
6
3
>
rows
(
ordered
):
8
SELECT
*
,
ROW_NUMBER
()
OVER
(
PARTITION
BY
CATEGORY
ORDER
BY
ID
)
RN
,
RANK
()
OVER
(
PARTITION
BY
CATEGORY
ORDER
BY
ID
)
RK
,
DENSE_RANK
()
OVER
(
PARTITION
BY
CATEGORY
ORDER
BY
ID
)
DR
FROM
TEST
;
>
ID
CATEGORY
VALUE
RN
RK
DR
>
-- -------- ----- -- -- --
>
1
1
11
1
1
1
>
2
1
12
2
2
2
>
3
1
13
3
3
3
>
4
2
21
1
1
1
>
5
2
22
2
2
2
>
6
3
31
1
1
1
>
7
3
32
2
2
2
>
8
3
33
3
3
3
>
rows
(
ordered
):
8
SELECT
ROW_NUMBER
()
OVER
()
RN
,
RANK
()
OVER
()
RK
,
DENSE_RANK
()
OVER
()
DR
FROM
TEST
GROUP
BY
CATEGORY
;
>
RN
RK
DR
>
-- -- --
>
1
1
1
>
2
1
1
>
3
1
1
>
rows
:
3
DROP
TABLE
TEST
;
>
ok
h2/src/test/org/h2/test/scripts/testScript.sql
浏览文件 @
d08cab6c
...
...
@@ -281,21 +281,21 @@ create table test(id int primary key, name varchar(255), row_number int);
insert
into
test
values
(
1
,
'hello'
,
10
),
(
2
,
'world'
,
20
);
>
update
count
:
2
select
row
_number
()
over
(),
id
,
name
from
test
order
by
id
;
select
row
num
(),
id
,
name
from
test
order
by
id
;
>
ROWNUM
()
ID
NAME
>
-------- -- -----
>
1
1
hello
>
2
2
world
>
rows
(
ordered
):
2
select
row
_number
()
over
(),
id
,
name
from
test
order
by
name
;
select
row
num
(),
id
,
name
from
test
order
by
name
;
>
ROWNUM
()
ID
NAME
>
-------- -- -----
>
1
1
hello
>
2
2
world
>
rows
(
ordered
):
2
select
row
_number
()
over
(),
id
,
name
from
test
order
by
name
desc
;
select
row
num
(),
id
,
name
from
test
order
by
name
desc
;
>
ROWNUM
()
ID
NAME
>
-------- -- -----
>
2
2
world
...
...
h2/src/tools/org/h2/build/doc/GenerateDoc.java
浏览文件 @
d08cab6c
...
...
@@ -90,6 +90,8 @@ public class GenerateDoc {
help
+
"= 'Functions (Time and Date)' ORDER BY ID"
,
true
,
false
);
map
(
"functionsSystem"
,
help
+
"= 'Functions (System)' ORDER BY ID"
,
true
,
false
);
map
(
"functionsWindow"
,
help
+
"= 'Functions (Window)' ORDER BY ID"
,
true
,
false
);
map
(
"dataTypes"
,
help
+
"LIKE 'Data Types%' ORDER BY SECTION, ID"
,
true
,
true
);
map
(
"intervalDataTypes"
,
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
d08cab6c
...
...
@@ -796,3 +796,4 @@ interior envelopes multilinestring multipoint packed exterior normalization awkw
xym normalizes coord setz xyzm geometrycollection multipolygon mixup rings polygons rejection finite
pointzm pointz pointm dimensionality redefine forum measures
mpg casted pzm mls constrained subtypes complains
ranks rno dro rko precede
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论