Skip to content

Commit e23ef37

Browse files
committed
matched by target/source fixes #1246
1 parent 89bb8ab commit e23ef37

File tree

5 files changed

+46
-5
lines changed

5 files changed

+46
-5
lines changed

sqlglot/dialects/snowflake.py

+1
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ class Tokenizer(tokens.Tokenizer):
254254
class Generator(generator.Generator):
255255
PARAMETER_TOKEN = "$"
256256
INTEGER_DIVISION = False
257+
MATCHED_BY_SOURCE = False
257258

258259
TRANSFORMS = {
259260
**generator.Generator.TRANSFORMS, # type: ignore

sqlglot/expressions.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3764,7 +3764,7 @@ class Merge(Expression):
37643764

37653765

37663766
class When(Func):
3767-
arg_types = {"this": True, "then": True}
3767+
arg_types = {"matched": True, "source": False, "condition": False, "then": True}
37683768

37693769

37703770
def _norm_args(expression):

sqlglot/generator.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ class Generator:
112112
# Whether or not to treat the division operator "/" as integer division
113113
INTEGER_DIVISION = True
114114

115+
# Whether or not MERGE ... WHEN MATCHED BY SOURCE is allowed
116+
MATCHED_BY_SOURCE = True
117+
115118
TYPE_MAPPING = {
116119
exp.DataType.Type.NCHAR: "CHAR",
117120
exp.DataType.Type.NVARCHAR: "VARCHAR",
@@ -1956,7 +1959,11 @@ def kwarg_sql(self, expression: exp.Kwarg) -> str:
19561959
return self.binary(expression, "=>")
19571960

19581961
def when_sql(self, expression: exp.When) -> str:
1959-
this = self.sql(expression, "this")
1962+
matched = "MATCHED" if expression.args["matched"] else "NOT MATCHED"
1963+
source = " BY SOURCE" if self.MATCHED_BY_SOURCE and expression.args.get("source") else ""
1964+
condition = self.sql(expression, "condition")
1965+
condition = f" AND {condition}" if condition else ""
1966+
19601967
then_expression = expression.args.get("then")
19611968
if isinstance(then_expression, exp.Insert):
19621969
then = f"INSERT {self.sql(then_expression, 'this')}"
@@ -1969,7 +1976,7 @@ def when_sql(self, expression: exp.When) -> str:
19691976
then = f"UPDATE SET {self.expressions(then_expression, flat=True)}"
19701977
else:
19711978
then = self.sql(then_expression)
1972-
return f"WHEN {this} THEN {then}"
1979+
return f"WHEN {matched}{source}{condition} THEN {then}"
19731980

19741981
def merge_sql(self, expression: exp.Merge) -> str:
19751982
this = self.sql(expression, "this")

sqlglot/parser.py

+20-2
Original file line numberDiff line numberDiff line change
@@ -3775,7 +3775,15 @@ def _parse_merge(self) -> exp.Expression:
37753775

37763776
whens = []
37773777
while self._match(TokenType.WHEN):
3778-
this = self._parse_conjunction()
3778+
matched = not self._match(TokenType.NOT)
3779+
self._match_text_seq("MATCHED")
3780+
source = (
3781+
False
3782+
if self._match_text_seq("BY", "TARGET")
3783+
else self._match_text_seq("BY", "SOURCE")
3784+
)
3785+
condition = self._parse_conjunction() if self._match(TokenType.AND) else None
3786+
37793787
self._match(TokenType.THEN)
37803788

37813789
if self._match(TokenType.INSERT):
@@ -3800,8 +3808,18 @@ def _parse_merge(self) -> exp.Expression:
38003808
)
38013809
elif self._match(TokenType.DELETE):
38023810
then = self.expression(exp.Var, this=self._prev.text)
3811+
else:
3812+
then = None
38033813

3804-
whens.append(self.expression(exp.When, this=this, then=then))
3814+
whens.append(
3815+
self.expression(
3816+
exp.When,
3817+
matched=matched,
3818+
source=source,
3819+
condition=condition,
3820+
then=then,
3821+
)
3822+
)
38053823

38063824
return self.expression(
38073825
exp.Merge,

tests/dialects/test_bigquery.py

+15
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,18 @@ def test_remove_precision_parameterized_types(self):
390390
"bigquery": "INSERT INTO test (cola, colb) VALUES (CAST(7 AS STRING), CAST(14 AS STRING))",
391391
},
392392
)
393+
394+
def test_merge(self):
395+
self.validate_all(
396+
"""
397+
MERGE dataset.Inventory T
398+
USING dataset.NewArrivals S ON FALSE
399+
WHEN NOT MATCHED BY TARGET AND product LIKE '%a%'
400+
THEN DELETE
401+
WHEN NOT MATCHED BY SOURCE AND product LIKE '%b%'
402+
THEN DELETE""",
403+
write={
404+
"bigquery": "MERGE INTO dataset.Inventory AS T USING dataset.NewArrivals AS S ON FALSE WHEN NOT MATCHED AND product LIKE '%a%' THEN DELETE WHEN NOT MATCHED BY SOURCE AND product LIKE '%b%' THEN DELETE",
405+
"snowflake": "MERGE INTO dataset.Inventory AS T USING dataset.NewArrivals AS S ON FALSE WHEN NOT MATCHED AND product LIKE '%a%' THEN DELETE WHEN NOT MATCHED AND product LIKE '%b%' THEN DELETE",
406+
},
407+
)

0 commit comments

Comments
 (0)