Home > front end >  T-SQL query to return JSON array of strings
T-SQL query to return JSON array of strings

Time:01-17

I'm hoping to build an optimized data JSON structure that only includes data, no names. I'll included the names in another JSON.

For example

[["1", "William"],["2", "Dylan"]]

I'm looking at "for json auto", running a query like this.

declare @t table(id int, name varchar(20))

insert into @t (id, name) values( 1, 'William')
insert into @t (id, name) values( 2, 'Dylan')

declare @result as varchar(max)

select id, name from @t for json auto  

However it includes the names with every value.

[{"id":1,"name":"William"},{"id":2,"name":"Dylan"}]

Is there a way to instruct SQL Server to omit the names and just return a string array?

I'll need to update a couple hundred queries, so I'm hoping for an answer that doesn't require too much modification on a basic query.

CodePudding user response:

Unfortunately, SQL Server does not support the JSON_AGG function or similar. You can hack it with STRING_AGG and STRING_ESCAPE.

You can either do this with a single aggregation and concatenating the row together

SELECT '['   STRING_AGG(CONCAT(
    '["',
    id,
    '","',
    STRING_ESCAPE(name, 'json'),
    '"]'
    ), ',')   ']'
FROM @t t;

Or with a nested aggregation, aggregating first each row in an unpivoted subquery, then all rows together

SELECT '['   STRING_AGG('['   j.json   ']', ',')   ']'
FROM @t t
CROSS APPLY (
    SELECT STRING_AGG('"'   STRING_ESCAPE(value, 'json')   '"', ',')
    FROM (VALUES
        (CAST(id AS nvarchar(max))),
        (name)
    ) v(value)
) j(json);

db<>fiddle

I've assumed columns are not nullable. Nullable columns will need special handling, I leave it as an exercise to the reader.

CodePudding user response:

Not all that different from Charlie's but uses CONCAT_WS to remove some of the explicit " characters:

SELECT [json] = '[' 
         STRING_AGG('["'   CONCAT_WS('", "', id, 
         STRING_ESCAPE(COALESCE(name,''), N'JSON')) 
         '"]', ',')   ']'
FROM @t;

Output (after adding a 3rd row, values(3, NULL):

json
[["1", "William"],["2", "Dylan"],["3", ""]]

If you want the literal string null with no quotes:

SELECT [json] = '[' 
         STRING_AGG('[' 
         CONCAT_WS(', ', CONCAT('"', id, '"'), 
           COALESCE('"'   STRING_ESCAPE(name, N'JSON')   '"', 'null'))
         ']', ',')   ']'
FROM @t;

Output:

json
[["1", "William"],["2", "Dylan"],["3", null]]

If you don't want the NULL value to present a column in the JSON, just remove the COALESCE:

SELECT [json] = '[' 
         STRING_AGG('["'   CONCAT_WS('", "', id, 
         STRING_ESCAPE(name, N'JSON')) 
         '"]', ',')   ']'
FROM @t;

Output:

json
[["1", "William"],["2", "Dylan"],["3"]]

If you don't want that row present in the JSON at all, just filter it out:

FROM @t WHERE name IS NOT NULL;

If that column doesn't allow NULLs, state it explicitly so we don't have to guess (probably doesn't hurt to confirm id is unique, either):

declare @t table(id int UNIQUE, name varchar(20) NOT NULL);
  •  Tags:  
  • Related