2017-08-21 3 views
2

En se référant à l'exemple fourni par Microsoft:Parsing JSON dans SQL Server

DECLARE @json NVARCHAR(MAX) 
SET @json = 
N'[ 
     { "id" : 2,"info": { "name": "John", "surname": "Smith" }, "age": 25 }, 
     { "id" : 5,"info": { "name": "Jane", "surname": "Smith" }, "dob": "2005-11-04T12:00:00" } 
]' 

SELECT * 
FROM OPENJSON(@json) 
    WITH (id int 'strict $.id', 
     firstName nvarchar(50) '$.info.name', lastName nvarchar(50) '$.info.surname', 
     age int, dateOfBirth datetime2 '$.dob') 

lorsque les données JSON a un tableau à l'intérieur, par exemple:

DECLARE @json NVARCHAR(MAX) 
SET @json = 
N'[ 
     { "id" : 2,"info": { "name": "John", "surname": "Smith" }, 
     "Phones": ["123","345","678"] // like here 
     } 
]' 

Est-il possible de se joindre au tableau sur les données analysées pour obtenir quelque chose comme ceci:

Id  First Name  Last Name Phone 
2  John   Smith  123 
2  John   Smith  345 
2  John   Smith  678 

Répondre

3

OUTER APPLY est votre ami ici. Mélangeons les deux types de lignes pour faire bonne mesure.

DECLARE @json NVARCHAR(MAX) 
SET @json = N' 
[ 
    { 
    "id": 2, 
    "info": { 
     "name": "John", 
     "surname": "Smith" 
    }, 
    "age": 25, 
    "Phones": [ 
     "123", 
     "345", 
     "678" 
    ] 
    }, 
    { 
    "id": 5, 
    "info": { 
     "name": "Jane", 
     "surname": "Smith" 
    }, 
    "dob": "2005-11-04T12:00:00" 
    } 
]' 

SELECT id, [name], [surname], age, dateOfBirth, number 
FROM (
    SELECT * 
    FROM OPENJSON(@json) 
    WITH (
     id   INT    'strict $.id', 
     [name]  NVARCHAR(50) '$.info.name', 
     [surname] NVARCHAR(50) '$.info.surname', 
     age   INT, 
     dateOfBirth DATETIME2  '$.dob', 
     Phones  NVARCHAR(MAX) AS JSON 
    ) 
) AS people 
OUTER APPLY OPENJSON(Phones) 
WITH (
    number NVARCHAR(50) '$' 
) 

Résultat:

+----+------+---------+------+-----------------------------+--------+ 
| id | name | surname | age |   dateOfBirth   | number | 
+----+------+---------+------+-----------------------------+--------+ 
| 2 | John | Smith | 25 | NULL      | 123 | 
| 2 | John | Smith | 25 | NULL      | 345 | 
| 2 | John | Smith | 25 | NULL      | 678 | 
| 5 | Jane | Smith | NULL | 2005-11-04 12:00:00.0000000 | NULL | 
+----+------+---------+------+-----------------------------+--------+ 
+0

grande solution, j'ai été bloqué à ce 'Phones NVARCHAR (MAX) AS JSON' donc mis en œuvre comme la clause de valeurs – TheGameiswar

+0

@TheGameiswar: Si le nombre de valeurs est strictement limité (et/ou connu) les arracher explicitement de la tableau peut être plus rapide qu'un second 'OPENJSON'. Mais j'ai zéro expérience chronométrage JSON, donc pas besoin d'optimiser pour le moment. :-) –

+0

oui vous avez raison, vu juste le plan d'exécution, l'original JSON a été évalué à 0, json ci-dessous l'application externe a été évalué à 20 – TheGameiswar

2

Vous devrez le faire en deux passes:

  1. Extrait pour chaque donnée personne et tableau laissant des numéros de téléphone comme JSON
  2. Utilisez CROSS/OUTER APPLY pour analyser le tableau des numéros de téléphone pour chaque personne et joindre le résultat ensemble

Quelque chose comme ceci:

DECLARE @json NVARCHAR(MAX) 
SET @json = 
N'[ 
    { "id" : 2,"info": { "name": "John", "surname": "Smith" }, "Phones": ["123","345","678"] }, 
    { "id" : 3,"info": { "name": "Jane", "surname": "Smith" }, "Phones": ["321","543"] } 
]'; 

WITH CTE AS (
    SELECT id, firstName, lastName, phones 
    FROM OPENJSON(@json) 
    WITH (
     id INT 'strict $.id', 
     firstName NVARCHAR(50) '$.info.name', 
     lastName NVARCHAR(50) '$.info.surname', 
     phones NVARCHAR(MAX) '$.Phones' AS JSON 
    ) 
) 
SELECT c.id, c.firstName, c.lastName, p.value as phone 
FROM CTE c 
    CROSS APPLY OPENJSON(c.phones) p 
3

Eh bien, vous pouvez toujours faire quelque chose comme ceci:

SELECT ID, FirstName, LastName, value 
FROM OPENJSON(@json) 
WITH(ID int '$.id', 
    FirstName nvarchar(50) '$.info.name', 
    LastName nvarchar(50) '$.info.surname', 
    Phones nvarchar(max) '$.Phones' AS Json) 
CROSS APPLY OPENJSON(Phones) 

Hope this helps.