arraysjsonsql-servert-sqlsql-server-2016

Query to get Value in row split with virgula character


I have the following table:

CREATE TABLE [dbo].[PRC_Tutors]
(
    [ID] [int] NOT NULL,
    [UserID] [int] NOT NULL,
    [LivelloZoom] [int] NULL,
    [PosizioneGIS] [nvarchar](max) NULL,

    CONSTRAINT [PK_PRC_Tutors] 
        PRIMARY KEY CLUSTERED ([ID] ASC)
                WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                      IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                      ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

This is the insert query:

INSERT INTO [dbo].[PRC_Tutors] ([ID], [UserID], [LivelloZoom], [PosizioneGIS])
VALUES (1, 1, 18, 'POLYGON((10.932815861897701 45.598233964590946,11.138809514241451 44.993985917715946,12.270401311116451 44.969266679434696,12.152298283772701 45.529569413809696,10.932815861897701 45.598233964590946))')

INSERT INTO [dbo].[PRC_Tutors] ([ID], [UserID], [LivelloZoom], [PosizioneGIS])
VALUES (2, 100, 10, 'POLYGON((12.053217932309531 44.2095244414735,12.261958166684531 44.14085989069225,12.341609045590781 44.280935574286,12.168574377622031 44.42650442194225,12.053217932309531 44.2095244414735))')

This is my query that returns a JSON:

SELECT  
    CAST((SELECT 
              'OK' As [status],
              TU.livelloZoom AS livelloZoom,
              (SELECT  REPLACE(REPLACE(N.PosizioneGIS, 'POLYGON((',''), '))', '') AS area
               FROM AA_V_PRC_Tutors N
               WHERE N.ID = TU.ID
               FOR JSON PATH, INCLUDE_NULL_VALUES) AS area
          FROM 
              AA_V_PRC_Tutors TU
          WHERE 
              UserID = @User_id
          FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER) AS nvarchar(max))

This is the JSON output of this query:

{
    "status":"OK",
    "livelloZoom":18,
    "area":[
        {"area":"10.932815861897701 45.598233964590946,
        11.138809514241451 44.993985917715946,
        12.270401311116451 44.969266679434696,
        12.152298283772701 45.529569413809696,
        10.932815861897701 45.598233964590946"
        }
    ]
}

But I need to generate the following JSON:

{
    "status":"OK",
    "livelloZoom":18,
    "area":[
        [10.932815861897701, 45.598233964590946],
        [11.138809514241451, 44.993985917715946],
        [12.270401311116451, 44.969266679434696],
        [12.152298283772701, 45.529569413809696],
        [10.932815861897701, 45.598233964590946]
    ]
}

How can I get that JSON?


Solution

  • There are a few approaches to this problem:

    1. Parse the WKT coordinates down to individual elements using a combination of REPLACE() and nested STRING_SPLIT() operations and then rebuild them up into JSON arrays.
    2. Convert the WKT to a geography element and use the built-in geography methods to extract the coordinate components and rebuild them as JSON (as demonstrated in Charlieface's answer - which may be the best approach).
    3. Use REPLACE() to directly convert the WKT into a JSON nested array syntax and include it in the results using JSON_QUERY().

    The below uses the third technique. The limitation is that the original data must precisely follow the expected format - no extra spaces or other variations.

    SELECT 
        'OK' As [status],
        TU.livelloZoom as livelloZoom,
        JSON_QUERY(C.CoordinatesNestedArray) as area
    FROM PRC_Tutors TU
    CROSS APPLY (
        -- From: 'POLYGON((X1 Y1,X2 Y2))' (with no extra spaces)
        -- To:   '[[X1,Y1],[X2,Y2]]'
        SELECT
            REPLACE(REPLACE(REPLACE(REPLACE(
                TU.PosizioneGIS,
                'POLYGON((', '[['), '))' ,']]'), ',' ,'],['), ' ', ',')
                AS CoordinatesNestedArray
    ) C
    WHERE UserID = @User_id
    FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER
    

    Sample Result (formatted using jsonformatter.org):

    {
      "status": "OK",
      "livelloZoom": 18,
      "area": [
        [
          10.932815861897701,
          45.598233964590946
        ],
        [
          11.138809514241451,
          44.993985917715946
        ],
        [
          12.270401311116451,
          44.969266679434696
        ],
        [
          12.152298283772701,
          45.529569413809696
        ],
        [
          10.932815861897701,
          45.598233964590946
        ]
      ]
    }
    

    See this db<>fiddle.