1

I have the following table with JSON collections:

ID SliderJson
1 [{"Slider":11, "Value":2},{"Slider":4, "Value":3}]
2
3 [{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}]

As can be see in the example not all records have a value, and those that have the length of the array vary (by a maximum of 9 items). Ideally I would like to create a column for each slider that contains its entry value, but there are about 400 million records and about 80 different sliders.

So I would be happy to create a columns only for certain sliders, say 4 and 5 and get the following table.

ID SliderJson 4 5
1 [{"Slider":11, "Value":2},{"Slider":4, "Value":3}] 3 NULL
2 NULL NULL
3 [{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}] 3 3

Or alternatively create a table that will extract the json to the columns in the following way:

ID SliderJson slider1 value1 slider2 value2 slider3 value3
1 [{"Slider":11, "Value":2},{"Slider":4, "Value":3}] 11 2 4 3 NULL NULL
2 NULL NULL NULL NULL NULL NULL
3 [{"Slider":11, "Value":4},{"Slider":4, "Value":3},{"Slider":25, "Value":3},{"Slider":2, "Value":4},{"Slider":5, "Value":3}] 11 4 4 3 25 3

Both options are good and working for me, the only consideration is efficiency because as mentioned there are a millions of records (and maybe there are other options that are preferred and I have not thought about). It also important that each record be associated with its original id.

So far I tried the following proceeder, however even when I execute it on very small amount of rows (only 100) it took hours, so I guess something wrong.

DECLARE @NOTE_ID uniqueidentifier
DECLARE @USER_ID uniqueidentifier
DECLARE @SINGEL_SLIDER NVARCHAR(MAX)

DECLARE SLIDER_CURSOR CURSOR FOR SELECT [NoteID],[UserID],[SliderJSON]  FROM [dbo].[SmallData]
OPEN SLIDER_CURSOR

FETCH NEXT FROM SLIDER_CURSOR INTO @NOTE_ID, @USER_ID, @SINGEL_SLIDER
WHILE @@FETCH_STATUS = 0  
BEGIN

IF len(@SINGEL_SLIDER)>1
    BEGIN 

        IF OBJECT_ID('tempdb..#TMP') IS NOT NULL
        DROP TABLE #TMP 

        SELECT *
        INTO #TMP
        FROM OPENJSON(@SINGEL_SLIDER)

        DECLARE @SLIDER_VALUE NVARCHAR(MAX)

        DECLARE SLIDER_VALUE_CURSOR CURSOR FOR SELECT [value]  FROM #TMP
        OPEN SLIDER_VALUE_CURSOR
        FETCH NEXT FROM SLIDER_VALUE_CURSOR INTO  @SLIDER_VALUE
        WHILE @@FETCH_STATUS = 0  
        BEGIN

        IF OBJECT_ID('tempdb..#TMP1') IS NOT NULL
        DROP TABLE #TMP1

        SELECT *
        INTO #TMP1
        FROM OPENJSON(@SLIDER_VALUE)

        DECLARE @SLIDER_ID NVARCHAR(100)
        DECLARE @SLIDER_OPTION_ID  NVARCHAR(100)

        SET @SLIDER_ID = (SELECT [value] FROM #TMP1 WHERE [key] = 'Slider')
        SET @SLIDER_OPTION_ID = (SELECT [value] FROM #TMP1 WHERE [key] = 'Value')

        IF @SLIDER_ID = 4 
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [4] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 7 
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [7] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 1
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [1] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 10
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [10] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 43
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [43] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 15
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [15] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
        ELSE IF @SLIDER_ID = 18
            BEGIN
                UPDATE [dbo].[SmallData]
                SET [18] = @SLIDER_OPTION_ID
                WHERE [NoteID] = @NOTE_ID
            END
    END

 FETCH NEXT FROM SLIDER_VALUE_CURSOR INTO @SLIDER_VALUE
END 

CLOSE SLIDER_VALUE_CURSOR  
DEALLOCATE SLIDER_VALUE_CURSOR 

FETCH NEXT FROM SLIDER_CURSOR INTO @NOTE_ID, @USER_ID, @SINGEL_SLIDER 
END 

CLOSE SLIDER_CURSOR  
DEALLOCATE SLIDER_CURSOR 

I would appreciate any help on this subject.

1
  • 1
    What have you tried so far? Why didn't it work? Have you looked into using OPENJSON? what about the functionalitu didn't you understand? Commented Jul 25, 2021 at 10:07

1 Answer 1

1

I'm unsure why you thought you needed all those cursors and a temp table, they are unnecessary.

You need two OPENJSONs here. To get just the value for each slider, you can just pivot on the slider number.

SELECT
  s.*,
  j.*
FROM dbo.SmallData s
CROSS APPLY (
    SELECT
      pvt.*
    FROM (
        SELECT
          j2.Slider,
          j2.Value
        FROM OPENJSON (s.SliderJSON) j1
        CROSS APPLY OPENJSON (j1.value)
          WITH (Slider int, Value int) j2
    ) j
    PIVOT (
        MIN(Value) FOR Slider IN
        ([4],[5])
    ) pvt
) j;

Your second version can also be done pretty simply with a multi-column pivot.

SELECT
  s.*,
  j.*
FROM dbo.SmallData s
CROSS APPLY (
    SELECT
      MAX(CASE WHEN j1.[key] = '0' THEN j2.Slider END) slider1,
      MAX(CASE WHEN j1.[key] = '0' THEN j2.Value  END)  value1,
      MAX(CASE WHEN j1.[key] = '1' THEN j2.Slider END) slider2,
      MAX(CASE WHEN j1.[key] = '1' THEN j2.Value  END)  value2,
      MAX(CASE WHEN j1.[key] = '2' THEN j2.Slider END) slider3,
      MAX(CASE WHEN j1.[key] = '2' THEN j2.Value  END)  value3,
      MAX(CASE WHEN j1.[key] = '3' THEN j2.Slider END) slider4,
      MAX(CASE WHEN j1.[key] = '3' THEN j2.Value  END)  value4,
      MAX(CASE WHEN j1.[key] = '4' THEN j2.Slider END) slider5,
      MAX(CASE WHEN j1.[key] = '4' THEN j2.Value  END)  value5,
      MAX(CASE WHEN j1.[key] = '5' THEN j2.Slider END) slider6,
      MAX(CASE WHEN j1.[key] = '5' THEN j2.Value  END)  value6,
      MAX(CASE WHEN j1.[key] = '6' THEN j2.Slider END) slider7,
      MAX(CASE WHEN j1.[key] = '6' THEN j2.Value  END)  value7,
      MAX(CASE WHEN j1.[key] = '7' THEN j2.Slider END) slider8,
      MAX(CASE WHEN j1.[key] = '7' THEN j2.Value  END)  value8,
      MAX(CASE WHEN j1.[key] = '8' THEN j2.Slider END) slider9,
      MAX(CASE WHEN j1.[key] = '8' THEN j2.Value  END)  value9
    FROM OPENJSON (s.SliderJSON) j1
    CROSS APPLY OPENJSON (j1.value)
      WITH (Slider int, Value int) j2
) j;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much! the query option work great, however for the first query I get 'Ambiguous column name 'Value'.' Any suggestion?

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.