3

We are exploring the JSON feature in SQL Sever and for one of the scenarios we want to come up with a SQL which can return a JSON like below

[
  {
    "field": {
      "uuid": "uuid-field-1"
    },
    "value": {
      "uuid": "uuid-value" //value is an object
    }
  },
  {
    "field": {
      "uuid": "uuid-field-2"
    },
    "value": "1". //value is simple integer
  }
  ... more rows
]

The value field can be a simple integer/string or a nested object.

We are able to come up with a table which looks like below:

field.uuid  | value.uuid | value|
------------|----------  | -----|
uuid-field-1| value-uuid | null |
uuid-field-2| null       | 1    |
  ... more rows

But as soon as we apply for json path, it fails saying

Property 'value' cannot be generated in JSON output due to a conflict with another column name or alias. Use different names and aliases for each column in SELECT list.

Is it possible to do it somehow generate this? The value will either be in the value.uuid or value not both?

Note: We are open to possibility of if we can convert each row to individual JSON and add all of them in an array.

0

2 Answers 2

1
select
    json_query((select v.[field.uuid] as 'uuid' for json path, without_array_wrapper)) as 'field',
    value as 'value',
    json_query((select v.[value.uuid] as 'uuid' where v.[value.uuid] is not null for json path, without_array_wrapper)) as 'value'
from
(
values 
    ('uuid-field-1', 'value-uuid1', null),
    ('uuid-field-2', null,  2),
    ('uuid-field-3', 'value-uuid3', null),
    ('uuid-field-4', null,  4)
) as v([field.uuid], [value.uuid], value)
for json auto;--, without_array_wrapper;
Sign up to request clarification or add additional context in comments.

2 Comments

Just a note - if value.uuid and value have not null values, the result will be a JSON with duplicate key names.So, as is mentioned in the question, .. The value will either be the value.uuid or value is a really important condition.
Thanks for the answer @lptr. This seems to be working. Just confirming with you, here the Json Auto is the trick, because if I try same thing with json path it doesn't work.
1

The reason for this error is that (as is mentioned in the documentation) ... FOR JSON PATH clause uses the column alias or column name to determine the key name in the JSON output. If an alias contains dots, the PATH option creates nested objects. In your case value.uuid and value both generate a key with name value.

I can suggest an approach (probably not the best one), which uses JSON_MODIFY() to generate the expected JSON from an empty JSON array:

Table:

CREATE TABLE Data (
   [field.uuid] varchar(100),
   [value.uuid] varchar(100), 
   [value] int
)
INSERT INTO Data 
   ([field.uuid], [value.uuid], [value])
VALUES   
   ('uuid-field-1', 'value-uuid', NULL),
   ('uuid-field-2', NULL,         1),
   ('uuid-field-3', NULL,         3),
   ('uuid-field-4', NULL,         4)

Statement:

DECLARE @json nvarchar(max) = N'[]'
SELECT @json = JSON_MODIFY(
   @json, 
   'append $', 
   JSON_QUERY(
      CASE
         WHEN [value.uuid] IS NOT NULL THEN (SELECT d.[field.uuid], [value.uuid] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
         WHEN [value] IS NOT NULL THEN (SELECT d.[field.uuid], [value] FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
      END   
   )   
)   
FROM Data d   
SELECT @json

Result:

[
    {
        "field":{
            "uuid":"uuid-field-1"
        },
        "value":{
            "uuid":"value-uuid"
        }
    },
    {
        "field":{
            "uuid":"uuid-field-2"
        },
        "value":1
    },
    {
        "field":{
            "uuid":"uuid-field-3"
        },
        "value":3
    },
    {
        "field":{
            "uuid":"uuid-field-4"
        },
        "value":4
    }
]

4 Comments

Thanks for the answer. I did a quick try of your answer and it is working. However I am still new to sql-server JSON features and will try to understand the query provided by you.
BTW just curious. Why would you think it is not the best way, is there a performance this would cause or something else?
@Mritunjay Not the best one mainly because the statement seems complicated.
@Mritunjay The answer is updated with simplified statement. The approach is the same.

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.