Repository: tobymao/sqlglot

Issue:
Failure to parse nested ANY_VALUE HAVING MIN [Dialect: BigQuery]
sqlglot 10.1.3 fails to parse this query:

`sqlglot.parse_one('SELECT ANY_VALUE(fruit HAVING MAX sold) AS a_highest_selling_fruit FROM (( SELECT 20 AS sold, "apples" AS fruit UNION ALL SELECT 30 AS sold, "pears" AS fruit UNION ALL SELECT 30 AS sold, "bananas" AS fruit UNION ALL SELECT 10 AS sold, "oranges" AS fruit))')`

It expect a closing ) after HAVING.

**Error**
sqlglot.errors.ParseError: Expecting ). Line 1, Col: 29.
  SELECT ANY_VALUE(fruit HAVING MAX sold) AS a_highest_selling_fruit FROM (( SELECT 20 AS sold, "apples" AS fruit UNION ALL SELECT

**Official Documentation**
BigQuery docs for [ANY_VALUE HAVING MIN](https://cloud.google.com/bigquery/docs/reference/standard-sql/aggregate_functions#any_value)


Discussion:
Hey,

You should generally use the dialect of interest when parsing / generating SQL (here, you'd need `read="bigquery"`).

In this particular case, there's indeed a bug when parsing with `"bigquery"` as the dialect. I'll take a look, thanks for the report!

Resolving patch:
diff --git a/sqlglot/expressions.py b/sqlglot/expressions.py
--- a/sqlglot/expressions.py
+++ b/sqlglot/expressions.py
@@ -3922,7 +3922,7 @@ class Avg(AggFunc):
 
 
 class AnyValue(AggFunc):
-    pass
+    arg_types = {"this": True, "having": False, "max": False}
 
 
 class Case(Func):
diff --git a/sqlglot/generator.py b/sqlglot/generator.py
--- a/sqlglot/generator.py
+++ b/sqlglot/generator.py
@@ -2423,6 +2423,15 @@ def clusteredbyproperty_sql(self, expression: exp.ClusteredByProperty) -> str:
         buckets = self.sql(expression, "buckets")
         return f"CLUSTERED BY ({expressions}){sorted_by} INTO {buckets} BUCKETS"
 
+    def anyvalue_sql(self, expression: exp.AnyValue) -> str:
+        this = self.sql(expression, "this")
+        having = self.sql(expression, "having")
+
+        if having:
+            this = f"{this} HAVING {'MAX' if expression.args.get('max') else 'MIN'} {having}"
+
+        return self.func("ANY_VALUE", this)
+
 
 def cached_generator(
     cache: t.Optional[t.Dict[int, str]] = None
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -717,6 +717,7 @@ class Parser(metaclass=_Parser):
     FUNCTIONS_WITH_ALIASED_ARGS = {"STRUCT"}
 
     FUNCTION_PARSERS: t.Dict[str, t.Callable] = {
+        "ANY_VALUE": lambda self: self._parse_any_value(),
         "CAST": lambda self: self._parse_cast(self.STRICT_CAST),
         "CONCAT": lambda self: self._parse_concat(),
         "CONVERT": lambda self: self._parse_convert(self.STRICT_CAST),
@@ -3678,6 +3679,18 @@ def _parse_extract(self) -> exp.Extract:
 
         return self.expression(exp.Extract, this=this, expression=self._parse_bitwise())
 
+    def _parse_any_value(self) -> exp.AnyValue:
+        this = self._parse_lambda()
+        is_max = None
+        having = None
+
+        if self._match(TokenType.HAVING):
+            self._match_texts(("MAX", "MIN"))
+            is_max = self._prev.text == "MAX"
+            having = self._parse_column()
+
+        return self.expression(exp.AnyValue, this=this, having=having, max=is_max)
+
     def _parse_cast(self, strict: bool) -> exp.Expression:
         this = self._parse_conjunction()
 


Test patch:
diff --git a/tests/dialects/test_bigquery.py b/tests/dialects/test_bigquery.py
--- a/tests/dialects/test_bigquery.py
+++ b/tests/dialects/test_bigquery.py
@@ -29,6 +29,8 @@ def test_bigquery(self):
         with self.assertRaises(ParseError):
             transpile("SELECT * FROM UNNEST(x) AS x(y)", read="bigquery")
 
+        self.validate_identity("SELECT ANY_VALUE(fruit HAVING MAX sold) FROM fruits")
+        self.validate_identity("SELECT ANY_VALUE(fruit HAVING MIN sold) FROM fruits")
         self.validate_identity("SELECT `project-id`.udfs.func(call.dir)")
         self.validate_identity("SELECT CAST(CURRENT_DATE AS STRING FORMAT 'DAY') AS current_day")
         self.validate_identity("SAFE_CAST(encrypted_value AS STRING FORMAT 'BASE64')")