Skip to content

Commit 3fade60

Browse files
committed
feat: support multiple value for pivot
1 parent 4921846 commit 3fade60

4 files changed

Lines changed: 32 additions & 7 deletions

File tree

src/ast/query.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ pub enum TableFactor {
13361336
Pivot {
13371337
table: Box<TableFactor>,
13381338
aggregate_functions: Vec<ExprWithAlias>, // Function expression
1339-
value_column: Vec<Ident>,
1339+
value_column: Vec<Expr>, // Expr is a identifier or a compound identifier
13401340
value_source: PivotValueSource,
13411341
default_on_null: Option<Expr>,
13421342
alias: Option<TableAlias>,
@@ -2010,10 +2010,15 @@ impl fmt::Display for TableFactor {
20102010
} => {
20112011
write!(
20122012
f,
2013-
"{table} PIVOT({} FOR {} IN ({value_source})",
2013+
"{table} PIVOT({} FOR ",
20142014
display_comma_separated(aggregate_functions),
2015-
Expr::CompoundIdentifier(value_column.to_vec()),
20162015
)?;
2016+
if value_column.len() == 1 {
2017+
write!(f, "{}", value_column[0])?;
2018+
} else {
2019+
write!(f, "({})", display_comma_separated(value_column))?;
2020+
}
2021+
write!(f, " IN ({value_source})")?;
20172022
if let Some(expr) = default_on_null {
20182023
write!(f, " DEFAULT ON NULL ({expr})")?;
20192024
}

src/ast/spans.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1971,7 +1971,7 @@ impl Spanned for TableFactor {
19711971
} => union_spans(
19721972
core::iter::once(table.span())
19731973
.chain(aggregate_functions.iter().map(|i| i.span()))
1974-
.chain(value_column.iter().map(|i| i.span))
1974+
.chain(value_column.iter().map(|i| i.span()))
19751975
.chain(core::iter::once(value_source.span()))
19761976
.chain(default_on_null.as_ref().map(|i| i.span()))
19771977
.chain(alias.as_ref().map(|i| i.span())),

src/parser/mod.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10820,6 +10820,16 @@ impl<'a> Parser<'a> {
1082010820
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| p.parse_identifier())
1082110821
}
1082210822

10823+
pub fn parse_parenthesized_compound_identifier_list(
10824+
&mut self,
10825+
optional: IsOptional,
10826+
allow_empty: bool,
10827+
) -> Result<Vec<Expr>, ParserError> {
10828+
self.parse_parenthesized_column_list_inner(optional, allow_empty, |p| {
10829+
Ok(Expr::CompoundIdentifier(p.parse_period_separated(|p| p.parse_identifier())?))
10830+
})
10831+
}
10832+
1082310833
/// Parses a parenthesized comma-separated list of index columns, which can be arbitrary
1082410834
/// expressions with ordering information (and an opclass in some dialects).
1082510835
fn parse_parenthesized_index_column_list(&mut self) -> Result<Vec<IndexColumn>, ParserError> {
@@ -13828,7 +13838,11 @@ impl<'a> Parser<'a> {
1382813838
self.expect_token(&Token::LParen)?;
1382913839
let aggregate_functions = self.parse_comma_separated(Self::parse_aliased_function_call)?;
1383013840
self.expect_keyword_is(Keyword::FOR)?;
13831-
let value_column = self.parse_period_separated(|p| p.parse_identifier())?;
13841+
let value_column = if self.peek_token().token == Token::LParen {
13842+
self.parse_parenthesized_compound_identifier_list(Mandatory, false)?
13843+
} else {
13844+
vec![Expr::CompoundIdentifier(self.parse_period_separated(|p| p.parse_identifier())?)]
13845+
};
1383213846
self.expect_keyword_is(Keyword::IN)?;
1383313847

1383413848
self.expect_token(&Token::LParen)?;

tests/sqlparser_common.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10875,7 +10875,7 @@ fn parse_pivot_table() {
1087510875
expected_function("b", Some("t")),
1087610876
expected_function("c", Some("u")),
1087710877
],
10878-
value_column: vec![Ident::new("a"), Ident::new("MONTH")],
10878+
value_column: vec![Expr::CompoundIdentifier(vec![Ident::new("a"), Ident::new("MONTH")])],
1087910879
value_source: PivotValueSource::List(vec![
1088010880
ExprWithAlias {
1088110881
expr: Expr::value(number("1")),
@@ -10922,6 +10922,12 @@ fn parse_pivot_table() {
1092210922
verified_stmt(sql_without_table_alias).to_string(),
1092310923
sql_without_table_alias
1092410924
);
10925+
10926+
let sql_with_multiple_value_column = concat!(
10927+
"SELECT * FROM person ",
10928+
"PIVOT(SUM(age) AS a, AVG(class) AS c FOR (name, age) IN (('John', 30) AS c1, ('Mike', 40) AS c2))"
10929+
);
10930+
assert_eq!(verified_stmt(sql_with_multiple_value_column).to_string(), sql_with_multiple_value_column);
1092510931
}
1092610932

1092710933
#[test]
@@ -11143,7 +11149,7 @@ fn parse_pivot_unpivot_table() {
1114311149
expr: call("sum", [Expr::Identifier(Ident::new("population"))]),
1114411150
alias: None
1114511151
}],
11146-
value_column: vec![Ident::new("year")],
11152+
value_column: vec![Expr::CompoundIdentifier(vec![Ident::new("year")])],
1114711153
value_source: PivotValueSource::List(vec![
1114811154
ExprWithAlias {
1114911155
expr: Expr::Value(

0 commit comments

Comments
 (0)