使用 union 命令为 JSON 个嵌套节点转义

Escaped for JSON nested nodes using union command

在存储过程中我有一个 for json 节点(框):

select
(
    select
        os.Name,
        os.Address,
        ss.carrierCode,
        (
            select 
                ob.envelopeCode, 
                ob.boxNumber,
                ob.weight,
                ob.width,
                ob.length,
                ob.height  
            from OrdersBoxes ob
            ...
            where os.OID=ob.OID 
            ...
            for json path 
        ) boxes,
        ....
        for json path
) orderDetails

这样我正确得到:

"boxes":[{
            "envelopeCode":"E70345D2AB90A879D4F53506FB465086",
            "boxNumber":1,
            "weight":3000,
            "width":300,
            "length":300,
            "height":100
        }]

现在我需要从 2 table 中获取详细信息,因此我将使用 union 命令,将 2 select 包装在另一个 select 查询中以避免以下错误:

The FOR XML and FOR JSON clauses are invalid in views, inline functions, derived tables, and subqueries when they contain a set operator. To work around, wrap the SELECT containing a set operator using derived table or common table expression or view and apply FOR XML or FOR JSON on top of it.

并添加JSON_QUERY以避免获得转义的嵌套节点:

select
(
    select 
        * 
    from 
    (
        select
            os.Name,
            os.Address,
            ss.carrierCode,
            JSON_QUERY((
                select 
                    ob.envelopeCode, 
                    ob.boxNumber,
                    ob.weight,
                    ob.width,
                    ob.length,
                    ob.height  
                from OrdersBoxes ob
                ...
                where os.OID=ob.OID 
                ...
                for json path 
            )) boxes,
            ....
            from table1
            where....
        
        union
        
        select
            os.Name,
            os.Address,
            ss.carrierCode,
            JSON_QUERY((
                select 
                    ob.envelopeCode, 
                    ob.boxNumber,
                    ob.weight,
                    ob.width,
                    ob.length,
                    ob.height  
                from OrdersBoxes ob
                ...
                where os.OID=ob.OID 
                ...
                for json path 
            )) boxes,
            ....
            from table2
            where....
    ) jj
    for json path
) orderDetails

有效,但返回的框节点已转义:

"boxes":"[{\"envelopeCode\":\"E70345D2AB90A879D4F53506FB465086\",\"boxNumber\":1,\"weight\":3000,\"width\":300,\"length\":300,\"height\":100}]"

我也试过这个 Solution 但它只有在从 1 table:

返回数据时才能正常工作

因为它 returns objects {} 得到一个数组需要改变第一行

select STRING_AGG (order_details,',') ods from (

select concat('[',STRING_AGG (order_details,','),']') ods from (

虽然有效,但我似乎不是很“优雅”。

有人可以建议一种更好的方法来正确格式化所有数据(因此未转义框节点)吗?

关于 JSON_QUERY() explains 的文档:... JSON_QUERY return 是一个有效的 JSON 片段。因此,FOR JSON 不会转义 JSON_QUERY return 值中的特殊字符。如果您 return 使用 FOR JSON 计算结果,并且您要包括已经采用 JSON 格式的数据(在列中或作为表达式的结果),请将 JSON 数据 JSON_QUERY 没有路径参数。。所以,如果我正确理解架构,你需要以不同的方式使用 JSON_QUERY()

表:

SELECT *
INTO table1
FROM (VALUES
   (1, 'Name1', 'Address1')
) v (oid, name, address)
SELECT *
INTO table2
FROM (VALUES
   (2, 'Name2', 'Address2')
) v (oid, name, address)
SELECT *
INTO OrdersBoxes 
FROM (VALUES
   (1, 'E70345D2AB90A879D4F53506FB465086', 1, 3000, 300, 300, 100),
   (2, 'e70345D2AB90A879D4F53506FB465086', 2, 3000, 300, 300, 100)
) v (oid, envelopeCode, boxNumber, weight, width, length, height)

声明:

select Name, Address, JSON_QUERY(boxes) AS Boxes
from (
   select
      os.Name,
      os.Address,
      (
      select ob.envelopeCode, ob.boxNumber, ob.weight, ob.width, ob.length, ob.height  
      from OrdersBoxes ob
      where os.OID = ob.OID 
      for json path 
      ) boxes
   from table1 os
   union all
   select
      os.Name,
      os.Address,
      (
      select ob.envelopeCode, ob.boxNumber, ob.weight, ob.width, ob.length, ob.height   
      from OrdersBoxes ob
      where os.OID = ob.OID 
      for json path 
      ) boxes
   from table2 os
) j
for json path

作为附加选项,您可以尝试使用 FOR JSON AUTO(JSON 输出的格式是根据 SELECT 列表中列的顺序及其对应的顺序自动确定的源表):

SELECT 
   cte.Name, cte.Address, 
   boxes.envelopeCode, boxes.boxNumber, boxes.weight, boxes.width, boxes.length, boxes.height
FROM (
   SELECT oid, name, address FROM table1
   UNION ALL
   SELECT oid, name, address FROM table2
) cte
JOIN OrdersBoxes boxes ON cte.oid = boxes.oid
FOR JSON AUTO

结果:

[
   {
   "Name":"Name1",
   "Address":"Address1",
   "boxes":[{"envelopeCode":"E70345D2AB90A879D4F53506FB465086","boxNumber":1,"weight":3000,"width":300,"length":300,"height":100}]
   },
   {
   "Name":"Name2",
   "Address":"Address2",
   "boxes":[{"envelopeCode":"e70345D2AB90A879D4F53506FB465086","boxNumber":2,"weight":3000,"width":300,"length":300,"height":100}]
   }
]