|
| 1 | +--- |
| 2 | +title: ANY_VALUE (Transact-SQL) |
| 3 | +description: The ANY_VALUE function returns any non-NULL value from a group of rows, or NULL if all values are NULL. |
| 4 | +author: WilliamDAssafMSFT |
| 5 | +ms.author: wiassaf |
| 6 | +ms.reviewer: jovanpop |
| 7 | +ms.date: 03/17/2026 |
| 8 | +ms.service: sql |
| 9 | +ms.subservice: t-sql |
| 10 | +ms.topic: reference |
| 11 | +f1_keywords: |
| 12 | + - "ANY_VALUE_TSQL" |
| 13 | + - "ANY_VALUE" |
| 14 | +helpviewer_keywords: |
| 15 | + - "ANY_VALUE function" |
| 16 | + - "analytic functions, ANY_VALUE" |
| 17 | +dev_langs: |
| 18 | + - TSQL |
| 19 | +monikerRange: "=fabric" |
| 20 | +--- |
| 21 | + |
| 22 | +# ANY_VALUE (Transact-SQL) |
| 23 | + |
| 24 | +[!INCLUDE [fabricdw](../../includes/applies-to-version/fabric-dw.md)] |
| 25 | + |
| 26 | +The `ANY_VALUE` function returns any (non-`NULL` if possible) value from a group of rows. You can use it as both an aggregate function and a window (analytic) function: |
| 27 | + |
| 28 | +- Aggregate usage: Returns an arbitrary value from the entire group. |
| 29 | +- Window usage: Operates over a defined window frame and returns an arbitrary value from the entire window. |
| 30 | + |
| 31 | +:::image type="icon" source="../../includes/media/topic-link-icon.svg" border="false"::: [Transact-SQL syntax conventions](../../t-sql/language-elements/transact-sql-syntax-conventions-transact-sql.md) |
| 32 | + |
| 33 | +## Syntax |
| 34 | + |
| 35 | +Aggregation function syntax: |
| 36 | + |
| 37 | +```syntaxsql |
| 38 | +ANY_VALUE ( [ ALL | DISTINCT ] expression ) |
| 39 | +``` |
| 40 | + |
| 41 | +Analytic function syntax: |
| 42 | + |
| 43 | +```syntaxsql |
| 44 | +ANY_VALUE ( [ ALL | DISTINCT ] expression) OVER ( [ <partition_by_clause> ] [ <order_by_clause> ] ) |
| 45 | +``` |
| 46 | + |
| 47 | +## Arguments |
| 48 | + |
| 49 | +#### ALL |
| 50 | + |
| 51 | +Applies the aggregate function to all values. ALL is the default, only meaningful option, and is available for ISO compatibility only. |
| 52 | + |
| 53 | +#### DISTINCT |
| 54 | + |
| 55 | +`DISTINCT` isn't meaningful with `ANY_VALUE`, and is available for ISO compatibility only. |
| 56 | + |
| 57 | +#### *expression* |
| 58 | + |
| 59 | + The value to be returned. Any of the values can be returned as the result, but the `NULL` values are skipped if possible. |
| 60 | + |
| 61 | +#### OVER clause |
| 62 | + |
| 63 | +The *partition_by_clause* divides the result set produced by the `FROM` clause into partitions, and the function is applied to each partition. |
| 64 | + |
| 65 | +If you don't specify this clause, the function treats all rows of the query result set as a single group. |
| 66 | + |
| 67 | +The *order_by_clause* determines the order of the data before the function is applied. If you specify *partition_by_clause*, it determines the order of the data in the partition. The *order_by_clause* isn't required. |
| 68 | + |
| 69 | +For more information, see [SELECT - OVER clause (Transact-SQL)](../queries/select-over-clause-transact-sql.md). |
| 70 | + |
| 71 | +## Return types |
| 72 | + |
| 73 | +Returns a value of the same type as *expression*. |
| 74 | + |
| 75 | +## Remarks |
| 76 | + |
| 77 | +`ANY_VALUE` is nondeterministic. For more information, see [Deterministic and nondeterministic functions](../../relational-databases/user-defined-functions/deterministic-and-nondeterministic-functions.md). Unlike `FIRST_VALUE` or `LAST_VALUE`, `ANY_VALUE` doesn't provide deterministic ordering. It's designed for cases where the exact value isn't important to the query logic. |
| 78 | + |
| 79 | +The function attempts to return a non-`NULL` value when possible and returns `NULL` value only if all values are `NULL`. |
| 80 | + |
| 81 | +## Use case |
| 82 | + |
| 83 | +A common use case for `ANY_VALUE` is when you need to include nonkey columns in a result set grouped by a key column. For example, if you group rows by `StoreID`, you can use `ANY_VALUE` to return values for columns such as store name, address, or other descriptive attributes without adding them to the `GROUP BY` clause or using more expensive functions like `MAX`, `MIN`, `FIRST_VALUE`, or `LAST_VALUE` to include them in the projection. This approach simplifies query design, improves readability, and enhances performance because SQL query doesn't need to perform unnecessary grouping on the descriptive columns. As a result, your aggregation remains concise, easier to maintain, and more efficient. |
| 84 | + |
| 85 | +## Examples |
| 86 | + |
| 87 | +### A. Retrieve any non-NULL value |
| 88 | + |
| 89 | +This simple query demonstrates how `ANY_VALUE` can return an arbitrary non-NULL value from a set of values: |
| 90 | + |
| 91 | +```sql |
| 92 | +SELECT ANY_VALUE(v) |
| 93 | +FROM (VALUES (NULL), (NULL), (NULL), (NULL), (2), (NULL), (NULL), (7), (NULL), (NULL)) AS t(v); |
| 94 | +``` |
| 95 | + |
| 96 | +The function ignores `NULL` values and returns one of the non-`NULL` values (sometimes 2, sometimes 7) in a nondeterministic way. |
| 97 | + |
| 98 | +### B. Project descriptive columns |
| 99 | + |
| 100 | +This query summarizes total sales per store by joining `FactSales` with `DimStore`, grouping on `StoreKey`, and retrieving key store details using `ANY_VALUE`. |
| 101 | + |
| 102 | +```sql |
| 103 | +USE ContosoDW; |
| 104 | +GO |
| 105 | +SELECT |
| 106 | + fs.StoreKey, |
| 107 | + ANY_VALUE(ds.StoreName) AS StoreName, |
| 108 | + ANY_VALUE(ds.StoreDescription) AS StoreDescription, |
| 109 | + ANY_VALUE(ds.Status) AS StoreStatus, |
| 110 | + ANY_VALUE(ds.Phone) AS StorePhone, |
| 111 | + ANY_VALUE(ds.Fax) AS StoreFax, |
| 112 | + ANY_VALUE(ds.ZipCode) AS ZipCode, |
| 113 | + ANY_VALUE(ds.AddressLine1) AS AddressLine1, |
| 114 | + ANY_VALUE(ds.AddressLine2) AS AddressLine2, |
| 115 | + SUM(fs.UnitPrice * fs.SalesQuantity) AS SalesAmount |
| 116 | +FROM dbo.FactSales AS fs |
| 117 | +LEFT JOIN dbo.DimStore AS ds |
| 118 | + ON ds.StoreKey = fs.StoreKey |
| 119 | +GROUP BY |
| 120 | + fs.StoreKey; |
| 121 | +``` |
| 122 | + |
| 123 | +By applying the `ANY_VALUE` function, you can include nongrouping columns (such as `StoreName`, `StoreDescription`, `StoreStatus`, `StorePhone`, `StoreFax`, `ZipCode`, `AddressLine1`, and `AddressLine2`) without listing them in the `GROUP BY` clause. |
| 124 | + |
| 125 | +### C. Unpivot values from rows to columns |
| 126 | + |
| 127 | +The `FactSales` table contains one row per line item, where `OrderKey` identifies the order. For each order, attributes such as `OrderDate`, `DeliveryDate`, `CustomerKey`, and `StoreKey` are repeated across all rows belonging to the same `OrderKey`. In contrast, `ProductKey` varies by line item, with one product per `LineNumber`. |
| 128 | + |
| 129 | +The following query pivots the `FactSales` rows so that each `OrderKey` is a single row. It keeps the shared order-level attributes and creates a separate column (`ProductKey0`, `ProductKey1`, ...) for the product associated with each line number. The `ANY_VALUE` function is used to pick a representative value from each group, while the conditional expressions extract the product for each specific line item. |
| 130 | + |
| 131 | +```sql |
| 132 | +SELECT |
| 133 | + OrderKey, |
| 134 | + -- Projecting groups that are same within the group. |
| 135 | + ANY_VALUE(OrderDate) AS OrderDate, |
| 136 | + ANY_VALUE(DeliveryDate) AS DeliveryDate, |
| 137 | + ANY_VALUE(CustomerKey) AS CustomerKey, |
| 138 | + ANY_VALUE(StoreKey) AS StoreKey, |
| 139 | + -- Unpivoted values returned as multiple columns per row |
| 140 | + ANY_VALUE(IIF(LineNumber = 0, ProductKey, NULL)) AS ProductKey0, |
| 141 | + ANY_VALUE(IIF(LineNumber = 1, ProductKey, NULL)) AS ProductKey1, |
| 142 | + ANY_VALUE(IIF(LineNumber = 2, ProductKey, NULL)) AS ProductKey2, |
| 143 | + ANY_VALUE(IIF(LineNumber = 3, ProductKey, NULL)) AS ProductKey3, |
| 144 | + ANY_VALUE(IIF(LineNumber = 4, ProductKey, NULL)) AS ProductKey4, |
| 145 | + ANY_VALUE(IIF(LineNumber = 5, ProductKey, NULL)) AS ProductKey5, |
| 146 | + ANY_VALUE(IIF(LineNumber = 6, ProductKey, NULL)) AS ProductKey6 |
| 147 | +FROM dbo.FactSales |
| 148 | +GROUP BY |
| 149 | + OrderKey; |
| 150 | +``` |
| 151 | + |
| 152 | +By using the `ANY_VALUE` function, you avoid placing `OrderDate`, `DeliveryDate`, `CustomerKey`, and `StoreKey` in the `GROUP BY` clause. The `ANY_VALUE` function simplifies the query and can improve performance because only a single column (`OrderKey`) is used in the `GROUP BY` clause. |
| 153 | +The `ANY_VALUE` + `CASE WHEN` pattern extracts the appropriate `ProductKey` for each line item and returns them as separate columns. In practice, this pattern produces a programmatic pivot of the product keys (an alternative to the traditional `UNPIVOT` operator). |
| 154 | + |
| 155 | +### D. Random value per two column partition |
| 156 | + |
| 157 | +You're producing a sales-level detail report with a daily key performance indicator (KPI) per store. In the report, you need to return the same `SalesOrderNumber` per (`StoreKey`, `DateKey`) partition where no business rule exists to pick a specific `SalesOrderNumber`. There's no requirement to pick earliest, latest, or greatest order per line in the report. For example, the user interface shows "a reference order for the store-day" next to each line so an analyst can quickly jump to an order from the (store, day) pair. |
| 158 | + |
| 159 | +The intent is to return one consistent `SalesOrderNumber` per (store, day). |
| 160 | + |
| 161 | +```sql |
| 162 | +USE ContosoDW; |
| 163 | +GO |
| 164 | +SELECT |
| 165 | + fs.DateKey, |
| 166 | + fs.StoreKey, |
| 167 | + |
| 168 | + -- Window KPI: total sales per Store-Day (keeps row-level output) |
| 169 | + SUM(fs.UnitPrice * fs.SalesQuantity) |
| 170 | + OVER (PARTITION BY fs.StoreKey, dd.DateKey) AS DailySales, |
| 171 | + |
| 172 | + -- Partition label with no preferred ordering: any one order from that Store-Day |
| 173 | + ANY_VALUE(fs.SalesOrderNumber) |
| 174 | + OVER (PARTITION BY fs.StoreKey, dd.DateKey) AS SampleOrderNumber |
| 175 | + |
| 176 | +FROM dbo.FactSales AS fs; |
| 177 | +``` |
| 178 | + |
| 179 | +If you replace the `ANY_VALUE(fs.SalesOrderNumber)` expression with `fs.SalesOrderNumber` column reference, the label varies row-by-row; you lose the "one consistent label per (store, day)" behavior. |
| 180 | + |
| 181 | +## Related content |
| 182 | + |
| 183 | +- [Aggregate functions (Transact-SQL)](aggregate-functions-transact-sql.md) |
| 184 | +- [Analytic functions (Transact-SQL)](analytic-functions-transact-sql.md) |
| 185 | +- [SELECT - OVER clause (Transact-SQL)](../queries/select-over-clause-transact-sql.md) |
0 commit comments