web-dev-qa-db-fra.com

SQL Server: interroger les colonnes sur un objet JSON avec group by

J'ai une table avec 3 colonnes, je veux interroger cette table de telle sorte que le résultat sera un objet JSON. 

Les exemples de données ressemblent à ceci:

 CREATE TABLE #Test (ValueV INT, KEYS NVARCHAR (100), ID INT) 

 INSERT INTO #Test 
 VALUES (1, N'ChangeAdress 19 - 21', 200),
        (1, N'ChangeAdress 20 - 22', 200),
        (1, N'ChangeAdress 22 - 24', 300),
        (1, N'ChangeAdress 23 - 25', 300),
        (2, N'ChangeAdress 24 - 26', 400),
        (2, N'ChangeAdress 25 - 27', 400),
        (3, N'ChangeAdress 26 - 28', 400),
        (3, N'ChangeAdress 27 - 29', 400)

 SELECT * FROM #Test

Ma tentative de requête:

 SELECT ID, Keys, ValueV
 FROM #Test  
 GROUP BY ID, keys, ValueV
 FOR JSON AUTO

Mais cela retourne 1 'ligne' JSON. Ce que je veux, c'est une ligne par groupe. Le groupe est ici ID, combinaison de valeurs. J'ai peu d'expérience avec les objets JSON (ce qui est probablement visible à partir de cette requête), une aide serait donc la bienvenue.

La sortie souhaitée (mais ensuite en tant que JSON par ligne):

 --------------------------------------------------
|200, 1, ChangeAdress 19 - 21, ChangeAdress 20 - 22|
|300, 1, ChangeAdress 22 - 24, ChangeAdress 23 - 25|
|400, 2, ChangeAdress 24 - 26, ChangeAdress 25 - 27|
|400, 3, ChangeAdress 26 - 28, ChangeAdress 27 - 29|

Merci d'avance!

4
SQL_M

Cela fonctionne (dans SQL Server 2017, où STRING_AGG est disponible), mais est assez maladroit. Je ne suis pas sûr qu'il n'y ait pas de manière plus élégante.

SELECT (
    SELECT 
       ID, 
       ValueV, 
       Keys = JSON_QUERY('["' + STRING_AGG(STRING_ESCAPE(Keys, 'json'), '","') + '"]')
    FOR JSON PATH
)
FROM #Test 
GROUP BY ID, ValueV

Pour SQL Server 2016 (qui n'a pas de STRING_AGG ou STRING_ESCAPE d'ailleurs):

SELECT (
    SELECT ID, ValueV, Keys = JSON_QUERY(REPLACE(REPLACE(
        (
            SELECT Keys 
            FROM #Test t2 WHERE t2.ID = t1.ID AND t2.ValueV = t1.ValueV 
            FOR JSON PATH
        ),
        '{"Keys":', ''),
        '}', ''))
    FOR JSON PATH
)
FROM #Test t1
GROUP BY ID, ValueV

Encore moins élégant, mais vous prenez ce que vous pouvez obtenir. Au moins, nous ne sommes pas en concaténation avec FOR XML...

3
Jeroen Mostert

Essaye ça:

SELECT (SELECT [ID], [Keys], [ValueV]  FOR JSON PATH)
FROM #Test 
GROUP BY ID, keys, ValueV

ou ca:

SELECT (SELECT [ID], [Keys], [ValueV]  FOR JSON PATH, WITHOUT_ARRAY_WRAPPER)
FROM #Test 
GROUP BY ID, keys, ValueV
0
newman

Mes deux centimes:

Il est intéressant de noter que vous voulez des lignes JSON individuelles valides et non une seule chaîne JSON. Quoi qu’il en soit, voici quelques réponses alternatives, bien que la réponse acceptée soit la meilleure. 

-- 100% hardcoded yourself. Pre SQL Server 2016 
SELECT '[{"ID":' + convert(nvarchar(4),T1.[ID]) + ',"ValueV":' + convert(nvarchar(4),T1.[ValueV]) + ',"Keys":["' + T1.[Keys] + '","' + T2.[Keys] + '"]}]' AS [keys]
FROM #Test AS T1 INNER JOIN #Test T2 ON t2.ID = t1.ID AND t2.ValueV = t1.ValueV AND t2.keys > t1.keys 

Ou:

-- Use the OPENJSON to output your results as a dataset and not just a single row. I've removed the escape character back slashes to match the accepted answers output  
    SELECT 
     '[' + REPLACE((REPLACE((REPLACE([value], '\','')),':"[',':[')),']"}',']}') + ']'
    FROM OPENJSON(
    (SELECT T1.[ID],T1.[ValueV], '["' + T1.[Keys] + '","' + T2.[Keys] + '"]' AS [keys]
    FROM #Test AS T1 INNER JOIN #Test T2 ON t2.ID = t1.ID AND t2.ValueV = t1.ValueV AND t2.keys > t1.keys 
    FOR JSON PATH))

Ou:

-- This is a lot cleaner for an array of values in pairs. Again using OPENJSON to output your desired result.  
select 
'[' + [Value] + ']' FROM OPENJSON(
(select T1.[ID], T1.[ValueV], JSON_MODIFY(JSON_MODIFY('[]','append lax $',t0.keys),'append lax $',t1.keys) as keys
FROM #Test AS T0 inner join #Test as t1
on  t0.ID = t1.ID AND t0.ValueV = t1.ValueV AND t0.keys < t1.keys
FOR JSON path))

Notez simplement que JSON n’est pas un objet, mais simplement une chaîne de paires de valeurs nommées, un JavaScript valide, mais un sous-ensemble néanmoins, il est complètement différent lorsque vous souhaitez par exemple un objet Javascript imbriqué (si JS est la destination de vos données, Je suppose ici). La fonction JSON est idéale pour extraire rapidement des données à transférer, mais lorsque vous souhaitez une sortie imbriquée ou un groupe de données pour un tableau de valeurs et non d'objets, cela peut devenir assez délicat. Personnellement, comme c'est une chaîne, pour des choses plus compliquées, je la construis moi-même. J'espère que c'est une prise différente. 

0
Useless_Wizard