我有一个nvarchar列,如果内容是有效的JSON,我想返回嵌入在JSON结果中,否则返回字符串。
这是我尝试过的:
select
(
case when IsJson(Arguments) = 1 then
Json_Query(Arguments)
else
Arguments
end
) Results
from Unit
for json path
这总是将结果放入字符串中。
以下内容有效,但前提是该属性包含有效的JSON:
select
(
Json_Query(
case when IsJson(Arguments) = 1 then
Arguments
else
'"' + String_escape(IsNull(Arguments, ''), 'json') + '"' end
)
) Results
from Unit
for json path
如果Arguments不包含JSON对象,则会发生运行时错误。
更新:示例数据:
Arguments
---------
{ "a": "b" }
Some text
更新:任何版本的SQL Server都可以。我什至很高兴知道它即将发布Beta版。
答案 0 :(得分:2)
我找不到一个好的解决方案,并且会很高兴,如果有人带来比这种黑客更好的解决方案:
DECLARE @tbl TABLE(ID INT IDENTITY,Arguments NVARCHAR(MAX));
INSERT INTO @tbl VALUES
(NULL)
,('plain text')
,('[{"id":"1"},{"id":"2"}]');
SELECT t1.ID
,(SELECT Arguments FROM @tbl t2 WHERE t2.ID=t1.ID AND ISJSON(Arguments)=0) Arguments
,(SELECT JSON_QUERY(Arguments) FROM @tbl t2 WHERE t2.ID=t1.ID AND ISJSON(Arguments)=1) ArgumentsJSON
FROM @tbl t1
FOR JSON PATH;
由于省略了NULL值,所以最终结果中总是会出现Arguments
或ArgumentsJSON
。将此JSON视为NVARCHAR(MAX),可以使用REPLACE
将所有名称重命名为相同的Arguments
。
问题似乎是,您不能在SELECT内包括两个具有相同名称的列,但每个列必须具有可预测的类型。这取决于您在CASE(或COALESCE)中使用的顺序。如果引擎认为“好,这是文本”,则所有内容都将被视为文本,并且您的JSON被转义。但是,如果引擎认为“好的,一些JSON”,则所有内容都将作为JSON处理,如果该JSON无效,则会中断。
对于FOR XML PATH
,使用namig列有一些技巧(例如,[*]
,[node()]
甚至在一个查询中是同一查询的两倍),但是FOR JSON PATH
并不那么强大...
答案 1 :(得分:1)
当您说语句“ ...始终将结果放入字符串中。” 时,您可能意味着当JSON
存储在文本列中时,{{1} }对此文本进行转义。当然,如果要返回未转义的FOR JSON
文本,则只需要对有效的JSON
文本使用JSON_QUERY
函数。
接下来是一个小变通方法(基于JSON
和字符串操作),可能有助于解决您的问题。
表格:
FOR JSON
声明:
CREATE TABLE #Data (
Arguments nvarchar(max)
)
INSERT INTO #Data
(Arguments)
VALUES
('{"a": "b"}'),
('Some text'),
('{"c": "d"}'),
('{"e": "f"}'),
('More[]text')
输出:
SELECT CONCAT(N'[', j1.JsonOutput, N',', j2.JsonOutput, N']')
FROM
(
SELECT JSON_QUERY(Arguments) AS Results
FROM #Data
WHERE ISJSON(Arguments) = 1
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j1 (JsonOutput),
(
SELECT STRING_ESCAPE(ISNULL(Arguments, ''), 'json') AS Results
FROM #Data
WHERE ISJSON(Arguments) = 0
FOR JSON PATH, WITHOUT_ARRAY_WRAPPER
) j2 (JsonOutput)
注意:
这里的一个缺点是生成的输出中项目的顺序与表中的顺序不同。