SQL Server 2016 FOR JSON PATH returns 使用 case 语句时使用字符串而不是数组

SQL Server 2016 FOR JSON PATH returns string instead of array when using case statement

我正在尝试使用 SQL Server 2016 构建一个包含数组的 JSON 对象。

数组的源数据本身就是 JSON,所以我在 select 语句中使用 JSON_QUERY,并将 FOR JSON 子句应用于select 语句。

一切都很好,直到我将 JSON_QUERY 子句包装在 CASE 语句中(在某些情况下,不得包含数组,即必须为空)。

下面的代码说明了这个问题:

declare  @projects nvarchar(max) = '{"projects": [23439658267415,166584258534050]}'
declare @id bigint = 123

SELECT 
      [data.array1] = JSON_QUERY(@projects, '$.projects') -- returns an array - perfect.
    , [data.array2] = CASE WHEN 1 is NOT NULL 
                           THEN JSON_QUERY(@projects, '$.projects') 
                           ELSE NULL END -- returns an array - still good!
    , [data.array3] = CASE WHEN @id is NOT NULL
                           THEN JSON_QUERY(@projects, '$.projects') 
                           ELSE NULL END  -- why do I end up with a string in the JSON when I do this?
FOR JSON PATH, without_array_wrapper

此代码 return 如下 JSON:

{  
   "data":{  
      "array1": [23439658267415,166584258534050],
      "array2": [23439658267415,166584258534050],
      "array3":"[23439658267415,166584258534050]"
   }
}

问题是第三个 'array' 被 return 编辑为字符串对象。

我希望它 return 以下 JSON:

{  
   "data":{  
      "array1": [23439658267415,166584258534050],
      "array2": [23439658267415,166584258534050],
      "array3": [23439658267415,166584258534050]
   }
}

如果我删除 FOR JSON PATH... 子句,则查询 return 的所有列都是相同的(即 JSON_QUERY 函数 return 的所有三个 nvarchar 值都是相同)。

为什么会这样,如何让它在最后输出一个数组JSON?

在对 JSON_QUERY.

的调用中包装 case 语句的结果
, [data.array3] = JSON_QUERY(
                            CASE WHEN @id is NOT NULL
                            THEN JSON_QUERY(@projects, '$.projects') 
                            ELSE NULL END
                            )

根据documentationJSON_QUERY"Extracts an object or an array from a JSON string"。再往下写着 "Returns a JSON fragment of type nvarchar(max)."。有点乱。

对字符串值执行 for xml json 将在 returned JSON 字符串中为您提供一个字符串值,当您对 JSON 对象执行此操作时,您获取结果字符串值中内联的 JSON 对象。

您可以将 CASE 视为具有 return 值的函数调用,通过查看您从 CASE return 获取的值自动为您确定。由于 JSON_QUERY return 是一个字符串,因此大小写将是 return 一个字符串,并且 returned 值将是 JSON.

中的一个字符串值

查询计划中的 case 语句如下所示。

<ScalarOperator ScalarString="CASE WHEN [@id] IS NOT NULL THEN json_query([@projects],N'$.projects') ELSE NULL END">

当您将案例包装在对 JSON_QUERY 的调用中时,它看起来像这样。

<ScalarOperator ScalarString="json_query(CASE WHEN [@id] IS NOT NULL THEN json_query([@projects],N'$.projects') ELSE NULL END)">
  <Intrinsic FunctionName="json_query">

通过某种内部魔法 SQL 服务器将其识别为 JSON 对象而不是字符串,并将其作为 JSON 插入到生成的 JSON 字符串中取而代之的价值。

CASE WHEN 1 is NOT NULL 有效,因为 SQL 服务器足够聪明,可以看到 case 语句始终为真并被优化掉。