Skip to content

Commit f366549

Browse files
committed
Support SAMPLE clause on subqueries (derived tables)
Add support for SAMPLE clause on subqueries/derived tables. Previously, SAMPLE clause was only supported on table references, but Snowflake and other databases also support it on subqueries. Example: SELECT * FROM (SELECT * FROM mytable) SAMPLE (10) SELECT * FROM (SELECT * FROM mytable) AS t SAMPLE (50 PERCENT) SELECT * FROM (SELECT * FROM mytable) SAMPLE (10) SEED (42)
1 parent 0cf85d3 commit f366549

5 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/ast/query.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,8 @@ pub enum TableFactor {
12421242
lateral: bool,
12431243
subquery: Box<Query>,
12441244
alias: Option<TableAlias>,
1245+
/// Optional table sample modifier
1246+
sample: Option<TableSampleKind>,
12451247
},
12461248
/// `TABLE(<expr>)[ AS <alias> ]`
12471249
TableFunction {
@@ -1922,6 +1924,7 @@ impl fmt::Display for TableFactor {
19221924
lateral,
19231925
subquery,
19241926
alias,
1927+
sample,
19251928
} => {
19261929
if *lateral {
19271930
write!(f, "LATERAL ")?;
@@ -1934,6 +1937,9 @@ impl fmt::Display for TableFactor {
19341937
if let Some(alias) = alias {
19351938
write!(f, " {alias}")?;
19361939
}
1940+
if let Some(TableSampleKind::AfterTableAlias(sample)) = sample {
1941+
write!(f, " {sample}")?;
1942+
}
19371943
Ok(())
19381944
}
19391945
TableFactor::Function {

src/ast/spans.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,7 @@ impl Spanned for TableFactor {
18811881
lateral: _,
18821882
subquery,
18831883
alias,
1884+
sample: _,
18841885
} => subquery
18851886
.span()
18861887
.union_opt(&alias.as_ref().map(|alias| alias.span())),

src/parser/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14667,6 +14667,7 @@ impl<'a> Parser<'a> {
1466714667
pipe_operators: vec![],
1466814668
}),
1466914669
alias,
14670+
sample: None,
1467014671
})
1467114672
} else if dialect_of!(self is BigQueryDialect | PostgreSqlDialect | GenericDialect)
1467214673
&& self.parse_keyword(Keyword::UNNEST)
@@ -15467,13 +15468,22 @@ impl<'a> Parser<'a> {
1546715468
let subquery = self.parse_query()?;
1546815469
self.expect_token(&Token::RParen)?;
1546915470
let alias = self.maybe_parse_table_alias()?;
15471+
15472+
// Parse optional SAMPLE clause after alias
15473+
let sample = if let Some(parsed_sample) = self.maybe_parse_table_sample()? {
15474+
Some(TableSampleKind::AfterTableAlias(parsed_sample))
15475+
} else {
15476+
None
15477+
};
15478+
1547015479
Ok(TableFactor::Derived {
1547115480
lateral: match lateral {
1547215481
Lateral => true,
1547315482
NotLateral => false,
1547415483
},
1547515484
subquery,
1547615485
alias,
15486+
sample,
1547715487
})
1547815488
}
1547915489

tests/sqlparser_common.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,8 @@ fn parse_update_set_from() {
512512
format_clause: None,
513513
pipe_operators: vec![],
514514
}),
515-
alias: table_alias(true, "t2")
515+
alias: table_alias(true, "t2"),
516+
sample: None,
516517
},
517518
joins: vec![]
518519
}])),
@@ -7792,6 +7793,7 @@ fn parse_derived_tables() {
77927793
lateral: false,
77937794
subquery: Box::new(verified_query("(SELECT 1) UNION (SELECT 2)")),
77947795
alias: table_alias(true, "t1"),
7796+
sample: None,
77957797
},
77967798
joins: vec![Join {
77977799
relation: table_from_name(ObjectName::from(vec!["t2".into()])),
@@ -8800,6 +8802,7 @@ fn lateral_derived() {
88008802
lateral,
88018803
ref subquery,
88028804
alias: Some(ref alias),
8805+
sample: _,
88038806
} = join.relation
88048807
{
88058808
assert_eq!(lateral_in, lateral);
@@ -9878,6 +9881,7 @@ fn parse_merge() {
98789881
pipe_operators: vec![],
98799882
}),
98809883
alias: table_alias(true, "stg"),
9884+
sample: None,
98819885
}
98829886
);
98839887
assert_eq!(source, source_no_into);

tests/sqlparser_snowflake.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,6 +3515,23 @@ fn test_table_sample() {
35153515
snowflake_and_generic().verified_stmt("SELECT id FROM mytable TABLESAMPLE (10) SEED (1)");
35163516
}
35173517

3518+
#[test]
3519+
fn test_subquery_sample() {
3520+
// Test SAMPLE clause on subqueries (derived tables)
3521+
snowflake_and_generic().verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10)");
3522+
snowflake_and_generic()
3523+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10000 ROWS)");
3524+
snowflake_and_generic()
3525+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) AS t SAMPLE (50 PERCENT)");
3526+
// Nested subquery with SAMPLE
3527+
snowflake_and_generic().verified_stmt(
3528+
"SELECT * FROM (SELECT * FROM (SELECT report_from FROM mytable) SAMPLE (10000 ROWS)) AS anon_1",
3529+
);
3530+
// SAMPLE with SEED on subquery
3531+
snowflake_and_generic()
3532+
.verified_stmt("SELECT * FROM (SELECT * FROM mytable) SAMPLE (10) SEED (42)");
3533+
}
3534+
35183535
#[test]
35193536
fn parse_ls_and_rm() {
35203537
snowflake().one_statement_parses_to("LS @~", "LIST @~");

0 commit comments

Comments
 (0)