【问题标题】:Create a stored procedure to aggregate rows创建存储过程以聚合行
【发布时间】:2018-08-26 17:35:47
【问题描述】:

有一个包含以下行的事务表:

Id    UserId   PlatformId    TransactionTypeId
-------------------------------------------------
 0       1          3                1
 1       1          1                2
 2       2          3                2
 3       3          2                1
 4       2          3                1

如何编写一个可以将行聚合到具有以下格式的新表中的存储过程?

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

因此,行由用户组合,计算每个平台/事务类型并存储为键/值 json 字符串。

参考:My previous related question

【问题讨论】:

  • 什么版本的 SQL Server?
  • 解决方案将在 Azure 上,所以我认为是 14。
  • 还是 Azure 上的 v12?

标签: sql-server azure stored-procedures aggregate


【解决方案1】:

您可以使用GROUP BY 和FOR JSON:

SELECT MIN(ID) AS ID, UserId, MIN(sub.x) AS Platforms, MIN(sub2.x) AS Transactions
FROM tab t
OUTER APPLY (SELECT CONCAT('p', platformId) AS platform, cnt 
            FROM (SELECT PlatformId, COUNT(*) AS cnt
                  FROM tab t2 WHERE t2.UserId = t.UserId  
                  GROUP BY PlatformId) s
              FOR JSON AUTO) sub(x)
OUTER APPLY (SELECT CONCAT('t', TransactiontypeId) AS Transactions, cnt 
            FROM (SELECT TransactiontypeId, COUNT(*) AS cnt
                  FROM tab t2 WHERE t2.UserId = t.UserId  
                  GROUP BY TransactiontypeId) s
              FOR JSON AUTO) sub2(x)
GROUP BY UserId;

DBFiddle Demo

结果有点不同(键值数组),但请以它为起点。

【讨论】:

  • 使用 Replace 来创建我想要的 json 格式可以吗? Replace(Replace(MIN(sub.x),'"platform":',''),'"cnt":','') 和 Replace(Replace(MIN(sub.x),'"Transactions":' ,''),'"cnt":','')
  • JSON 只是文本。所以你可以在它上面使用任何字符串操作。
【解决方案2】:

您的示例 JSON 并不是真正的 json,但既然您希望这样:

SELECT u.UserId, plt.pValue, ttyp.ttValue
FROM Users AS [u]
CROSS APPLY (
SELECT '{'+STUFF( (SELECT ',"'+pn.pName+'":'+LTRIM(STR(pn.pCount))
    FROM (SELECT p.Name AS pName, COUNT(*) AS pCount 
        FROM transactions t
        left JOIN Platforms p ON p.PlatformID = t.PlatformId
        WHERE t.UserId = u.UserId
        GROUP BY p.PlatformId, p.Name
        ) pn
    FOR XML PATH('')),1,1,'')+'}'
    ) plt(pValue)
CROSS APPLY (
SELECT '{'+STUFF( (SELECT ',"'+tty.ttName+'":'+LTRIM(STR(tty.ttCount))
    FROM (SELECT tt.Name AS ttName, COUNT(*) AS ttCount 
        FROM transactions t
        left JOIN dbo.TransactionType tt ON tt.TransactionTypeId = t.TransactionTypeID
        WHERE t.UserId = u.UserId
        GROUP BY tt.TransactionTypeId, tt.Name
        ) tty
    FOR XML PATH('')),1,1,'')+'}'
    ) ttyp(ttValue)
WHERE EXISTS (SELECT * FROM transactions t WHERE u.UserId = t.UserId)
ORDER BY UserId;

DBFiddle Sample

【讨论】:

  • 不是真的json是什么意思?据我所知,它们是 json 对象? JSON 对象被花括号 {} 包围。 JSON 对象以键/值对的形式编写。键必须是字符串,值必须是有效的 JSON 数据类型(字符串、数字、对象、数组、布尔值或 null)。键和值用冒号分隔。每个键/值对用逗号分隔。
  • @Leila,我的意思是它们只是字典的儿子表示。很难序列化,反序列化它们。最后,您不是也将返回 Platform, cnt 的回复标记为键,而不是完全按照您的要求执行的键吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多