mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
Merge pull request #25589 from TszKitLo40/support-distinct-on
This commit is contained in:
commit
bf0695ff84
@ -1,4 +1,5 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <Parsers/ASTLiteral.h>
|
||||||
#include <Parsers/ASTSelectQuery.h>
|
#include <Parsers/ASTSelectQuery.h>
|
||||||
#include <Parsers/IParserBase.h>
|
#include <Parsers/IParserBase.h>
|
||||||
#include <Parsers/CommonParsers.h>
|
#include <Parsers/CommonParsers.h>
|
||||||
@ -16,11 +17,12 @@ namespace DB
|
|||||||
|
|
||||||
namespace ErrorCodes
|
namespace ErrorCodes
|
||||||
{
|
{
|
||||||
extern const int TOP_AND_LIMIT_TOGETHER;
|
extern const int FIRST_AND_NEXT_TOGETHER;
|
||||||
extern const int WITH_TIES_WITHOUT_ORDER_BY;
|
|
||||||
extern const int LIMIT_BY_WITH_TIES_IS_NOT_SUPPORTED;
|
extern const int LIMIT_BY_WITH_TIES_IS_NOT_SUPPORTED;
|
||||||
extern const int ROW_AND_ROWS_TOGETHER;
|
extern const int ROW_AND_ROWS_TOGETHER;
|
||||||
extern const int FIRST_AND_NEXT_TOGETHER;
|
extern const int SYNTAX_ERROR;
|
||||||
|
extern const int TOP_AND_LIMIT_TOGETHER;
|
||||||
|
extern const int WITH_TIES_WITHOUT_ORDER_BY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
ParserKeyword s_select("SELECT");
|
ParserKeyword s_select("SELECT");
|
||||||
ParserKeyword s_all("ALL");
|
ParserKeyword s_all("ALL");
|
||||||
ParserKeyword s_distinct("DISTINCT");
|
ParserKeyword s_distinct("DISTINCT");
|
||||||
|
ParserKeyword s_distinct_on("DISTINCT ON");
|
||||||
ParserKeyword s_from("FROM");
|
ParserKeyword s_from("FROM");
|
||||||
ParserKeyword s_prewhere("PREWHERE");
|
ParserKeyword s_prewhere("PREWHERE");
|
||||||
ParserKeyword s_where("WHERE");
|
ParserKeyword s_where("WHERE");
|
||||||
@ -77,12 +80,13 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
ASTPtr limit_by_length;
|
ASTPtr limit_by_length;
|
||||||
ASTPtr limit_by_offset;
|
ASTPtr limit_by_offset;
|
||||||
ASTPtr limit_by_expression_list;
|
ASTPtr limit_by_expression_list;
|
||||||
|
ASTPtr distinct_on_expression_list;
|
||||||
ASTPtr limit_offset;
|
ASTPtr limit_offset;
|
||||||
ASTPtr limit_length;
|
ASTPtr limit_length;
|
||||||
ASTPtr top_length;
|
ASTPtr top_length;
|
||||||
ASTPtr settings;
|
ASTPtr settings;
|
||||||
|
|
||||||
/// WITH expr list
|
/// WITH expr_list
|
||||||
{
|
{
|
||||||
if (s_with.ignore(pos, expected))
|
if (s_with.ignore(pos, expected))
|
||||||
{
|
{
|
||||||
@ -94,7 +98,7 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SELECT [ALL/DISTINCT] [TOP N [WITH TIES]] expr list
|
/// SELECT [ALL/DISTINCT [ON (expr_list)]] [TOP N [WITH TIES]] expr_list
|
||||||
{
|
{
|
||||||
bool has_all = false;
|
bool has_all = false;
|
||||||
if (!s_select.ignore(pos, expected))
|
if (!s_select.ignore(pos, expected))
|
||||||
@ -103,13 +107,27 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
if (s_all.ignore(pos, expected))
|
if (s_all.ignore(pos, expected))
|
||||||
has_all = true;
|
has_all = true;
|
||||||
|
|
||||||
if (s_distinct.ignore(pos, expected))
|
if (s_distinct_on.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
if (open_bracket.ignore(pos, expected))
|
||||||
|
{
|
||||||
|
if (!exp_list.parse(pos, distinct_on_expression_list, expected))
|
||||||
|
return false;
|
||||||
|
if (!close_bracket.ignore(pos, expected))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (s_distinct.ignore(pos, expected))
|
||||||
|
{
|
||||||
select_query->distinct = true;
|
select_query->distinct = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!has_all && s_all.ignore(pos, expected))
|
if (!has_all && s_all.ignore(pos, expected))
|
||||||
has_all = true;
|
has_all = true;
|
||||||
|
|
||||||
if (has_all && select_query->distinct)
|
if (has_all && (select_query->distinct || distinct_on_expression_list))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (s_top.ignore(pos, expected))
|
if (s_top.ignore(pos, expected))
|
||||||
@ -256,13 +274,19 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
select_query->limit_with_ties = true;
|
select_query->limit_with_ties = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (limit_with_ties_occured && distinct_on_expression_list)
|
||||||
|
throw Exception("Can not use WITH TIES alongside LIMIT BY/DISTINCT ON", ErrorCodes::LIMIT_BY_WITH_TIES_IS_NOT_SUPPORTED);
|
||||||
|
|
||||||
if (s_by.ignore(pos, expected))
|
if (s_by.ignore(pos, expected))
|
||||||
{
|
{
|
||||||
/// WITH TIES was used alongside LIMIT BY
|
/// WITH TIES was used alongside LIMIT BY
|
||||||
/// But there are other kind of queries like LIMIT n BY smth LIMIT m WITH TIES which are allowed.
|
/// But there are other kind of queries like LIMIT n BY smth LIMIT m WITH TIES which are allowed.
|
||||||
/// So we have to ignore WITH TIES exactly in LIMIT BY state.
|
/// So we have to ignore WITH TIES exactly in LIMIT BY state.
|
||||||
if (limit_with_ties_occured)
|
if (limit_with_ties_occured)
|
||||||
throw Exception("Can not use WITH TIES alongside LIMIT BY", ErrorCodes::LIMIT_BY_WITH_TIES_IS_NOT_SUPPORTED);
|
throw Exception("Can not use WITH TIES alongside LIMIT BY/DISTINCT ON", ErrorCodes::LIMIT_BY_WITH_TIES_IS_NOT_SUPPORTED);
|
||||||
|
|
||||||
|
if (distinct_on_expression_list)
|
||||||
|
throw Exception("Can not use DISTINCT ON alongside LIMIT BY", ErrorCodes::SYNTAX_ERROR);
|
||||||
|
|
||||||
limit_by_length = limit_length;
|
limit_by_length = limit_length;
|
||||||
limit_by_offset = limit_offset;
|
limit_by_offset = limit_offset;
|
||||||
@ -335,6 +359,17 @@ bool ParserSelectQuery::parseImpl(Pos & pos, ASTPtr & node, Expected & expected)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distinct_on_expression_list)
|
||||||
|
{
|
||||||
|
/// DISTINCT ON and LIMIT BY are mutually exclusive, checked before
|
||||||
|
assert (limit_by_expression_list == nullptr);
|
||||||
|
|
||||||
|
/// Transform `DISTINCT ON expr` to `LIMIT 1 BY expr`
|
||||||
|
limit_by_expression_list = distinct_on_expression_list;
|
||||||
|
limit_by_length = std::make_shared<ASTLiteral>(Field{UInt8(1)});
|
||||||
|
distinct_on_expression_list = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
/// Because TOP n in totally equals LIMIT n
|
/// Because TOP n in totally equals LIMIT n
|
||||||
if (top_length)
|
if (top_length)
|
||||||
limit_length = top_length;
|
limit_length = top_length;
|
||||||
|
8
tests/queries/0_stateless/01917_distinct_on.reference
Normal file
8
tests/queries/0_stateless/01917_distinct_on.reference
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
1 1 1
|
||||||
|
2 2 2
|
||||||
|
1 2 2
|
||||||
|
1 1 1
|
||||||
|
2 2 2
|
||||||
|
1 2 2
|
||||||
|
1 1 1
|
||||||
|
2 2 2
|
23
tests/queries/0_stateless/01917_distinct_on.sql
Normal file
23
tests/queries/0_stateless/01917_distinct_on.sql
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (`a` UInt32, `b` UInt32, `c` UInt32 ) ENGINE = Memory;
|
||||||
|
INSERT INTO t1 VALUES (1, 1, 1), (1, 1, 2), (2, 2, 2), (1, 2, 2);
|
||||||
|
|
||||||
|
SELECT DISTINCT ON (a, b) a, b, c FROM t1;
|
||||||
|
SELECT DISTINCT ON (a, b) * FROM t1;
|
||||||
|
SELECT DISTINCT ON (a) * FROM t1;
|
||||||
|
|
||||||
|
-- fuzzer will fail, enable when fixed
|
||||||
|
-- SELECT DISTINCT ON (a, b) a, b, c FROM t1 LIMIT 1 BY a, b; -- { clientError 62 }
|
||||||
|
|
||||||
|
-- SELECT DISTINCT ON a, b a, b FROM t1; -- { clientError 62 }
|
||||||
|
-- SELECT DISTINCT ON a a, b FROM t1; -- { clientError 62 }
|
||||||
|
|
||||||
|
-- "Code: 47. DB::Exception: Missing columns: 'DISTINCT'" - error can be better
|
||||||
|
-- SELECT DISTINCT ON (a, b) DISTINCT a, b FROM t1; -- { serverError 47 }
|
||||||
|
-- SELECT DISTINCT DISTINCT ON (a, b) a, b FROM t1; -- { clientError 62 }
|
||||||
|
|
||||||
|
-- SELECT ALL DISTINCT ON (a, b) a, b FROM t1; -- { clientError 62 }
|
||||||
|
-- SELECT DISTINCT ON (a, b) ALL a, b FROM t1; -- { clientError 62 }
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS t1;
|
Loading…
Reference in New Issue
Block a user