有没有办法使用 FOR JSON return 字符串或嵌入 JSON?
Is there a way to return either a string or embedded JSON using FOR JSON?
我有一个 nvarchar 列,如果内容有效 JSON,我想将其 return 嵌入到我的 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
如果参数不包含 JSON 对象,则会发生运行时错误。
更新:示例数据:
Arguments
---------
{ "a": "b" }
Some text
更新:SQL 服务器的任何版本都可以。我什至很高兴知道它即将推出测试版或其他内容。
我没有找到好的解决方案,如果有人提出比这个 hack 更好的解决方案,我会很高兴:
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-values 被省略,您将始终在最终结果中找到 Arguments
或 ArgumentsJSON
。将此 JSON 视为 NVARCHAR(MAX) 您可以使用 REPLACE
将所有重命名为相同的 Arguments
.
问题似乎是,您不能在 SELECT 中包含两个同名的列,但每个列都必须具有可预测的类型。这取决于您在 CASE(或 COALESCE)中使用的顺序。如果引擎认为 "Okay, here's text",所有内容都将被视为文本,您的 JSON 将被转义。但是,如果引擎认为 "Okay, some JSON",所有内容都将作为 JSON 处理,如果此 JSON 无效,则会中断。
对于 FOR XML PATH
列 namig 有一些技巧(例如 [*]
、[node()]
甚至在一个查询中两次相同),但 FOR JSON PATH
不是那个强大...
当您说您的语句 "... 总是将结果放入字符串中。",您的意思可能是当 JSON
存储在文本列中时, FOR JSON
转义此文本。当然,如果你想 return 一个未转义的 JSON
文本,你只需要对有效的 JSON
文本使用 JSON_QUERY
函数。
接下来是一个小的解决方法(基于 FOR JSON
和字符串操作),可能有助于解决您的问题。
Table:
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)
输出:
[{"Results":{"a": "b"}},{"Results":{"c": "d"}},{"Results":{"e": "f"}},{"Results":"Some text"},{"Results":"More[]text"}]
备注:
此处的一个缺点是生成的输出中的项目顺序与 table 中的顺序不同。
我有一个 nvarchar 列,如果内容有效 JSON,我想将其 return 嵌入到我的 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
如果参数不包含 JSON 对象,则会发生运行时错误。
更新:示例数据:
Arguments
---------
{ "a": "b" }
Some text
更新:SQL 服务器的任何版本都可以。我什至很高兴知道它即将推出测试版或其他内容。
我没有找到好的解决方案,如果有人提出比这个 hack 更好的解决方案,我会很高兴:
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-values 被省略,您将始终在最终结果中找到 Arguments
或 ArgumentsJSON
。将此 JSON 视为 NVARCHAR(MAX) 您可以使用 REPLACE
将所有重命名为相同的 Arguments
.
问题似乎是,您不能在 SELECT 中包含两个同名的列,但每个列都必须具有可预测的类型。这取决于您在 CASE(或 COALESCE)中使用的顺序。如果引擎认为 "Okay, here's text",所有内容都将被视为文本,您的 JSON 将被转义。但是,如果引擎认为 "Okay, some JSON",所有内容都将作为 JSON 处理,如果此 JSON 无效,则会中断。
对于 FOR XML PATH
列 namig 有一些技巧(例如 [*]
、[node()]
甚至在一个查询中两次相同),但 FOR JSON PATH
不是那个强大...
当您说您的语句 "... 总是将结果放入字符串中。",您的意思可能是当 JSON
存储在文本列中时, FOR JSON
转义此文本。当然,如果你想 return 一个未转义的 JSON
文本,你只需要对有效的 JSON
文本使用 JSON_QUERY
函数。
接下来是一个小的解决方法(基于 FOR JSON
和字符串操作),可能有助于解决您的问题。
Table:
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)
输出:
[{"Results":{"a": "b"}},{"Results":{"c": "d"}},{"Results":{"e": "f"}},{"Results":"Some text"},{"Results":"More[]text"}]
备注:
此处的一个缺点是生成的输出中的项目顺序与 table 中的顺序不同。