Skip to content

Commit

Permalink
SQL: Implement TOP as an alternative to LIMIT (#57428)
Browse files Browse the repository at this point in the history
Add basic support for `TOP X` as a synonym to LIMIT X which is used
by [MS-SQL server](https://docs.microsoft.com/en-us/sql/t-sql/queries/top-transact-sql?view=sql-server-ver15),
e.g.:

```
SELECT TOP 5 a, b, c FROM test
```

TOP in SQL server also supports the `PERCENTAGE` and `WITH TIES`
keywords which this implementation doesn't.

Don't allow usage of both TOP and LIMIT in the same query.

Refers to #41195
  • Loading branch information
matriv authored Jun 2, 2020
1 parent d7b31a8 commit 2f5ab81
Show file tree
Hide file tree
Showing 15 changed files with 1,797 additions and 1,549 deletions.
1 change: 1 addition & 0 deletions docs/reference/sql/appendix/syntax-reserved.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ s|SQL-92
|`TABLES` | |
|`THEN` |reserved |reserved
|`TO` |reserved |reserved
|`TOP` |reserved |reserved
|`TRUE` |reserved |reserved
|`TYPE` | |
|`USING` |reserved |reserved
Expand Down
42 changes: 34 additions & 8 deletions docs/reference/sql/language/syntax/commands/select.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
.Synopsis:
[source, sql]
----
SELECT select_expr [, ...]
SELECT [TOP [ count ] ] select_expr [, ...]
[ FROM table_name ]
[ WHERE condition ]
[ GROUP BY grouping_element [, ...] ]
Expand All @@ -25,7 +25,7 @@ The general execution of `SELECT` is as follows:
. If the `GROUP BY` clause is specified, or if there are aggregate function calls, the output is combined into groups of rows that match on one or more values, and the results of aggregate functions are computed. If the `HAVING` clause is present, it eliminates groups that do not satisfy the given condition. (See <<sql-syntax-group-by, GROUP BY Clause>> and <<sql-syntax-having, HAVING Clause>> below.)
. The actual output rows are computed using the `SELECT` output expressions for each selected row or row group.
. If the `ORDER BY` clause is specified, the returned rows are sorted in the specified order. If `ORDER BY` is not given, the rows are returned in whatever order the system finds fastest to produce. (See <<sql-syntax-order-by,ORDER BY Clause>> below.)
. If the `LIMIT` is specified, the `SELECT` statement only returns a subset of the result rows. (See <<sql-syntax-limit, LIMIT Clause>> below.)
. If the `LIMIT` or `TOP` is specified (cannot use both in the same query), the `SELECT` statement only returns a subset of the result rows. (See <<sql-syntax-limit, LIMIT Clause>> and <<sql-syntax-top, TOP clause>> below.)


[[sql-syntax-select-list]]
Expand Down Expand Up @@ -69,6 +69,30 @@ include-tagged::{sql-specs}/docs/docs.csv-spec[wildcardWithOrder]

which essentially returns all(top-level fields, sub-fields, such as multi-fields are ignored] columns found.

[[sql-syntax-top]]
==== TOP

The `TOP` clause can be used before the <<sql-syntax-select-list, `SELECT` list>> or the <<sql-syntax-select-wildcard, `wildcard`> to
restrict (limit) the number of rows returned using the format:

[source, sql]
----
SELECT TOP <count> <select list> ...
----

where

count:: is a positive integer or zero indicating the maximum *possible* number of results being returned (as there might be fewer matches
than the limit). If `0` is specified, no results are returned.

[source, sql]
----
include-tagged::{sql-specs}/docs/docs.csv-spec[topBasic]
----

[NOTE]
<<sql-syntax-top, `TOP`>> and <<sql-syntax-limit, `LIMIT`>> cannot be used together in the same query and an error is returned otherwise.

[[sql-syntax-from]]
==== FROM Clause

Expand Down Expand Up @@ -336,7 +360,7 @@ include-tagged::{sql-specs}/docs/docs.csv-spec[orderByAgg]
----
IMPORTANT: Ordering by aggregation is possible for up to *10000* entries for memory consumption reasons.
In cases where the results pass this threshold, use <<sql-syntax-limit,`LIMIT`>> to reduce the number
In cases where the results pass this threshold, use <<sql-syntax-limit,`LIMIT`>> or <<sql-syntax-top, `TOP`>> to reduce the number
of results.
[[sql-syntax-order-by-score]]
Expand Down Expand Up @@ -371,26 +395,28 @@ all are equally relevant.
[[sql-syntax-limit]]
==== LIMIT
The `LIMIT` clause restricts (limits) the number of rows returns using the format:
The `LIMIT` clause restricts (limits) the number of rows returned using the format:
[source, sql]
----
LIMIT ( count | ALL )
LIMIT ( <count> | ALL )
----
where
count:: is a positive integer or zero indicating the maximum *possible* number of results being returned (as there might be less matches than the limit). If `0` is specified, no results are returned.
count:: is a positive integer or zero indicating the maximum *possible* number of results being returned (as there might be fewer matches
than the limit). If `0` is specified, no results are returned.
ALL:: indicates there is no limit and thus all results are being returned.
To return
[source, sql]
----
include-tagged::{sql-specs}/docs/docs.csv-spec[limitBasic]
----
[NOTE]
<<sql-syntax-top, `TOP`>> and <<sql-syntax-limit, `LIMIT`>> cannot be used together in the same query and an error is returned otherwise.
[[sql-syntax-pivot]]
==== PIVOT
Expand Down
12 changes: 12 additions & 0 deletions x-pack/plugin/sql/qa/server/src/main/resources/docs/docs.csv-spec
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,18 @@ Georgi |Facello |10001
// end::limitBasic
;

topBasic
// tag::topBasic
SELECT TOP 2 first_name, last_name, emp_no FROM emp;

first_name | last_name | emp_no
---------------+---------------+---------------
Georgi |Facello |10001
Bezalel |Simmel |10002

// end::topBasic
;

///////////////////////////////
//
// Aggregations
Expand Down
38 changes: 38 additions & 0 deletions x-pack/plugin/sql/qa/server/src/main/resources/select.csv-spec
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,41 @@ SELECT emp_no, CAST(languages NOT IN (2, 3) AS STRING), CAST(NOT languages IN (2
10019 |true |null
10020 |null |null
;

topWithWildCard
schema::birth_date:ts|emp_no:i|first_name:s|gender:s|hire_date:ts|languages:byte|last_name:s|salary:i
SELECT TOP 5 * FROM test_emp ORDER BY emp_no;

birth_date | emp_no | first_name | gender | hire_date | languages | last_name | salary
------------------------+---------------+---------------+---------------+------------------------+---------------+---------------+---------------
1953-09-02T00:00:00.000Z|10001 |Georgi |M |1986-06-26T00:00:00.000Z|2 |Facello |57305
1964-06-02T00:00:00.000Z|10002 |Bezalel |F |1985-11-21T00:00:00.000Z|5 |Simmel |56371
1959-12-03T00:00:00.000Z|10003 |Parto |M |1986-08-28T00:00:00.000Z|4 |Bamford |61805
1954-05-01T00:00:00.000Z|10004 |Chirstian |M |1986-12-01T00:00:00.000Z|5 |Koblick |36174
1955-01-21T00:00:00.000Z|10005 |Kyoichi |M |1989-09-12T00:00:00.000Z|1 |Maliniak |63528
;

topWithColumnNames
SELECT TOP 7 emp_no, first_name, last_name FROM test_emp ORDER BY emp_no DESC;

emp_no | first_name | last_name
---------------+---------------+---------------
10100 |Hironobu |Haraldson
10099 |Valter |Sullins
10098 |Sreekrishna |Servieres
10097 |Remzi |Waschkowski
10096 |Jayson |Mandell
10095 |Hilari |Morton
10094 |Arumugam |Ossenbruggen
;

topWithAggregations
schema::cnt:l|emp_no % languages:i
SELECT TOP 3 count(*) AS cnt, emp_no % languages FROM test_emp GROUP BY 2 ORDER BY 1 DESC;

cnt | emp_no % languages
----------+-------------------
37 |0
24 |1
16 |2
;
9 changes: 7 additions & 2 deletions x-pack/plugin/sql/src/main/antlr/SqlBase.g4
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ orderBy
;

querySpecification
: SELECT setQuantifier? selectItems
: SELECT topClause? setQuantifier? selectItems
fromClause?
(WHERE where=booleanExpression)?
(GROUP BY groupBy)?
Expand Down Expand Up @@ -118,6 +118,10 @@ namedQuery
: name=identifier AS '(' queryNoWith ')'
;

topClause
: TOP top=INTEGER_VALUE
;

setQuantifier
: DISTINCT
| ALL
Expand Down Expand Up @@ -376,7 +380,7 @@ nonReserved
| QUERY
| RLIKE
| SCHEMAS | SECOND | SHOW | SYS
| TABLES | TEXT | TYPE | TYPES
| TABLES | TEXT | TOP | TYPE | TYPES
| VERIFY
| YEAR
;
Expand Down Expand Up @@ -469,6 +473,7 @@ TEXT: 'TEXT';
THEN: 'THEN';
TRUE: 'TRUE';
TO: 'TO';
TOP: 'TOP';
TYPE: 'TYPE';
TYPES: 'TYPES';
USING: 'USING';
Expand Down
146 changes: 74 additions & 72 deletions x-pack/plugin/sql/src/main/antlr/SqlBase.tokens
Original file line number Diff line number Diff line change
Expand Up @@ -90,53 +90,54 @@ TEXT=89
THEN=90
TRUE=91
TO=92
TYPE=93
TYPES=94
USING=95
VERIFY=96
WHEN=97
WHERE=98
WITH=99
YEAR=100
YEARS=101
ESCAPE_ESC=102
FUNCTION_ESC=103
LIMIT_ESC=104
DATE_ESC=105
TIME_ESC=106
TIMESTAMP_ESC=107
GUID_ESC=108
ESC_START=109
ESC_END=110
EQ=111
NULLEQ=112
NEQ=113
LT=114
LTE=115
GT=116
GTE=117
PLUS=118
MINUS=119
ASTERISK=120
SLASH=121
PERCENT=122
CAST_OP=123
CONCAT=124
DOT=125
PARAM=126
STRING=127
INTEGER_VALUE=128
DECIMAL_VALUE=129
IDENTIFIER=130
DIGIT_IDENTIFIER=131
TABLE_IDENTIFIER=132
QUOTED_IDENTIFIER=133
BACKQUOTED_IDENTIFIER=134
SIMPLE_COMMENT=135
BRACKETED_COMMENT=136
WS=137
UNRECOGNIZED=138
DELIMITER=139
TOP=93
TYPE=94
TYPES=95
USING=96
VERIFY=97
WHEN=98
WHERE=99
WITH=100
YEAR=101
YEARS=102
ESCAPE_ESC=103
FUNCTION_ESC=104
LIMIT_ESC=105
DATE_ESC=106
TIME_ESC=107
TIMESTAMP_ESC=108
GUID_ESC=109
ESC_START=110
ESC_END=111
EQ=112
NULLEQ=113
NEQ=114
LT=115
LTE=116
GT=117
GTE=118
PLUS=119
MINUS=120
ASTERISK=121
SLASH=122
PERCENT=123
CAST_OP=124
CONCAT=125
DOT=126
PARAM=127
STRING=128
INTEGER_VALUE=129
DECIMAL_VALUE=130
IDENTIFIER=131
DIGIT_IDENTIFIER=132
TABLE_IDENTIFIER=133
QUOTED_IDENTIFIER=134
BACKQUOTED_IDENTIFIER=135
SIMPLE_COMMENT=136
BRACKETED_COMMENT=137
WS=138
UNRECOGNIZED=139
DELIMITER=140
'('=1
')'=2
','=3
Expand Down Expand Up @@ -229,28 +230,29 @@ DELIMITER=139
'THEN'=90
'TRUE'=91
'TO'=92
'TYPE'=93
'TYPES'=94
'USING'=95
'VERIFY'=96
'WHEN'=97
'WHERE'=98
'WITH'=99
'YEAR'=100
'YEARS'=101
'}'=110
'='=111
'<=>'=112
'<'=114
'<='=115
'>'=116
'>='=117
'+'=118
'-'=119
'*'=120
'/'=121
'%'=122
'::'=123
'||'=124
'.'=125
'?'=126
'TOP'=93
'TYPE'=94
'TYPES'=95
'USING'=96
'VERIFY'=97
'WHEN'=98
'WHERE'=99
'WITH'=100
'YEAR'=101
'YEARS'=102
'}'=111
'='=112
'<=>'=113
'<'=115
'<='=116
'>'=117
'>='=118
'+'=119
'-'=120
'*'=121
'/'=122
'%'=123
'::'=124
'||'=125
'.'=126
'?'=127
Loading

0 comments on commit 2f5ab81

Please sign in to comment.