Skip to content

Commit 4670853

Browse files
committed
feat: WITHIN GROUP expression support
1 parent 6a54d27 commit 4670853

File tree

3 files changed

+79
-2
lines changed

3 files changed

+79
-2
lines changed

src/ast/mod.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,8 @@ pub enum Expr {
348348
ListAgg(ListAgg),
349349
/// The `ARRAY_AGG` function `SELECT ARRAY_AGG(... ORDER BY ...)`
350350
ArrayAgg(ArrayAgg),
351+
/// The `WITHIN GROUP` expr `... WITHIN GROUP (ORDER BY ...)`
352+
WithinGroup(WithinGroup),
351353
/// The `GROUPING SETS` expr.
352354
GroupingSets(Vec<Vec<Expr>>),
353355
/// The `CUBE` expr.
@@ -549,6 +551,7 @@ impl fmt::Display for Expr {
549551
Expr::ArraySubquery(s) => write!(f, "ARRAY({})", s),
550552
Expr::ListAgg(listagg) => write!(f, "{}", listagg),
551553
Expr::ArrayAgg(arrayagg) => write!(f, "{}", arrayagg),
554+
Expr::WithinGroup(withingroup) => write!(f, "{}", withingroup),
552555
Expr::GroupingSets(sets) => {
553556
write!(f, "GROUPING SETS (")?;
554557
let mut sep = "";
@@ -2523,6 +2526,26 @@ impl fmt::Display for ArrayAgg {
25232526
}
25242527
}
25252528

2529+
/// A `WITHIN GROUP` invocation `<expr> WITHIN GROUP (ORDER BY <sort_expr> )`
2530+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2531+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2532+
pub struct WithinGroup {
2533+
pub expr: Box<Expr>,
2534+
pub order_by: Vec<OrderByExpr>,
2535+
}
2536+
2537+
impl fmt::Display for WithinGroup {
2538+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2539+
write!(
2540+
f,
2541+
"{} WITHIN GROUP (ORDER BY {})",
2542+
self.expr,
2543+
display_comma_separated(&self.order_by),
2544+
)?;
2545+
Ok(())
2546+
}
2547+
}
2548+
25262549
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25272550
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25282551
pub enum ObjectType {

src/parser.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,14 +627,33 @@ impl<'a> Parser<'a> {
627627
None
628628
};
629629

630-
Ok(Expr::Function(Function {
630+
let within_group = if self.parse_keywords(&[Keyword::WITHIN, Keyword::GROUP]) {
631+
self.expect_token(&Token::LParen)?;
632+
self.expect_keywords(&[Keyword::ORDER, Keyword::BY])?;
633+
let order_by_expr = self.parse_comma_separated(Parser::parse_order_by_expr)?;
634+
self.expect_token(&Token::RParen)?;
635+
Some(order_by_expr)
636+
} else {
637+
None
638+
};
639+
640+
let function = Expr::Function(Function {
631641
name,
632642
args,
633643
over,
634644
distinct,
635645
special: false,
636646
approximate: false,
637-
}))
647+
});
648+
649+
Ok(if let Some(within_group) = within_group {
650+
Expr::WithinGroup(WithinGroup {
651+
expr: Box::new(function),
652+
order_by: within_group,
653+
})
654+
} else {
655+
function
656+
})
638657
}
639658

640659
pub fn parse_time_functions(&mut self, name: ObjectName) -> Result<Expr, ParserError> {

tests/sqlparser_common.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,41 @@ fn parse_array_agg_func() {
17361736
}
17371737
}
17381738

1739+
#[test]
1740+
fn parse_within_group() {
1741+
let sql = "SELECT PERCENTILE_CONT(0.0) WITHIN GROUP (ORDER BY name ASC NULLS FIRST)";
1742+
let select = verified_only_select(sql);
1743+
1744+
#[cfg(feature = "bigdecimal")]
1745+
let value = bigdecimal::BigDecimal::from(0);
1746+
#[cfg(not(feature = "bigdecimal"))]
1747+
let value = "0.0".to_string();
1748+
let expr = Expr::Value(Value::Number(value, false));
1749+
let function = Expr::Function(Function {
1750+
name: ObjectName(vec![Ident::new("PERCENTILE_CONT")]),
1751+
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(expr))],
1752+
over: None,
1753+
distinct: false,
1754+
special: false,
1755+
approximate: false,
1756+
});
1757+
let within_group = vec![OrderByExpr {
1758+
expr: Expr::Identifier(Ident {
1759+
value: "name".to_string(),
1760+
quote_style: None,
1761+
}),
1762+
asc: Some(true),
1763+
nulls_first: Some(true),
1764+
}];
1765+
assert_eq!(
1766+
&Expr::WithinGroup(WithinGroup {
1767+
expr: Box::new(function),
1768+
order_by: within_group
1769+
}),
1770+
expr_from_projection(only(&select.projection))
1771+
);
1772+
}
1773+
17391774
#[test]
17401775
fn parse_create_table() {
17411776
let sql = "CREATE TABLE uk_cities (\

0 commit comments

Comments
 (0)