5

I am trying to open up a JSON string and have each key to be its own column. The JSON column lives in a Metadata table with key and polymorphic id.

enter image description here

I want to be able to parse every key into its own column with its corresponding value populated for each polymorphic id.

enter image description here

I can parse each key one by one with json_query, but I see there is a function call openjson which can parse the entire string, but I don't know how to use it since the example from the documentation are applying the function on a set value instead of a column from a table. If there a easier way to parse a JSON string than using json_query?

1
  • 1
    Please provide your date text-based, not picture. It will greatly increase chances to receive the answer. Commented Mar 28, 2019 at 0:32

4 Answers 4

7

I'd try this approach

SELECT t.RelatedPolimorphicId
      ,t.[Key] 
      ,A.*
FROM YourMetaDataTable t
CROSS APPLY OPENJSON(t.[Value]) 
WITH (
     BrandPresent BIT
    ,OneImage BIT
    ,UPCPresenet BIT
    ,ModelNumberPresent BIT
    ,TitlePresent BIT
    ,DescriptionPresent BIT
    ,Feature1Present BIT
) A;

OPENJSON in connection with a WITH clause offers a nice and clean and type-safe(!) approach to read your JSON. I'd use BIT, because true and false will be translated implicitly.

3
  • What if, say ModelNumberPresent is an array and you want to "explode" that aswell?
    – CutePoison
    Commented Oct 19, 2020 at 10:51
  • @CutePoison Just add another call to openjson(A.ModelNumberPresent) B and examine the result (change BIT to NVARCHAR(MAX) AS Json and add B.* to the select list). Commented Oct 19, 2020 at 10:54
  • If you want to, you can add that answer to stackoverflow.com/questions/64424626/…
    – CutePoison
    Commented Oct 19, 2020 at 11:04
3

You may try with the next approach using OPENJSON() and WITH clause (to specify columns and their types). Without WITH clause OPENJSON returns three columns - key, value and type of each {key: value} pair.

Input

CREATE TABLE #Table (
   RelatedPolimorphicId int,
   [Key] nvarchar(50),
   [Value] varchar(max)
)
INSERT INTO #Table
   (RelatedPolimorphicId, [Key], [Value])
VALUES
   (23, N'ContentStats', N'{"BrandPresent": true, "OneImage": true, "UPCPresenet": true, "ModelNumberPresent": true, "TitlePresent": true, "DescriptionPresent": true, "Feature1Present": true}')

Statement

SELECT 
   t.RelatedPolimorphicId,
   j.*
FROM #Table t
CROSS APPLY (
   SELECT * 
   FROM OPENJSON(t.[Value])
   WITH (
       BrandPresent varchar(10) '$.BrandPresent',
       OneImage varchar(10) '$.OneImage',
       UPCPresenet varchar(10) '$.UPCPresenet',
       ModelNumberPresent varchar(10) '$.ModelNumberPresent',
       TitlePresent varchar(10) '$.TitlePresent',
       DescriptionPresent varchar(10) '$.TitlePresent',
       Feature1Present varchar(10) '$.Feature1Present'
   )
) j

Output

RelatedPolimorphicId    BrandPresent    OneImage    UPCPresenet ModelNumberPresent  TitlePresent    DescriptionPresent  Feature1Present
23                      true            true        true        true              true              true            true
1
  • This is correct in principles, but to complicated (no sub-select needed). Still an upvote from my side. Commented Mar 28, 2019 at 10:06
0

Please try this:

SELECT p.RelatedPolymorphId,p.[BrandPresent],p.[OneImage],p.[UPCPresent],p.[ModelNumberPresent],p.[TitlePresent],p.[DescriptionPresent],p.[Feature1Present]
FROM (SELECT v.RelatedPolymorphId,v.Value AS [JsonValue] FROM [YourTableName] v) a
CROSS APPLY OPENJSON(a.JsonValue) j
PIVOT(MAX(j.[value]) FOR j.[key] IN ([BrandPresent],[OneImage],[UPCPresent],[ModelNumberPresent],[TitlePresent],[DescriptionPresent],[Feature1Present])) p
;
5
  • No, PIVOT is the wrong approach here. Better use OPENJSON in connection with a WITH clause. Besides the speed the advantage is the type you can place at each derived column. Furthermore, one could easily set a column alias within the WITH. And very often we need to dive deeper into nested JSON. This would be a mess without WITH... See my answer for an example Commented Mar 28, 2019 at 10:11
  • Why it's "wrong approach"? It is just different which can be useful in some cases. Commented Mar 28, 2019 at 22:08
  • No, one point is, that pivot will force you to return all with the same type, there might be unexpected results due to aggregation, it's a huge overhead and it does not allow for Json-hierarchies. Commented Mar 28, 2019 at 22:21
  • 1
    OPENJSON returns NVARCHAR - results and aggregation are always as expected. I see you're fan of "No" word. Commented Mar 28, 2019 at 22:25
  • No, 😉, the With clause allows to specify the type. Do, whatever you want, in my eyes that's a wrong approach... Happy Coding Commented Mar 28, 2019 at 22:30
0

Thanks everyone for responding. @shnugo, in your solution with openjson, the solution still have to list every key that I wanted to parse, I have solved it with JSON_query, a simpler solution, but the problem is I have more than 40 keys to parse, which is inefficient to list them one by one. I was looking for a function that can parse the JSON column without having to specify each key within the JSON string.

solution with json_query

1
  • 2
    This is not an answer but rather a comment... Well, one principle with SQL-Server is: The engine must no the result set's structure in advance. As you want to use your JSON-internals as column names, you have to tell the engine what to do... Your solution (the link) is by no means easier or more efficient. My solution returns exactly the expected output as you've placed it in your question. If you need something else, please do not change this question, but close it by accept one of the answers and start a new question. Otherwise google "chameleon question". Happy Coding... Commented Mar 28, 2019 at 18:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.