2

我有一个 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 都可以。我什至很高兴知道它即将推出测试版或其他版本。

4

2 回答 2

2

我没有找到一个好的解决方案,如果有人提出比这个 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 值,您将始终在最终结果中找到 eiterArgumentsArgumentsJSON。将此 JSON 视为 NVARCHAR(MAX) 您可以使用REPLACE将所有重命名为相同的Arguments.

问题似乎是,您不能在 SELECT 中包含两个具有相同名称的列,但每列必须具有可预测的类型。这取决于您在 CASE(或 COALESCE)中使用的顺序。如果引擎认为“好的,这里是文本”,所有内容都将被视为文本,并且您的 JSON 被转义。但是,如果引擎认为“好的,一些 JSON”,则所有内容都将作为 JSON 处理,并且如果此 JSON 无效,则会中断。

使用FOR XML PATH列 namig 有一些技巧(例如[*][node()]甚至在一个查询中两次相同),但FOR JSON PATH不是那么强大......

于 2019-06-11T06:50:42.607 回答
1

当您说您的陈述 “......总是将结果放入字符串中”时。,您可能的意思是当JSON存储在文本列中时,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)

输出:

[{"Results":{"a": "b"}},{"Results":{"c": "d"}},{"Results":{"e": "f"}},{"Results":"Some text"},{"Results":"More[]text"}]

笔记:

这里的一个缺点是生成的输出中项目的顺序与表中的不同。

于 2019-06-11T07:35:12.343 回答