Skip to content

Commit c944dcc

Browse files
20260318 ANY_VALUE function (#36250)
Co-authored-by: WilliamDAssafMSFT <74387232+WilliamDAssafMSFT@users.noreply.github.com>
1 parent cd5a65a commit c944dcc

4 files changed

Lines changed: 238 additions & 50 deletions

File tree

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
2-
title: "Aggregate Functions (Transact-SQL)"
3-
description: "Aggregate Functions (Transact-SQL)"
2+
title: Aggregate Functions (Transact-SQL)
3+
description: An aggregate function in Transact-SQL performs a calculation on a set of values, and returns a single value. Learn about the aggregate functions in the SQL Database Engine.
44
author: markingmyname
55
ms.author: maghan
6-
ms.date: "08/15/2018"
6+
ms.date: 03/17/2026
77
ms.service: sql
88
ms.subservice: t-sql
99
ms.topic: reference
@@ -15,41 +15,42 @@ helpviewer_keywords:
1515
- "summarizing functions"
1616
- "aggregate functions [SQL Server]"
1717
dev_langs:
18-
- "TSQL"
18+
- TSQL
1919
monikerRange: ">=aps-pdw-2016 || =azuresqldb-current || =azure-sqldw-latest || >=sql-server-2016 || >=sql-server-linux-2017 || =azuresqldb-mi-current || =fabric || =fabric-sqldb"
2020
---
21-
# Aggregate Functions (Transact-SQL)
21+
# Aggregate functions (Transact-SQL)
22+
2223
[!INCLUDE [sql-asdb-asdbmi-asa-pdw-fabricse-fabricdw-fabricsqldb](../../includes/applies-to-version/sql-asdb-asdbmi-asa-pdw-fabricse-fabricdw-fabricsqldb.md)]
2324

24-
An aggregate function performs a calculation on a set of values, and returns a single value. Except for `COUNT(*)`, aggregate functions ignore null values. Aggregate functions are often used with the GROUP BY clause of the SELECT statement.
25-
26-
All aggregate functions are deterministic. In other words, aggregate functions return the same value each time that they are called, when called with a specific set of input values. See [Deterministic and Nondeterministic Functions](../../relational-databases/user-defined-functions/deterministic-and-nondeterministic-functions.md) for more information about function determinism. The [OVER clause](../../t-sql/queries/select-over-clause-transact-sql.md) may follow all aggregate functions, except the STRING_AGG, GROUPING or GROUPING_ID functions.
27-
25+
An aggregate function in the [Microsoft SQL Database Engine](../../database-engine/sql-database-engine.md) performs a calculation on a set of values, and returns a single value. Except for `COUNT(*)`, aggregate functions ignore `NULL` values. Aggregate functions are often used with the `GROUP BY` clause of the SELECT statement.
26+
27+
All aggregate functions are deterministic. In other words, aggregate functions return the same value each time that they are called, when called with a specific set of input values. See [Deterministic and nondeterministic functions](../../relational-databases/user-defined-functions/deterministic-and-nondeterministic-functions.md) for more information about function determinism. The [OVER clause](../queries/select-over-clause-transact-sql.md) might follow all aggregate functions, except the `STRING_AGG`, `GROUPING`, or `GROUPING_ID` functions.
28+
2829
Use aggregate functions as expressions only in the following situations:
29-
- The select list of a SELECT statement (either a subquery or an outer query).
30-
- A HAVING clause.
31-
30+
31+
- The select list of a `SELECT` statement (either a subquery or an outer query).
32+
- A `HAVING` clause.
33+
3234
[!INCLUDE[tsql](../../includes/tsql-md.md)] provides the following aggregate functions:
3335

34-
- [APPROX_COUNT_DISTINCT](../../t-sql/functions/approx-count-distinct-transact-sql.md)
35-
- [AVG](../../t-sql/functions/avg-transact-sql.md)
36-
- [CHECKSUM_AGG](../../t-sql/functions/checksum-agg-transact-sql.md)
37-
- [COUNT](../../t-sql/functions/count-transact-sql.md)
38-
- [COUNT_BIG](../../t-sql/functions/count-big-transact-sql.md)
39-
- [GROUPING](../../t-sql/functions/grouping-transact-sql.md)
40-
- [GROUPING_ID](../../t-sql/functions/grouping-id-transact-sql.md)
41-
- [MAX](../../t-sql/functions/max-transact-sql.md)
42-
- [MIN](../../t-sql/functions/min-transact-sql.md)
43-
- [STDEV](../../t-sql/functions/stdev-transact-sql.md)
44-
- [STDEVP](../../t-sql/functions/stdevp-transact-sql.md)
45-
- [STRING_AGG](../../t-sql/functions/string-agg-transact-sql.md)
46-
- [SUM](../../t-sql/functions/sum-transact-sql.md)
47-
- [VAR](../../t-sql/functions/var-transact-sql.md)
48-
- [VARP](../../t-sql/functions/varp-transact-sql.md)
49-
50-
## See also
51-
[Built-in Functions &#40;Transact-SQL&#41;](../../t-sql/functions/functions.md)
52-
[OVER Clause &#40;Transact-SQL&#41;](../../t-sql/queries/select-over-clause-transact-sql.md)
53-
54-
36+
- [ANY_VALUE](any-value-transact-sql.md)
37+
- [APPROX_COUNT_DISTINCT](approx-count-distinct-transact-sql.md)
38+
- [AVG](avg-transact-sql.md)
39+
- [CHECKSUM_AGG](checksum-agg-transact-sql.md)
40+
- [COUNT](count-transact-sql.md)
41+
- [COUNT_BIG](count-big-transact-sql.md)
42+
- [GROUPING](grouping-transact-sql.md)
43+
- [GROUPING_ID](grouping-id-transact-sql.md)
44+
- [MAX](max-transact-sql.md)
45+
- [MIN](min-transact-sql.md)
46+
- [STDEV](stdev-transact-sql.md)
47+
- [STDEVP](stdevp-transact-sql.md)
48+
- [STRING_AGG](string-agg-transact-sql.md)
49+
- [SUM](sum-transact-sql.md)
50+
- [VAR](var-transact-sql.md)
51+
- [VARP](varp-transact-sql.md)
52+
53+
## Related content
5554

55+
- [What are the SQL database functions?](functions.md)
56+
- [SELECT - OVER clause (Transact-SQL)](../queries/select-over-clause-transact-sql.md)
Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
---
2-
title: "Analytic Functions (Transact-SQL)"
3-
description: "Analytic Functions (Transact-SQL)"
2+
title: Analytic Functions (Transact-SQL)
3+
description: Analytic functions in Transact-SQL calculate an aggregate value based on a group of rows. Learn about the analytic functions in the SQL Database Engine.
44
author: markingmyname
55
ms.author: maghan
66
ms.reviewer: randolphwest
7-
ms.date: 05/09/2022
7+
ms.date: 03/17/2026
88
ms.service: sql
99
ms.subservice: t-sql
1010
ms.topic: reference
1111
ms.custom:
1212
- ignite-2025
1313
dev_langs:
14-
- "TSQL"
14+
- TSQL
1515
monikerRange: ">=aps-pdw-2016 || =azuresqldb-current || =azure-sqldw-latest || >=sql-server-2016 || >=sql-server-linux-2017 || =azuresqldb-mi-current || =fabric || =fabric-sqldb"
1616
---
1717
# Analytic functions (Transact-SQL)
1818

1919
[!INCLUDE [sql-asdb-asdbmi-asa-pdw-edge-fabricse-fabricdw-fabricsqldb](../../includes/applies-to-version/sql-asdb-asdbmi-asa-pdw-edge-fabricse-fabricdw-fabricsqldb.md)]
2020

21-
SQL Server supports these analytic functions:
22-
23-
- [CUME_DIST &#40;Transact-SQL&#41;](../../t-sql/functions/cume-dist-transact-sql.md)
24-
- [FIRST_VALUE &#40;Transact-SQL&#41;](../../t-sql/functions/first-value-transact-sql.md)
25-
- [LAG &#40;Transact-SQL&#41;](../../t-sql/functions/lag-transact-sql.md)
26-
- [LAST_VALUE &#40;Transact-SQL&#41;](../../t-sql/functions/last-value-transact-sql.md)
27-
- [LEAD &#40;Transact-SQL&#41;](../../t-sql/functions/lead-transact-sql.md)
28-
- [PERCENT_RANK &#40;Transact-SQL&#41;](../../t-sql/functions/percent-rank-transact-sql.md)
29-
- [PERCENTILE_CONT &#40;Transact-SQL&#41;](../../t-sql/functions/percentile-cont-transact-sql.md)
30-
- [PERCENTILE_DISC &#40;Transact-SQL&#41;](../../t-sql/functions/percentile-disc-transact-sql.md)
31-
3221
Analytic functions calculate an aggregate value based on a group of rows. Unlike aggregate functions, however, analytic functions can return multiple rows for each group. Use analytic functions to compute moving averages, running totals, percentages or top-N results within a group.
3322

34-
## See also
23+
The [Microsoft SQL Database Engine](../../database-engine/sql-database-engine.md) supports these analytic functions:
24+
25+
- [ANY_VALUE](any-value-transact-sql.md)
26+
- [CUME_DIST](cume-dist-transact-sql.md)
27+
- [FIRST_VALUE](first-value-transact-sql.md)
28+
- [LAG](lag-transact-sql.md)
29+
- [LAST_VALUE](last-value-transact-sql.md)
30+
- [LEAD](lead-transact-sql.md)
31+
- [PERCENT_RANK](percent-rank-transact-sql.md)
32+
- [PERCENTILE_CONT](percentile-cont-transact-sql.md)
33+
- [PERCENTILE_DISC](percentile-disc-transact-sql.md)
3534

36-
- [OVER Clause &#40;Transact-SQL&#41;](../../t-sql/queries/select-over-clause-transact-sql.md)
35+
## Related content
3736

37+
- [SELECT - OVER clause (Transact-SQL)](../queries/select-over-clause-transact-sql.md)
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
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)

docs/toc.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15593,6 +15593,8 @@ items:
1559315593
- name: Aggregate
1559415594
href: t-sql/functions/aggregate-functions-transact-sql.md
1559515595
items:
15596+
- name: ANY_VALUE
15597+
href: t-sql/functions/any-value-transact-sql.md
1559615598
- name: APPROX_COUNT_DISTINCT
1559715599
href: t-sql/functions/approx-count-distinct-transact-sql.md
1559815600
- name: APPROX_PERCENTILE_CONT

0 commit comments

Comments
 (0)