我知道已经多次问过类似的问题,但是我的情况似乎有些不同。
我的数据库表是这样的:
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
列可以具有不同的值,但是对于同一JSONData
,App 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键名进行拆分,要么是创建将导致性能问题的临时表。
答案 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,并针对每个结构使用专用的语句。