mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-30 10:47:22 +00:00
Provide LISTAGG implementation (#174)
This patch provides an initial implemenation of LISTAGG[1]. Notably this implemenation deviates from ANSI SQL by allowing both WITHIN GROUP and the delimiter to be optional. We do so because Redshift SQL works this way and this approach is ultimately more flexible. Fixes #169. [1] https://modern-sql.com/feature/listagg
This commit is contained in:
parent
418b9631ce
commit
5f3c1bda01
5 changed files with 207 additions and 17 deletions
|
@ -244,7 +244,7 @@ fn parse_select_all() {
|
|||
fn parse_select_all_distinct() {
|
||||
let result = parse_sql_statements("SELECT ALL DISTINCT name FROM customer");
|
||||
assert_eq!(
|
||||
ParserError::ParserError("Cannot specify both ALL and DISTINCT in SELECT".to_string()),
|
||||
ParserError::ParserError("Cannot specify both ALL and DISTINCT".to_string()),
|
||||
result.unwrap_err(),
|
||||
);
|
||||
}
|
||||
|
@ -357,9 +357,7 @@ fn parse_select_count_distinct() {
|
|||
let sql = "SELECT COUNT(ALL DISTINCT + x) FROM customer";
|
||||
let res = parse_sql_statements(sql);
|
||||
assert_eq!(
|
||||
ParserError::ParserError(
|
||||
"Cannot specify both ALL and DISTINCT in function: COUNT".to_string()
|
||||
),
|
||||
ParserError::ParserError("Cannot specify both ALL and DISTINCT".to_string()),
|
||||
res.unwrap_err()
|
||||
);
|
||||
}
|
||||
|
@ -914,6 +912,58 @@ fn parse_extract() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_listagg() {
|
||||
let sql = "SELECT LISTAGG(DISTINCT dateid, ', ' ON OVERFLOW TRUNCATE '%' WITHOUT COUNT) \
|
||||
WITHIN GROUP (ORDER BY id, username)";
|
||||
let select = verified_only_select(sql);
|
||||
|
||||
verified_stmt("SELECT LISTAGG(sellerid) WITHIN GROUP (ORDER BY dateid)");
|
||||
verified_stmt("SELECT LISTAGG(dateid)");
|
||||
verified_stmt("SELECT LISTAGG(DISTINCT dateid)");
|
||||
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW ERROR)");
|
||||
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW TRUNCATE N'...' WITH COUNT)");
|
||||
verified_stmt("SELECT LISTAGG(dateid ON OVERFLOW TRUNCATE X'deadbeef' WITH COUNT)");
|
||||
|
||||
let expr = Box::new(Expr::Identifier(Ident::new("dateid")));
|
||||
let on_overflow = Some(ListAggOnOverflow::Truncate {
|
||||
filler: Some(Box::new(Expr::Value(Value::SingleQuotedString(
|
||||
"%".to_string(),
|
||||
)))),
|
||||
with_count: false,
|
||||
});
|
||||
let within_group = vec![
|
||||
OrderByExpr {
|
||||
expr: Expr::Identifier(Ident {
|
||||
value: "id".to_string(),
|
||||
quote_style: None,
|
||||
}),
|
||||
asc: None,
|
||||
nulls_first: None,
|
||||
},
|
||||
OrderByExpr {
|
||||
expr: Expr::Identifier(Ident {
|
||||
value: "username".to_string(),
|
||||
quote_style: None,
|
||||
}),
|
||||
asc: None,
|
||||
nulls_first: None,
|
||||
},
|
||||
];
|
||||
assert_eq!(
|
||||
&Expr::ListAgg(ListAgg {
|
||||
distinct: true,
|
||||
expr,
|
||||
separator: Some(Box::new(Expr::Value(Value::SingleQuotedString(
|
||||
", ".to_string()
|
||||
)))),
|
||||
on_overflow,
|
||||
within_group
|
||||
}),
|
||||
expr_from_projection(only(&select.projection))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_create_table() {
|
||||
let sql = "CREATE TABLE uk_cities (\
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue