Skip to content
Advertisement

How to extract list of values from JSON in SQL Server

In a SQL Server database, I have a table that contains 2 columns, ID and JSON. The JSON column contains JSON-formatted text. I have access to ISJSON, JSON_VALUE and JSON_QUERY, but not OPENJSON.

I am trying to write a query similar to the one below, that returns the ID column and all of the WorkstationID values. My query returns null. Can someone help me see what I am doing wrong? Below is an example of the JSON data I am working with, as well as my query, and what I expect the output to look like. Thanks for any help that can be offered!

{
   "areas":[
      {
         "type":"rect",
         "coords":[
            85,
            17,
            175,
            98
         ],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"592",
         "WorkstationID":"592"
      },
      {
         "type":"rect",
         "coords":[
            214,
            23,
            316,
            97
         ],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"594",
         "WorkstationID":"594"
      },
      {
         "type":"rect",
         "coords":[
            208,
            132,
            295,
            183
         ],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"595",
         "WorkstationID":"595"
      },
      {
         "type":"rect",
         "coords":[
            84,
            118,
            179,
            248
         ],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"596",
         "WorkstationID":"596"
      },
      {
         "type":"rect",
         "coords":[
            83,
            264,
            185,
            322
         ],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"597",
         "WorkstationID":"597"
      }
   ],
   "img":"/filepath/filename"
}
SELECT ID, JSON_QUERY(JSON,'$.areas') AS WorkstationID
FROM MyTable
WHERE ID = 1
1,592
1,594
1,595
1,596
1,597

UPDATE: As was discussed in the comments below, OPENJSON seems to be the easy way to do this, but this is not possible for me because my compatibility level is < 130. I have found that the following regex string can be used to extract all WorkstationID’s from the JSON.

WorkstationID”:”([0-9]{1,4})

Could using a regular expression like this be useful to return the list of all WorkstationID’s contained in the JSON in a table format like what is explained in a table format?

Advertisement

Answer

Given this is a one-off for you, I’ve written an inefficient JSON to XML converter for you to access your data.

DECLARE @json varchar(8000) =
'{
   "areas":[
      {
         "type":"rect",
         "coords":[85, 17, 175, 98],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"592",
         "WorkstationID":"592"
      },
      {
         "type":"rect",
         "coords":[214, 23, 316, 97],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"594",
         "WorkstationID":"594"
      },
      {
         "type":"rect",
         "coords":[208, 132, 295, 183],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"595",
         "WorkstationID":"595"
      },
      {
         "type":"rect",
         "coords":[84, 118, 179, 248],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"596",
         "WorkstationID":"596"
      },
      {
         "type":"rect",
         "coords":[83, 264, 185, 322],
         "href":"#",
         "alt":"0",
         "title":"0",
         "nameid":"597",
         "WorkstationID":"597"
      }
   ],
   "img":"/filepath/filename"
}';

DECLARE @Fields table ( field varchar(50), tag varchar(50), term varchar(1), id int IDENTITY(1,1) );
INSERT INTO @Fields VALUES
    ( '"type":"', 'type', '"' ),
    ( '"coords":[', 'coords', ']' ),
    ( '"href":"', 'href', '"' ),
    ( '"alt":"', 'alt', '"' ),
    ( '"title":"', 'title', '"' ),
    ( '"nameid":"', 'nameid', '"' ),
    ( '"WorkstationID":"', 'WorkstationID', '"' ); 

-- Convert JSON to XML --
DECLARE @id int = 1, @field varchar(50), @tag varchar(50), @term varchar(1);
WHILE @id <= ( SELECT MAX ( id ) FROM @Fields )
BEGIN

    -- Current Field --
    SELECT 
        @field = field,
        @tag = tag,
        @term = term
    FROM @Fields WHERE id = @id;

    -- Convert field to XML --
    DECLARE @i int = CHARINDEX ( @field, @json );   
    WHILE @i > 0
    BEGIN
    
        -- Stuff in the opening tag --
        SELECT @json = STUFF (
            @json,
            CHARINDEX ( @field, @json, @i ),
            LEN ( @field ),
            '<' + @tag + '>'
        ),
        @json = STUFF (
            @json,
            CHARINDEX ( @term, @json, CHARINDEX ( @tag, @json, @i ) + 1 ),
            LEN ( @term ),
            '</' + @tag + '>'
        );

        -- Continue field search --
        SET @i = CHARINDEX ( @field, @json, @i );

    END

    -- Next Field --
    SET @id = @id + 1;

END

-- Final Cleanup --
SELECT
    @json = REPLACE ( @json, '{', '<data>' ),
    @json = REPLACE ( @json, '}', '</data>' ),
    @json = REPLACE ( @json, '"areas":[', '<areas>' ),
    @json = REPLACE ( @json, ']', '</areas>' ),
    @json = REPLACE ( @json, '"img":"/filepath/filename"', '<img>/filepath/filename</img>' ),
    @json = REPLACE ( @json, '>,', '>' );

-- Select resultset --
SELECT
    t.f.value( 'type[1]', 'varchar(255)' ) AS [type],
    t.f.value( 'coords[1]', 'varchar(255)' ) AS [coords],
    t.f.value( 'href[1]', 'varchar(255)' ) AS [href],
    t.f.value( 'alt[1]', 'varchar(255)' ) AS [alt],
    t.f.value( 'title[1]', 'varchar(255)' ) AS [title],
    t.f.value( 'nameid[1]', 'varchar(255)' ) AS [nameid],
    t.f.value( 'WorkstationID[1]', 'varchar(255)' ) AS [WorkstationID],
    t.f.value( '../../img[1]', 'varchar(255)' ) AS [img]
FROM (
    SELECT CAST ( @json AS xml ) AS d
) x
CROSS APPLY x.d.nodes('//data/areas/data') t(f);

Returns

+------+--------------------+------+-----+-------+--------+---------------+--------------------+
| type |       coords       | href | alt | title | nameid | WorkstationID |        img         |
+------+--------------------+------+-----+-------+--------+---------------+--------------------+
| rect | 85, 17, 175, 98    | #    |   0 |     0 |    592 |           592 | /filepath/filename |
| rect | 214, 23, 316, 97   | #    |   0 |     0 |    594 |           594 | /filepath/filename |
| rect | 208, 132, 295, 183 | #    |   0 |     0 |    595 |           595 | /filepath/filename |
| rect | 84, 118, 179, 248  | #    |   0 |     0 |    596 |           596 | /filepath/filename |
| rect | 83, 264, 185, 322  | #    |   0 |     0 |    597 |           597 | /filepath/filename |
+------+--------------------+------+-----+-------+--------+---------------+--------------------+

Your JSON gets converted to the following XML:

<data>
   <areas>
      <data>
         <type>rect</type>
         <coords>85, 17, 175, 98</coords>
         <href>#</href>
         <alt>0</alt>
         <title>0</title>
         <nameid>592</nameid>
         <WorkstationID>592</WorkstationID>
      </data>
      <data>
         <type>rect</type>
         <coords>214, 23, 316, 97</coords>
         <href>#</href>
         <alt>0</alt>
         <title>0</title>
         <nameid>594</nameid>
         <WorkstationID>594</WorkstationID>
      </data>
      <data>
         <type>rect</type>
         <coords>208, 132, 295, 183</coords>
         <href>#</href>
         <alt>0</alt>
         <title>0</title>
         <nameid>595</nameid>
         <WorkstationID>595</WorkstationID>
      </data>
      <data>
         <type>rect</type>
         <coords>84, 118, 179, 248</coords>
         <href>#</href>
         <alt>0</alt>
         <title>0</title>
         <nameid>596</nameid>
         <WorkstationID>596</WorkstationID>
      </data>
      <data>
         <type>rect</type>
         <coords>83, 264, 185, 322</coords>
         <href>#</href>
         <alt>0</alt>
         <title>0</title>
         <nameid>597</nameid>
         <WorkstationID>597</WorkstationID>
      </data>
   </areas>
   <img>/filepath/filename</img>
</data>
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement