mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
feat: Group By All (#964)
Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
This commit is contained in:
parent
2593dcfb79
commit
bb7b05e106
9 changed files with 85 additions and 36 deletions
|
@ -36,7 +36,7 @@ pub use self::ddl::{
|
||||||
};
|
};
|
||||||
pub use self::operator::{BinaryOperator, UnaryOperator};
|
pub use self::operator::{BinaryOperator, UnaryOperator};
|
||||||
pub use self::query::{
|
pub use self::query::{
|
||||||
Cte, Distinct, ExceptSelectItem, ExcludeSelectItem, Fetch, IdentWithAlias, Join,
|
Cte, Distinct, ExceptSelectItem, ExcludeSelectItem, Fetch, GroupByExpr, IdentWithAlias, Join,
|
||||||
JoinConstraint, JoinOperator, LateralView, LockClause, LockType, NamedWindowDefinition,
|
JoinConstraint, JoinOperator, LateralView, LockClause, LockType, NamedWindowDefinition,
|
||||||
NonBlock, Offset, OffsetRows, OrderByExpr, Query, RenameSelectItem, ReplaceSelectElement,
|
NonBlock, Offset, OffsetRows, OrderByExpr, Query, RenameSelectItem, ReplaceSelectElement,
|
||||||
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Table,
|
ReplaceSelectItem, Select, SelectInto, SelectItem, SetExpr, SetOperator, SetQuantifier, Table,
|
||||||
|
|
|
@ -214,7 +214,7 @@ pub struct Select {
|
||||||
/// WHERE
|
/// WHERE
|
||||||
pub selection: Option<Expr>,
|
pub selection: Option<Expr>,
|
||||||
/// GROUP BY
|
/// GROUP BY
|
||||||
pub group_by: Vec<Expr>,
|
pub group_by: GroupByExpr,
|
||||||
/// CLUSTER BY (Hive)
|
/// CLUSTER BY (Hive)
|
||||||
pub cluster_by: Vec<Expr>,
|
pub cluster_by: Vec<Expr>,
|
||||||
/// DISTRIBUTE BY (Hive)
|
/// DISTRIBUTE BY (Hive)
|
||||||
|
@ -255,8 +255,13 @@ impl fmt::Display for Select {
|
||||||
if let Some(ref selection) = self.selection {
|
if let Some(ref selection) = self.selection {
|
||||||
write!(f, " WHERE {selection}")?;
|
write!(f, " WHERE {selection}")?;
|
||||||
}
|
}
|
||||||
if !self.group_by.is_empty() {
|
match &self.group_by {
|
||||||
write!(f, " GROUP BY {}", display_comma_separated(&self.group_by))?;
|
GroupByExpr::All => write!(f, " GROUP BY ALL")?,
|
||||||
|
GroupByExpr::Expressions(exprs) => {
|
||||||
|
if !exprs.is_empty() {
|
||||||
|
write!(f, " GROUP BY {}", display_comma_separated(exprs))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !self.cluster_by.is_empty() {
|
if !self.cluster_by.is_empty() {
|
||||||
write!(
|
write!(
|
||||||
|
@ -1218,3 +1223,29 @@ impl fmt::Display for SelectInto {
|
||||||
write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
|
write!(f, "INTO{}{}{} {}", temporary, unlogged, table, self.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
|
||||||
|
pub enum GroupByExpr {
|
||||||
|
/// ALL syntax of [Snowflake], and [DuckDB]
|
||||||
|
///
|
||||||
|
/// [Snowflake]: <https://docs.snowflake.com/en/sql-reference/constructs/group-by#label-group-by-all-columns>
|
||||||
|
/// [DuckDB]: <https://duckdb.org/docs/sql/query_syntax/groupby.html>
|
||||||
|
All,
|
||||||
|
|
||||||
|
/// Expressions
|
||||||
|
Expressions(Vec<Expr>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for GroupByExpr {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
GroupByExpr::All => write!(f, "GROUP BY ALL"),
|
||||||
|
GroupByExpr::Expressions(col_names) => {
|
||||||
|
let col_names = display_comma_separated(col_names);
|
||||||
|
write!(f, "GROUP BY ({col_names})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5662,9 +5662,13 @@ impl<'a> Parser<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let group_by = if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
|
let group_by = if self.parse_keywords(&[Keyword::GROUP, Keyword::BY]) {
|
||||||
self.parse_comma_separated(Parser::parse_group_by_expr)?
|
if self.parse_keyword(Keyword::ALL) {
|
||||||
|
GroupByExpr::All
|
||||||
|
} else {
|
||||||
|
GroupByExpr::Expressions(self.parse_comma_separated(Parser::parse_group_by_expr)?)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
GroupByExpr::Expressions(vec![])
|
||||||
};
|
};
|
||||||
|
|
||||||
let cluster_by = if self.parse_keywords(&[Keyword::CLUSTER, Keyword::BY]) {
|
let cluster_by = if self.parse_keywords(&[Keyword::CLUSTER, Keyword::BY]) {
|
||||||
|
|
|
@ -97,7 +97,7 @@ fn parse_map_access_expr() {
|
||||||
right: Box::new(Expr::Value(Value::SingleQuotedString("foo".to_string())))
|
right: Box::new(Expr::Value(Value::SingleQuotedString("foo".to_string())))
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
|
|
@ -247,7 +247,9 @@ fn parse_update_set_from() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![Expr::Identifier(Ident::new("id"))],
|
group_by: GroupByExpr::Expressions(vec![Expr::Identifier(Ident::new(
|
||||||
|
"id"
|
||||||
|
))]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -1808,10 +1810,10 @@ fn parse_select_group_by() {
|
||||||
let sql = "SELECT id, fname, lname FROM customer GROUP BY lname, fname";
|
let sql = "SELECT id, fname, lname FROM customer GROUP BY lname, fname";
|
||||||
let select = verified_only_select(sql);
|
let select = verified_only_select(sql);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![
|
GroupByExpr::Expressions(vec![
|
||||||
Expr::Identifier(Ident::new("lname")),
|
Expr::Identifier(Ident::new("lname")),
|
||||||
Expr::Identifier(Ident::new("fname")),
|
Expr::Identifier(Ident::new("fname")),
|
||||||
],
|
]),
|
||||||
select.group_by
|
select.group_by
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1822,6 +1824,18 @@ fn parse_select_group_by() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_select_group_by_all() {
|
||||||
|
let sql = "SELECT id, fname, lname, SUM(order) FROM customer GROUP BY ALL";
|
||||||
|
let select = verified_only_select(sql);
|
||||||
|
assert_eq!(GroupByExpr::All, select.group_by);
|
||||||
|
|
||||||
|
one_statement_parses_to(
|
||||||
|
"SELECT id, fname, lname, SUM(order) FROM customer GROUP BY ALL",
|
||||||
|
"SELECT id, fname, lname, SUM(order) FROM customer GROUP BY ALL",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_select_having() {
|
fn parse_select_having() {
|
||||||
let sql = "SELECT foo FROM bar GROUP BY foo HAVING COUNT(*) > 1";
|
let sql = "SELECT foo FROM bar GROUP BY foo HAVING COUNT(*) > 1";
|
||||||
|
@ -3543,7 +3557,7 @@ fn test_parse_named_window() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -3930,7 +3944,7 @@ fn parse_interval_and_or_xor() {
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -6333,7 +6347,7 @@ fn parse_merge() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
|
|
@ -161,7 +161,7 @@ fn test_select_union_by_name() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -194,7 +194,7 @@ fn test_select_union_by_name() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -236,7 +236,7 @@ fn test_select_union_by_name() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -269,7 +269,7 @@ fn test_select_union_by_name() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
|
|
@ -103,7 +103,7 @@ fn parse_create_procedure() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -519,7 +519,7 @@ fn parse_substring_in_select() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
|
|
@ -496,7 +496,7 @@ fn parse_escaped_quote_identifiers_with_escape() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -538,7 +538,7 @@ fn parse_escaped_quote_identifiers_with_no_escape() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -577,7 +577,7 @@ fn parse_escaped_backticks_with_escape() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -616,7 +616,7 @@ fn parse_escaped_backticks_with_no_escape() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -1100,7 +1100,7 @@ fn parse_select_with_numeric_prefix_column_name() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -1149,7 +1149,7 @@ fn parse_select_with_concatenation_of_exp_number_and_numeric_prefix_column() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -1325,7 +1325,7 @@ fn parse_substring_in_select() {
|
||||||
}],
|
}],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -1604,7 +1604,7 @@ fn parse_hex_string_introducer() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
|
|
@ -990,7 +990,7 @@ fn parse_copy_to() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
having: None,
|
having: None,
|
||||||
named_window: vec![],
|
named_window: vec![],
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
|
@ -2019,7 +2019,7 @@ fn parse_array_subquery_expr() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -2035,7 +2035,7 @@ fn parse_array_subquery_expr() {
|
||||||
from: vec![],
|
from: vec![],
|
||||||
lateral_views: vec![],
|
lateral_views: vec![],
|
||||||
selection: None,
|
selection: None,
|
||||||
group_by: vec![],
|
group_by: GroupByExpr::Expressions(vec![]),
|
||||||
cluster_by: vec![],
|
cluster_by: vec![],
|
||||||
distribute_by: vec![],
|
distribute_by: vec![],
|
||||||
sort_by: vec![],
|
sort_by: vec![],
|
||||||
|
@ -3321,14 +3321,14 @@ fn parse_select_group_by_grouping_sets() {
|
||||||
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, GROUPING SETS ((brand), (size), ())"
|
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, GROUPING SETS ((brand), (size), ())"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![
|
GroupByExpr::Expressions(vec![
|
||||||
Expr::Identifier(Ident::new("size")),
|
Expr::Identifier(Ident::new("size")),
|
||||||
Expr::GroupingSets(vec![
|
Expr::GroupingSets(vec![
|
||||||
vec![Expr::Identifier(Ident::new("brand"))],
|
vec![Expr::Identifier(Ident::new("brand"))],
|
||||||
vec![Expr::Identifier(Ident::new("size"))],
|
vec![Expr::Identifier(Ident::new("size"))],
|
||||||
vec![],
|
vec![],
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
select.group_by
|
select.group_by
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3339,13 +3339,13 @@ fn parse_select_group_by_rollup() {
|
||||||
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, ROLLUP (brand, size)",
|
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, ROLLUP (brand, size)",
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![
|
GroupByExpr::Expressions(vec![
|
||||||
Expr::Identifier(Ident::new("size")),
|
Expr::Identifier(Ident::new("size")),
|
||||||
Expr::Rollup(vec![
|
Expr::Rollup(vec![
|
||||||
vec![Expr::Identifier(Ident::new("brand"))],
|
vec![Expr::Identifier(Ident::new("brand"))],
|
||||||
vec![Expr::Identifier(Ident::new("size"))],
|
vec![Expr::Identifier(Ident::new("size"))],
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
select.group_by
|
select.group_by
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -3356,13 +3356,13 @@ fn parse_select_group_by_cube() {
|
||||||
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, CUBE (brand, size)",
|
"SELECT brand, size, sum(sales) FROM items_sold GROUP BY size, CUBE (brand, size)",
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
vec![
|
GroupByExpr::Expressions(vec![
|
||||||
Expr::Identifier(Ident::new("size")),
|
Expr::Identifier(Ident::new("size")),
|
||||||
Expr::Cube(vec![
|
Expr::Cube(vec![
|
||||||
vec![Expr::Identifier(Ident::new("brand"))],
|
vec![Expr::Identifier(Ident::new("brand"))],
|
||||||
vec![Expr::Identifier(Ident::new("size"))],
|
vec![Expr::Identifier(Ident::new("size"))],
|
||||||
]),
|
]),
|
||||||
],
|
]),
|
||||||
select.group_by
|
select.group_by
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue