将 JSON 转换为 SQL - 相同 属性 的对象和字符串

Converting JSON with SQL - object and string for same property

我在使用 SQL 服务器将 JSON 数组转换为不同的输出格式时遇到了挑战...

输入:

[
    {
        "label": "City",
        "values": [
            "Test City"
        ]
    },
    {
        "label": "imgTest",
        "values": [
            {
                "identifier": "56696553-48F4-4BC5-BB43-FF4F71743EE9",
                "filename": "file1.jpg",
                "contentType": "image/jpg",
                "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
            },
            {
                "identifier": "2D9106D7-71A1-440E-8255-679E8905B32E",
                "filename": "file2.jpg",
                "contentType": "image/jpg",
                "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
            }
        ]
    }
]

期望的输出:

[
    {
        "label": "City",
        "answer": "Test City"
    },
    {
        "label": "imgTest",
        "answer": {
            "filename": "file1.jpg",
            "contentType": "image/jpg",
            "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
        }
    },
    {
        "label": "imgTest",
        "answer": {
            "filename": "file2.jpg",
            "contentType": "image/jpg",
            "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
        }
    }
]

我发现的挑战在于将字符串和对象组合为输出中的 'answer'-属性。

请注意,这只是非常嵌套的 JSON 输入的一小部分。谢谢。 临时 tables 等是完全可能的,因为这很可能通过存储过程发生

我提到 SQL 的原因是因为这是我最熟悉的技术,并且过去已成功用于这些目的。

在图像开始播放之前,我最初的方法是构建一个具有不同层的 'label-values' 对的临时 table,然后将此 table 变成 json 和一系列嵌套的 'for json path' 语句。

但是,当我对图像数据执行此操作时,它假定内容是字符串,因此它会转义字符,这在将输出发送到下一个应用程序时会导致问题...

默认情况下,FOR JSON 子句使用 \ 转义 JSON 输出中的特殊字符,通常您可以使用 JSON_QUERY() 来避免这种情况(如解释在文档中 ...JSON_QUERY returns 是一个有效的 JSON 片段。因此,FOR JSON 不会转义 [= 中的特殊字符34=] return 值).

如您所知,这里的问题是 JSON 的 $."values" 部分包含一个字符串和一个对象。此问题的可能解决方案是生成一个包含两个同名列的 table 并应用 FOR JSON AUTO 子句。 FOR JSON AUTO 的输出由 SELECT 子句中列的顺序和 SELECT 子句中引用的 table 的组合决定,所以我'我不确定此输出是“设计使然”还是只是有用的副作用。当然,如果您包含 INCLUDE_NULL_VALUES 选项,结果将包含两列的值。

JSON:

DECLARE @json nvarchar(max) = N'
[
    {
        "label": "City",
        "values": [
            "Test City"
        ]
    },
    {
        "label": "imgTest",
        "values": [
            {
                "identifier": "56696553-48F4-4BC5-BB43-FF4F71743EE9",
                "filename": "file1.jpg",
                "contentType": "image/jpg",
                "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
            },
            {
                "identifier": "2D9106D7-71A1-440E-8255-679E8905B32E",
                "filename": "file2.jpg",
                "contentType": "image/jpg",
                "bytes": "iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
            }
        ]
    }
]'

T-SQL:

SELECT 
   [label], 
   CASE WHEN ISJSON([value]) = 0 THEN [value] END AS [answer],
   JSON_QUERY(CASE WHEN ISJSON([value]) = 1 THEN [value] END) AS [answer]
FROM (
   SELECT j1.[label], j2.[value]
   FROM OPENJSON(@json) WITH (
      [label] nvarchar(100) '$.label',
      [values] nvarchar(max) '$.values' AS JSON
   ) j1
   OUTER APPLY OPENJSON(j1.[values]) j2
) t   
FOR JSON AUTO, INCLUDE_NULL_VALUES 

结果:

[
   {
      "label":"City",
      "answer":"Test City"
   },
   {
      "label":"imgTest",
      "answer":{
         "identifier":"56696553-48F4-4BC5-BB43-FF4F71743EE9",
         "filename":"file1.jpg",
         "contentType":"image/jpg",
         "bytes":"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
      }
   },
   {
      "label":"imgTest",
      "answer":{
         "identifier":"2D9106D7-71A1-440E-8255-679E8905B32E",
         "filename":"file2.jpg",
         "contentType":"image/jpg",
         "bytes":"iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII"
      }
   }
]