【问题标题】:Converting JSON with SQL - object and string for same property使用 SQL 转换 JSON - 相同属性的对象和字符串
【发布时间】:2022-01-12 03:32:45
【问题描述】:

我在使用 SQL Server 将 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"
        }
    }
]

我发现的挑战在于将字符串和对象组合为输出中的“答案”属性。

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

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

在图像发挥作用之前,我最初的方法是构建一个具有不同层“标签值”对的临时表,然后将该表转换为带有一系列嵌套“for json path”语句的 json。

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

【问题讨论】:

  • 根据问题指南,请展示您的尝试并告诉我们您发现了什么(在本网站或其他地方)以及为什么它不能满足您的需求。

标签: arrays json sql-server data-conversion


【解决方案1】:

默认情况下,FOR JSON 子句使用 \ 转义 JSON 输出中的特殊字符,通常您可以通过使用 JSON_QUERY() 来避免这种情况(如文档中所述 ...JSON_QUERY 返回一个有效的 JSON 片段。因此,FOR JSON 不会转义 JSON_QUERY 返回值中的特殊字符)。

如您所知,这里的问题是 JSON 的 $."values" 部分包含一个字符串和一个对象。此问题的一个可能解决方案是生成一个包含两个同名列的表并应用FOR JSON AUTO 子句。 FOR JSON AUTO 的输出由SELECT 子句中的列顺序和SELECT 子句中引用的表的组合决定,所以我不确定这个输出是否是“设计使然”或者只是一个有用的副作用。当然,如果您包含 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"
      }
   }
]

【讨论】:

  • 非常感谢@Zhorov。我不知道 JSON AUTO 允许具有相同别名的多个表达式。 JSON PATH 不接受它,但我可以解决这个要求。
【解决方案2】:

试试这个。在 Visual Studio 中测试过

    var jArray = JArray.Parse(json);

    foreach (var jObject in jArray)
    {
        var data = new Data { Label = jObject["label"].ToString() };    
        var result = new List<Data>();

        foreach (var jArr in (JArray)jObject["values"])
        {
            if (jArr.GetType().Name.ToString() == "JValue") data.ShortAnswer = ((JValue)jArr).ToString();
            else
            {
            if (data.Answer == null) data.Answer = new List<Answer>();
            data.Answer.Add(jArr.ToObject<Answer>());
            }
        }
        result.Add(data);
   }

结果

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

public partial class Data
{
    [JsonProperty("label")]
    public string Label { get; set; }

    [JsonProperty("answer")]
    public List<Answer> Answer { get; set; }

    [JsonProperty("shortAnswer")]
    public string ShortAnswer { get; set; }
}

public partial class Answer
{
    [JsonProperty("filename")]
    public string Filename { get; set; }

    [JsonProperty("contentType")]
    public string ContentType { get; set; }

    [JsonProperty("bytes")]
    public string Bytes { get; set; }
}

【讨论】:

  • 谢谢,Serge,但我一直在寻找 SQL Server 解决方案。由于整个设置都在 SQL Server 中,我真的非常非常想避免切换技术......
  • @WouterDeRaeve 这不是关于 Json,而是关于你将如何使用它。 Json 没用,只能在服务器之间移动数据。要使用它需要反序列化。我已经反序列化了现有的 json,它可以使用了。但是你将不得不再次反序列化另一个 json。
猜你喜欢
  • 2015-04-14
  • 1970-01-01
  • 1970-01-01
  • 2012-10-27
  • 2020-01-30
  • 1970-01-01
  • 2018-05-03
  • 2018-03-13
  • 1970-01-01
相关资源
最近更新 更多