-
Notifications
You must be signed in to change notification settings - Fork 616
Support IGNORE|RESPECT
NULLs clause in window functions
#998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0a7123b
78cad93
c8ac7fd
3035a79
fa507d8
c8cb2c4
5e5a047
25da82a
9819639
e5b30e5
504a215
b7b9b30
a914309
6432c94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -518,6 +518,7 @@ define_keywords!( | |
REPLACE, | ||
REPLICATION, | ||
RESET, | ||
RESPECT, | ||
RESTRICT, | ||
RESULT, | ||
RETAIN, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -875,6 +875,7 @@ fn parse_select_count_wildcard() { | |
&Expr::Function(Function { | ||
name: ObjectName(vec![Ident::new("COUNT")]), | ||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -896,6 +897,7 @@ fn parse_select_count_distinct() { | |
op: UnaryOperator::Plus, | ||
expr: Box::new(Expr::Identifier(Ident::new("x"))), | ||
}))], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: true, | ||
|
@@ -1864,6 +1866,7 @@ fn parse_select_having() { | |
left: Box::new(Expr::Function(Function { | ||
name: ObjectName(vec![Ident::new("COUNT")]), | ||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Wildcard)], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -1890,6 +1893,7 @@ fn parse_select_qualify() { | |
left: Box::new(Expr::Function(Function { | ||
name: ObjectName(vec![Ident::new("ROW_NUMBER")]), | ||
args: vec![], | ||
null_treatment: None, | ||
filter: None, | ||
over: Some(WindowType::WindowSpec(WindowSpec { | ||
partition_by: vec![Expr::Identifier(Ident::new("p"))], | ||
|
@@ -2287,6 +2291,45 @@ fn parse_agg_with_order_by() { | |
} | ||
} | ||
|
||
#[test] | ||
fn parse_window_rank_function() { | ||
let supported_dialects = TestedDialects { | ||
dialects: vec![ | ||
Box::new(GenericDialect {}), | ||
Box::new(PostgreSqlDialect {}), | ||
Box::new(MsSqlDialect {}), | ||
Box::new(AnsiDialect {}), | ||
Box::new(HiveDialect {}), | ||
Box::new(SnowflakeDialect {}), | ||
], | ||
options: None, | ||
}; | ||
|
||
for sql in [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why were these tests changed? This PR adds support for window functions (aka those that have an I think you should keep the existing tests and add a new one for the IGNORE NULLS / RESPECT NULLs syntax There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the feedback @alamb . The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think that is true when the FIRST_VALUE function is being used as a window function Some systems allow SELECT
FIRST_VALUE(amount ORDER BY time),
LAST_VALUE(amount ORDER BY time)
FROM
t
GROUP BY
currency Perhaps @mustafasrepo can offer some perspective as the author of #882 But basically I think we should retain these tests There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @alamb and @mustafasrepo :) Learned something about these functions :) |
||
"SELECT column1, column2, FIRST_VALUE(column2) OVER (PARTITION BY column1 ORDER BY column2 NULLS LAST) AS column2_first FROM t1", | ||
"SELECT column1, column2, FIRST_VALUE(column2) OVER (ORDER BY column2 NULLS LAST) AS column2_first FROM t1", | ||
"SELECT col_1, col_2, LAG(col_2) OVER (ORDER BY col_1) FROM t1", | ||
"SELECT LAG(col_2, 1, 0) OVER (ORDER BY col_1) FROM t1", | ||
"SELECT LAG(col_2, 1, 0) OVER (PARTITION BY col_3 ORDER BY col_1)", | ||
] { | ||
supported_dialects.verified_stmt(sql); | ||
} | ||
|
||
let supported_dialects_nulls = TestedDialects { | ||
dialects: vec![Box::new(MsSqlDialect {}), Box::new(SnowflakeDialect {})], | ||
options: None, | ||
}; | ||
|
||
for sql in [ | ||
"SELECT column1, column2, FIRST_VALUE(column2) IGNORE NULLS OVER (PARTITION BY column1 ORDER BY column2 NULLS LAST) AS column2_first FROM t1", | ||
"SELECT column1, column2, FIRST_VALUE(column2) RESPECT NULLS OVER (PARTITION BY column1 ORDER BY column2 NULLS LAST) AS column2_first FROM t1", | ||
"SELECT LAG(col_2, 1, 0) IGNORE NULLS OVER (ORDER BY col_1) FROM t1", | ||
"SELECT LAG(col_2, 1, 0) RESPECT NULLS OVER (ORDER BY col_1) FROM t1", | ||
] { | ||
supported_dialects_nulls.verified_stmt(sql); | ||
} | ||
} | ||
|
||
#[test] | ||
fn parse_create_table() { | ||
let sql = "CREATE TABLE uk_cities (\ | ||
|
@@ -3346,6 +3389,7 @@ fn parse_scalar_function_in_projection() { | |
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr( | ||
Expr::Identifier(Ident::new("id")) | ||
))], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -3466,6 +3510,7 @@ fn parse_named_argument_function() { | |
))), | ||
}, | ||
], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -3498,6 +3543,7 @@ fn parse_window_functions() { | |
&Expr::Function(Function { | ||
name: ObjectName(vec![Ident::new("row_number")]), | ||
args: vec![], | ||
null_treatment: None, | ||
filter: None, | ||
over: Some(WindowType::WindowSpec(WindowSpec { | ||
partition_by: vec![], | ||
|
@@ -3542,6 +3588,7 @@ fn test_parse_named_window() { | |
quote_style: None, | ||
}), | ||
))], | ||
null_treatment: None, | ||
filter: None, | ||
over: Some(WindowType::NamedWindow(Ident { | ||
value: "window1".to_string(), | ||
|
@@ -3568,6 +3615,7 @@ fn test_parse_named_window() { | |
quote_style: None, | ||
}), | ||
))], | ||
null_treatment: None, | ||
filter: None, | ||
over: Some(WindowType::NamedWindow(Ident { | ||
value: "window2".to_string(), | ||
|
@@ -4038,6 +4086,7 @@ fn parse_at_timezone() { | |
quote_style: None, | ||
}]), | ||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero.clone()))], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4066,6 +4115,7 @@ fn parse_at_timezone() { | |
quote_style: None, | ||
},],), | ||
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(zero))], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4078,6 +4128,7 @@ fn parse_at_timezone() { | |
Value::SingleQuotedString("%Y-%m-%dT%H".to_string()), | ||
),),), | ||
], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4237,6 +4288,7 @@ fn parse_table_function() { | |
args: vec![FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value( | ||
Value::SingleQuotedString("1".to_owned()), | ||
)))], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4389,6 +4441,7 @@ fn parse_unnest_in_from_clause() { | |
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("2")))), | ||
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("3")))), | ||
], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4419,6 +4472,7 @@ fn parse_unnest_in_from_clause() { | |
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("2")))), | ||
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("3")))), | ||
], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -4431,6 +4485,7 @@ fn parse_unnest_in_from_clause() { | |
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("5")))), | ||
FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Value(number("6")))), | ||
], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -6904,6 +6959,7 @@ fn parse_time_functions() { | |
let select_localtime_func_call_ast = Function { | ||
name: ObjectName(vec![Ident::new(func_name)]), | ||
args: vec![], | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -7391,6 +7447,7 @@ fn parse_pivot_table() { | |
args: (vec![FunctionArg::Unnamed(FunctionArgExpr::Expr( | ||
Expr::CompoundIdentifier(vec![Ident::new("a"), Ident::new("amount"),]) | ||
))]), | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
@@ -7541,6 +7598,7 @@ fn parse_pivot_unpivot_table() { | |
args: (vec![FunctionArg::Unnamed(FunctionArgExpr::Expr( | ||
Expr::Identifier(Ident::new("population")) | ||
))]), | ||
null_treatment: None, | ||
filter: None, | ||
over: None, | ||
distinct: false, | ||
|
Uh oh!
There was an error while loading. Please reload this page.