8

I have a table with following fields

 Id     RequestId     CategoryId
 1      112           1
 2      123           1
 3      123           2

SELECT      R.RequestId,
            (SELECT RC.CategoryId FROM Request RC WHERE RC.Id = R.Id FOR JSON AUTO) AS Categories
FROM        Request R

Above query returns the data as mentioned below

 RequestId     Categories
 112           [{"CategoryId":"1"}]
 123           [{"CategoryId":"1"},{"CategoryId":"2"}]

But, I want that column name CategoryId should not be repeated for every item in json array. Thus, my expected result is:

 RequestId     Categories
 112           ["1"]
 123           ["1","2"]
1
  • Hi, what was the best solution for this? Commented Oct 25, 2022 at 8:22

4 Answers 4

3

Was used: SQL to JSON - array of objects to array of values in SQL 2016

create table Request (
  Id int,
  RequestId int,
  CategoryId int
)
GO
insert into Request (Id,RequestId,CategoryId) values
( 1,      112,           1),
( 2,      123,           1),
( 3,      123,           2);
GO
SELECT distinct R.RequestId,
            (
SELECT  
  JSON_QUERY('[' + STUFF(( SELECT ',' + '"' + convert(varchar(10), RC.CategoryId) + '"' 
FROM Request RC
WHERE RC.RequestId = R.RequestId
FOR XML PATH('')),1,1,'') + ']' ) Categories  
FOR JSON PATH , WITHOUT_ARRAY_WRAPPER 
            ) AS Categories
FROM Request R
GO
RequestId | Categories              
--------: | :-----------------------
      112 | {"Categories":["1"]}    
      123 | {"Categories":["1","2"]}
SELECT  distinct R.RequestId,

JSON_QUERY(
            (
SELECT  
  JSON_QUERY('[' + STUFF(( SELECT ',' + '"' + convert(varchar(10), RC.CategoryId) + '"' 
FROM Request RC
WHERE RC.RequestId = R.RequestId
FOR XML PATH('')),1,1,'') + ']' ) Categories  
FOR JSON PATH , WITHOUT_ARRAY_WRAPPER 
            )
, '$.Categories' )
FROM Request R
GO
RequestId | (No column name)
--------: | :---------------
      112 | ["1"]           
      123 | ["1","2"]       

db<>fiddle here

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer. But, STUFF makes query execution really very slow when data is huge. Any thoughts about it?
3

As far as I know, you need to aggregate string yourself and then convert it to json. For example, in Sql Server 2017 you can use STRING_AGG:

select
    t.RequestId,
    concat('[',string_agg(t.CategoryId, ','),']') as Categories
from Table1 as t
group by
    t.RequestId

sql fiddle demo

If you need your array values to be strings instead of integers you can then you need to add " char manually and you also might want to use STRING_ESCAPE so special characters will be converted safely:

select
    t.RequestId,
    concat('[',string_agg(concat('"', string_escape(t.CategoryId, 'json'),'"'),','),']') as Categories
from Table1 as t
group by
    t.RequestId

sql fiddle demo

In yearlier versions of Sql Server you can either use xml trick or create custom clr aggregate.

Comments

1

Can be achieved using REPLACE:

 declare @test table ([Id] int, [RequestId] int, [CategoryId] int)
 insert into @test values
   (1, 112, 1)
 , (2, 123, 1)
 , (3, 123, 2)

    SELECT      R.RequestId,
                json_query(replace(replace((SELECT RC.CategoryId FROM @test RC WHERE RC.Id = R.Id FOR JSON AUTO), '{"CategoryId":', '"'), '}','"'))  AS Categories
    FROM        @test R

Comments

0

For sample table

SELECT Id,RequestId,CategoryId INTO #Request FROM ( values
( 1,      112,           '1'),
( 2,      123,           '1'),
( 3,      123,           '2'))v(Id,RequestId,CategoryId)
;

You can perform a recursive query

 WITH S AS (
    SELECT RequestId,CategoryId,ROW_NUMBER()OVER(Partition BY RequestId ORDER BY CategoryId DESC) _LP FROM  #Request
    )
    , C AS (
    SELECT s.RequestId,JSON_MODIFY('[]','append $',s.CategoryId)w,s._lp
    FROM (SELECT RequestId,MAX(_LP)_MLP FROM S GROUP BY RequestId) S1
    INNER JOIN S ON s.RequestId=s1.RequestId AND s._LP=s1._MLP
    union ALL
    SELECT s.RequestId,JSON_MODIFY(c.w,'append $',s.CategoryId)w,s._lp
    FROM  S
    inner join C ON s.RequestId=c.RequestId and s._LP=c._lp-1
    )
    SELECT RequestId,W Categories FROM C WHERE _LP=1 

You will receive the result:

RequestId   Categories
----------- --------------------
112         ["1"]
123         ["1","2"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.