选择查询中存储在SQL中的SELECT动态JSON

时间:2019-03-15 09:54:38

标签: sql json sql-server tsql

我知道已经多次问过类似的问题,但是我的情况似乎有些不同。

我的数据库表是这样的:

App ID    |    ID     |     JSONData      |     URL      |     CreatedOn
----------+-----------+-------------------+--------------+-----------------
5b5cd8    |    1      | {"F":"B", "S":"D"}| http://local | Mar 19 2018 13:04
5b5cd8    |    2      | {"F":"C", "S":"K"}| http://remote| Mar 29 2018 09:34
6b9df0    |    3      | {"T":"N", "D":"S"}| http://site  | Apr 04 2018 16:12

App ID列可以具有不同的值,但是对于同一JSONDataApp ID的结构(*应该是相同)。

反正我可以拆分JSONData数据并得到这样的结果吗?

App ID    |    ID     |  F  |  S  |     URL      |     CreatedOn
----------+-----------+-----+-----+--------------+-------------------------
5b5cd8    |    1      |  B  |  D  | http://local | Mar 19 2018 13:04
5b5cd8    |    2      |  C  |  K  | http://remote| Mar 29 2018 09:34

对于下一个App ID,就像这样

App ID    |    ID     |  T  |  D  |     URL      |     CreatedOn
----------+-----------+-----+-----+--------------+-------------------------
6b9df0    |    3      |  N  |  S  | http://site  | Apr 04 2018 16:12

注意JSONData字段中的数据大多是一级深度,即所有数据都是字符串,没有其他对象。

我在大多数情况下都发现的解决方案,例如this,要么是使用静态JSON键名进行拆分,要么是创建将导致性能问题的临时表。

1 个答案:

答案 0 :(得分:0)

您已经被告知,必须预先知道结果集的列名。

唯一的解决方法是动态SQL (将语句创建为字符串,然后创建EXEC()以获得结果)。但这有一些主要缺点(和一些优点)...

您可能会对此感兴趣(需要SQL Server 2016 +):

一个样机表

DECLARE @tbl TABLE(AppID VARCHAR(100),ID INT,JSONData NVARCHAR(MAX));
INSERT INTO @tbl VALUES
 ('5b5cd8',1,N'{"F":"B", "S":"D"}')
,('5b5cd8',2,N'{"F":"C", "S":"K"}')
,('6b9df0',3,N'{"T":"N", "D":"S"}');

-此查询使用JSON_VALUE提取值
-您需要为每个可能的列列表创建一个语句
-应用WHERE过滤适当的行

SELECT t.AppID
      ,t.ID
      ,JSON_VALUE(t.JSONData,'$.F') AS F
      ,JSON_VALUE(t.JSONData,'$.S') AS S
FROM @tbl t
WHERE t.AppID='5b5cd8'

-您可能会包括所有可能的列
-此方法无需过滤器,但会返回很多NULL

SELECT t.AppID
      ,t.ID
      ,JSON_VALUE(t.JSONData,'$.F') AS F
      ,JSON_VALUE(t.JSONData,'$.S') AS S
      ,JSON_VALUE(t.JSONData,'$.T') AS T
      ,JSON_VALUE(t.JSONData,'$.D') AS D
FROM @tbl t

-与OPENJSON()条款

相比,WITH更为清晰/读起来更好
SELECT t.AppID
      ,t.ID
      ,JsonColumns.*
FROM @tbl t
CROSS APPLY OPENJSON(t.JSONData) WITH(F CHAR(1)
                                     ,S CHAR(1)
                                     ,T CHAR(1)
                                     ,D CHAR(1)) JsonColumns 

我的建议:将最后一个创建为VIEW或(可能更好)一个iTVF,并针对每个结构使用专用的语句。