Суммирование json объектов в SQL - PullRequest
0 голосов
/ 26 августа 2018

Как объединять строки и суммировать объекты JSON в SQL?Учитывая следующую таблицу, я хочу очистить строки по UserId и объединить объекты JSON. Учитывая, что ключ JSON заранее неизвестен.

Id    UserId   Platforms          TransactionTypeId
--------------------------------------------------
 0      1      {"p3":1,"p1":1}    {"t1":1,"t2":1}
 1      2      {"p3":2}           {"t2":1,"t1":1}
 3      1      {"p2":1}           {"t1":1}

Результат:

Id    UserId   Platforms                 TransactionTypeId
---------------------------------------------------------
 0      1      {"p3":1,"p1":1,"p2":1}    {"t1":2,"t2":1}
 1      2      {"p3":2}                  {"t2":1,"t1":1}

Ответы [ 2 ]

0 голосов
/ 26 августа 2018
DECLARE @transactions TABLE (Id INT IDENTITY, UserId INT, 
Platforms VARCHAR(MAX), 
TransactionTypeId VARCHAR(MAX));

INSERT INTO @transactions
(
    UserId,
    Platforms,
    TransactionTypeId
)
VALUES
(1, '{"p3":1,"p1":1}', '{"t1":1,"t2":1}'),
(2, '{"p3":2}', '{"t2":1,"t1":1}'),
(1, '{"p2":1}', '{"t1":1}');

WITH plats AS
(
    SELECT UserId,
           p.[Key] AS pName, SUM(CAST(p.Value AS int)) AS pCount
    FROM @transactions
    CROSS APPLY OPENJSON(Platforms) AS p
    GROUP BY UserId, p.[Key]
),
platGroup AS 
(
    SELECT userId,
    JSON_QUERY( '{' + 
    STRING_AGG( '"' + [pName] + '":' + CAST([pCount] AS varchar(10)), ',' )  
    + '}' ) Platforms
    FROM plats
    GROUP BY UserId
),
ttypes AS 
(
    SELECT UserId,
           t.[Key] AS tName, SUM(CAST(t.Value AS Int)) AS tCount
    FROM @transactions
    CROSS APPLY OPENJSON(TransactionTypeId) AS t
    GROUP BY UserId, t.[Key]
),
ttypeGroup AS
(
    SELECT userId,
    JSON_QUERY( '{' + 
    STRING_AGG( '"' + [tName] + '":' + CAST([tCount] AS varchar(10)), ',' )  
    + '}' ) TransactionTypeId
    FROM ttypes
    GROUP BY UserId
)
SELECT COALESCE(pg.UserId, tg.UserId) AS UserId,
       pg.Platforms,
       tg.TransactionTypeId
FROM platGroup pg
FULL JOIN ttypeGroup tg ON tg.UserId = pg.UserId;

Образец DBFiddle

0 голосов
/ 26 августа 2018

Вы можете распаковать JSON с помощью метода OPENJSON, а затем собрать его с помощью STRING_AGG и JSON_QUERY. Простой пример:

USE tempdb
GO

DROP TABLE IF EXISTS jsonWorking;

CREATE TABLE jsonWorking (
    Id                  INT PRIMARY KEY,
    UserId              INT NOT NULL,
    Platforms           NVARCHAR(MAX) NOT NULL,
    TransactionTypeId   NVARCHAR(MAX) NOT NULL
)
GO

INSERT INTO jsonWorking ( Id, UserId, Platforms, TransactionTypeId )
VALUES
    ( 0, 1, '{"p3":1,"p1":1}', '{"t1":1,"t2":1}' ),
    ( 1, 2, '{"p3":2}', '{"t2":1,"t1":1}' ),
    ( 3, 1, '{"p2":1}', '{"t1":1}' )
GO


-- Crack open the json WITH OPENJSON, reassemble it with STRING_AGG and JSON_QUERY
;WITH platforms AS
(
SELECT Id, UserId, [key], [value]
FROM jsonWorking 
    CROSS APPLY OPENJSON ( Platforms )
)
SELECT MIN(Id) Id, UserId, 
    JSON_QUERY( '{' + STRING_AGG( '"' + [key] + '"' + ':' + [value], ',' )  + '}' ) yourJson
FROM platforms
GROUP BY UserId

Мои результаты:

My results

Расширить технику на два столбца JSON немного сложнее, но возможно, например,

;WITH p1 AS
(
SELECT MIN(Id) Id, UserId, [key], SUM( CAST( [value] AS INT ) ) [value]
FROM jsonWorking
    CROSS APPLY OPENJSON ( Platforms )
GROUP BY UserId, [key]
), p2 AS 
(
SELECT MIN(Id) Id, UserId, 
    JSON_QUERY( '{' + STRING_AGG( '"' + [key] + '"' + ':' + CAST( [value] AS VARCHAR(10) ), ',' )  + '}' ) Platforms
FROM p1
GROUP BY UserId
), t1 AS
(
SELECT MIN(Id) AS Id, UserId, [key], SUM( CAST( [value] AS INT ) ) [value]
FROM jsonWorking
    CROSS APPLY OPENJSON ( TransactionTypeId )
GROUP BY UserId, [key]
), t2 AS 
(
SELECT MIN(Id) Id, UserId, 
    JSON_QUERY( '{' + STRING_AGG( '"' + [key] + '"' + ':' + CAST( [value] AS VARCHAR(10) ), ',' )  + '}' ) TransactionTypeId
FROM t1
GROUP BY UserId
)
SELECT p2.Id, p2.UserId, p2.Platforms, t2.TransactionTypeId
FROM p2 
    INNER JOIN t2 ON p2.UserId = t2.UserId
...