【问题标题】:Is there a way to return either a string or embedded JSON using FOR JSON?有没有办法使用 FOR JSON 返回字符串或嵌入的 JSON?
【发布时间】:2019-06-10 22:54:54
【问题描述】:

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

【问题讨论】:

  • 你有样本数据吗?这会很有帮助
  • 您的 SQL Server 版本也很重要。 2016 年及以上版本提供了许多 json 功能。它可以在几乎任何版本的 SQL 中完成(它只是字符数据),但不同版本的答案会有所不同。
  • 样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this.

标签: sql-server tsql for-json


【解决方案1】:

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

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

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

【讨论】:

  • 非常有趣的方法,+1。
【解决方案2】:

当你说你的语句“...总是将结果放入一个字符串中。”,你可能的意思是当JSON 存储在一个文本列中时,FOR JSON 转义了这个文本.当然,如果你想返回一个未转义的JSON文本,你只需要对你有效的JSON文本使用JSON_QUERY函数。

接下来是一个小解决方法(基于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"}]

注意事项:

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

【讨论】:

  • 聪明的解决方法,谢谢!可惜 SQL Server 没有办法更干净地处理这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
  • 2021-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多