如何将不同值的JSON文件导入SQL表?

r6vfmomb  于 2023-10-21  发布在  其他
关注(0)|答案(1)|浏览(171)

我每天都会生成一个JSON文件。根据源数据的不同,它可以有不同的结构(每个JSON文件中的属性可能更多或更少)。举例来说:文件% 1具有属性:productCode、productType、sellerName、sellerCountry文件2具有所有上述属性,加上sellerState,下一个文件的属性可能比文件2更多或更少
如何将这种JSON文件动态地扁平化为SQL表?
文件1:

[
  {
    "productCode": "00001",
    "productType": "Food",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "UK"
      }
    ]
  },
  {
    "productCode": "00002",
    "productType": "Clothing"
  }
]

文件2:

[
  {
    "productCode": "00001",
    "productType": "Food",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "UK"
      }
    ]
  },
  {
    "productCode": "00002",
    "productType": "Clothing"
  },
  {
    "productCode": "00003",
    "productType": "Toy",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "AUS",
        "sellerState": "VIC"
      }
    ]
  }
]
1aaf6o9v

1aaf6o9v1#

可以使用动态SQL生成来动态地执行此操作,但在大多数情况下这不是必需的。
在JSON文件中,如果单个实体的值为null,则通常会排除它们的属性。这意味着,尽管输出看起来像是 * 动态的 *,但生成这些文件的系统通常符合标准模式。在这种情况下,有一个最大的结构是可能的,但如果你不知道这个模式,你可以通过比较文件来确定它。
一旦你有了一个固定的模式,我们就可以根据这个模式读取所有文件,缺失的属性将被导入一个null值。
这个输入中的一个复杂因素是sellerDetails是一个嵌套数组,在SQL中这是一个新的维度或 table,所以我们需要连接提取根元素属性的结果,这将使数据变平。
这在How to use OPENJSON on multiple rows中进行了描述
因此,让我们定义最大模式,假设sellerDetails具有3个属性:sellerNamesellerCountrysellerState。如果您标识了更多的字段,请将它们添加到WITH声明中。
这个小提琴演示了MS SQL Server中的解决方案:http://sqlfiddle.com/#!18/7d5fd/2
我已经将两个输入合并到同一个结果集中,以便您可以比较输出

SELECT DISTINCT product.ProductCode, product.productType, seller.*
FROM
(
  SELECT @json1 as json
  UNION 
  SELECT @json2
) input
CROSS APPLY OPENJSON (json)
WITH (
    productCode varchar(10), 
    productType varchar(50), 
    sellerDetails NVARCHAR(MAX) as JSON
) product
OUTER APPLY OPENJSON (product.sellerDetails) 
WITH (
  sellerName varchar(50),
  sellerCountry varchar(50),
  sellerState varchar(50)
) seller

| productCode| productType|卖家名称|卖家国家|sellerState|
| --|--|--|--|--|
| 00001 |食品|中远|英国|NULL|
| 00002 |服装|NULL| NULL| NULL|
| 00003 |玩具|中远|AUS|维克|
请注意,代码忽略了第一个文件中缺少的sellerState,并注入了NULL

更新:

感谢@Charlieface指出我们应该考虑使用OUTER APPLY OPENJSON (product.sellerDetails)进行嵌套的OPENJSON调用。CROSS APPLY的行为类似于INNER JOIN,因此在这里使用cross apply会导致删除没有 * 任何 * sellerDetails记录的product记录,如本例中的'Clothing'。
DISTINCT也被添加到这个查询中以删除重复的条目,例如产品00002 Clothing出现在两个文件中。
以下是变量声明:

DECLARE @json1 varchar(max) = '[
  {
    "productCode": "00001",
    "productType": "Food",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "UK"
      }
    ]
  },
  {
    "productCode": "00002",
    "productType": "Clothing"
  }
]
';
DECLARE @json2 varchar(max) = '[
  {
    "productCode": "00001",
    "productType": "Food",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "UK"
      }
    ]
  },
  {
    "productCode": "00002",
    "productType": "Clothing"
  },
  {
    "productCode": "00003",
    "productType": "Toy",
    "sellerDetails": [
      {
        "sellerName": "Cosco",
        "sellerCountry": "AUS",
        "sellerState": "VIC"
      }
    ]
  }
]
';

相关问题