JSON and string aggregation

Completed

SQL Server 2025 introduces new aggregation functions for building JSON arrays, JSON objects, and delimited strings. These additions make it easier to generate structured output such as API responses, reports, or log exports directly from T-SQL queries. The new functions let you move data formatting into the database layer, reducing the need for complex client-side transformation.

Overview of JSON and String Aggregation Functions

Let's look at the three new aggregation functions:

JSON_ARRAYAGG

Creates a JSON array from the values of an expression. Each row’s value becomes an element in the resulting JSON array. It simplifies generating arrays of values such as lists of IDs or names.

JSON_OBJECTAGG

Creates a JSON object from key-value pairs. The first argument defines the key, and the second defines the value. This value-pairing makes it easy to build JSON documents directly from query results.

STRING_CONCAT_WS

Concatenates strings with a specified separator while skipping NULL values. The function’s name stands for String CONCAT With Separator. It provides an efficient way to join values like names, tags, or comma-delimited lists.

String concatenation operator ||

SQL Server 2025 introduces the ANSI-standard || operator as an alternative to + for string concatenation. It provides more portable syntax and is often preferred when combining multiple columns into a single text output.

UNISTR function

UNISTR() returns a Unicode string based on escape sequences, enabling you to insert characters by code point or escape notation. It’s useful when authoring scripts that include nonprintable or multilingual characters.

Example 1: Build JSON Arrays and Objects from Query Results

Imagine your database stores customer order data in two tables, Sales.Customer and Sales.SalesOrderHeader. The analytics team needs a JSON report summarizing each customer and their order IDs for integration with a web dashboard.

Query: Use JSON_ARRAYAGG and JSON_OBJECTAGG

The following query retrieves each customer along with a JSON array of their order IDs, wrapped in a JSON object.

SELECT
    C.CustomerID,
    C.FirstName + ' ' + C.LastName AS CustomerName,
    JSON_OBJECTAGG(
        'Customer' : C.CustomerID,
        'Orders'   : JSON_ARRAYAGG(SOH.SalesOrderID)
    ) AS CustomerSummary
FROM Sales.Customer AS C
JOIN Sales.SalesOrderHeader AS SOH
    ON C.CustomerID = SOH.CustomerID
GROUP BY C.CustomerID, C.FirstName, C.LastName;

Results

CustomerID CustomerName CustomerSummary
11001 Jordan Patterson {"Customer":11001,"Orders":[43722,43723,43724]}
11002 Alicia Tran {"Customer":11002,"Orders":[43725,43726]}
11003 Marco Diaz {"Customer":11003,"Orders":[43727]}

In this example, JSON_ARRAYAGG collects all order IDs for each customer into a JSON array, and JSON_OBJECTAGG wraps the result into a JSON object with clear key-value pairs. The entire structure is produced in one T-SQL query.

Example 2: Format Text Output Using STRING_CONCAT_WS

The marketing team needs a list of each customer’s purchased product names separated by commas for an email campaign. The STRING_CONCAT_WS function can generate these results cleanly, omitting any NULL values.

Query: Join Product Names with a Separator

The following query retrieves each customer along with a comma-separated list of products they purchased.

SELECT
    C.CustomerID,
    C.FirstName + ' ' + C.LastName AS CustomerName,
    STRING_CONCAT_WS(', ',
        P.Name
    ) AS ProductsPurchased
FROM Sales.Customer AS C
JOIN Sales.SalesOrderHeader AS SOH
    ON C.CustomerID = SOH.CustomerID
JOIN Sales.SalesOrderDetail AS SOD
    ON SOH.SalesOrderID = SOD.SalesOrderID
JOIN Production.Product AS P
    ON SOD.ProductID = P.ProductID
GROUP BY C.CustomerID, C.FirstName, C.LastName;

Results

CustomerID CustomerName ProductsPurchased
11001 Jordan Patterson Touring-2000 Blue, 50, Mountain-100 Black, 44
11002 Alicia Tran Road-250 Yellow, 44, Mountain-200 Red, 48
11003 Marco Diaz Touring-3000 Blue, 62

Here, STRING_CONCAT_WS joins product names with commas and ignores NULL entries automatically, avoiding manual COALESCE, or ISNULL logic.

Example 3: Combine JSON and Delimited Text for API Output

You can also use these functions together to prepare structured data for an API response. The following query creates a JSON array of objects where each object contains a customer’s name and comma-delimited product list.

SELECT
    JSON_ARRAYAGG(
        JSON_OBJECTAGG(
            'Customer' : C.FirstName + ' ' + C.LastName,
            'Products' : STRING_CONCAT_WS(', ', P.Name)
        )
    ) AS ApiOutput
FROM Sales.Customer AS C
JOIN Sales.SalesOrderHeader AS SOH
    ON C.CustomerID = SOH.CustomerID
JOIN Sales.SalesOrderDetail AS SOD
    ON SOH.SalesOrderID = SOD.SalesOrderID
JOIN Production.Product AS P
    ON SOD.ProductID = P.ProductID
GROUP BY C.CustomerID, C.FirstName, C.LastName;

Result Sample

[
  {"Customer":"Jordan Patterson","Products":"Touring-2000 Blue, 50, Mountain-100 Black, 44"},
  {"Customer":"Alicia Tran","Products":"Road-250 Yellow, 44, Mountain-200 Red, 48"},
  {"Customer":"Marco Diaz","Products":"Touring-3000 Blue, 62"}
]

An application directly consumes this structure or exports it as a JSON document through tools like SQL Server Management Studio (SSMS) or Azure Data Studio.

Summary

SQL Server 2025 adds JSON_ARRAYAGG, JSON_OBJECTAGG, and STRING_CONCAT_WS to simplify building structured text and JSON output within T-SQL. These functions let you generate application-ready data from queries without external code. Whether you’re preparing JSON payloads, constructing reports, or formatting API responses, these aggregation features make SQL Server 2025 a more versatile platform for modern data applications.