【问题标题】:How to load a JSON file into Postgres with all of its keys?如何将 JSON 文件及其所有密钥加载到 Postgres 中?
【发布时间】:2020-12-14 16:41:11
【问题描述】:

我有一个 XML 文件,该文件已分解为较小的表。我可以将它们加载到 Navicat,除了一张表。 这是 XML 结构:

<Food> 
  <Id> 100 </Id>
  <Type> Meat </Type>
  <Expiry Date>
    <Chicken>
      2020/12/20
    </Chicken>
    <Beef>
      2020/12/25
    </Beef>
  </Expiry Date>
</Food>

<Food>
  <Id> 200 </Id>
  <Type> Vegetables </Type>
  <Nutrition> B1 </Nutrition>
</Food>

我已经把它变成了 JSON,在 Python 中使用 xmltodict:

[{
"Id": "100",
"Type": "Meat",
"Expiry Date": {
  "Chicken": "2020/12/20",
  "Beef": "2020/12/25"
  }
},

{
"Id": "200",
"Type": "Vegetables",
"Nutrition": "B1"
}]

但是,当我将此 JSON 文件加载到 Navicat(PostgresSQL 连接)时,SQL 表架构只有 Id、Type 和 Expiry Date。如您所见,一个对象中缺少键,但出现在其他对象中。如何创建一个包含 JSON 文件中所有字段的 SQL 表? (ID、类型、有效期和营养)。

【问题讨论】:

  • 在客户端解析 JSON 并向数据库发出适当的 INSERT 语句。或者,使用json_array_elements-&gt;&gt; 运算符在数据库中执行此操作。

标签: sql json postgresql navicat


【解决方案1】:

如果您没有特殊原因首先将其转换为 JSON,那么您可以将 XMLTABLE 与“原始”嵌入式 XML 一起使用,如下所示:

select * 
from xmltable ( '//Food' passing 
    xmlparse (document '<dummyRoot>
    <Food> 
      <Id> 100 </Id>
      <Type> Meat </Type>
      <ExpiryDate>
        <Chicken>
          2020/12/20
        </Chicken>
        <Beef>
          2020/12/25
        </Beef>
      </ExpiryDate>
    </Food>
    <Food>
      <Id> 200 </Id>
      <Type> Vegetables </Type>
      <Nutrition> B1 </Nutrition>
    </Food>
    </dummyRoot>')
  columns 
   "Id" integer,
   "Type" text, 
   "ExpiryDate.Chicken" date path 'ExpiryDate/Chicken',
   "ExpiryDate.Beef" date path 'ExpiryDate/Beef',
   "Nutrition" text
);

Date> 需要分别更改为 才能成为有效的标签名称。结果如下:

Id |Type        |ExpiryDate.Chicken|ExpiryDate.Beef|Nutrition|
---|------------|------------------|---------------|---------|
100| Meat       |        2020-12-20|     2020-12-25|         |
200| Vegetables |                  |               | B1      |

编辑简化的 XML 查询

如果需要 JSON ,那么按照 Laurenz Albe 的建议:

select 
    (j->>'Id')::integer id, 
    j->>'Type' "type", 
    (j->'Expiry Date'->>'Chicken')::date xdate_chicken, 
    (j->'Expiry Date'->>'Beef')::date xdate_beef,
    j->>'Nutrition' nutrition
from jsonb_array_elements
('[{
"Id": "100",
"Type": "Meat",
"Expiry Date": {
  "Chicken": "2020/12/20",
  "Beef": "2020/12/25"
  }
},
{
"Id": "200",
"Type": "Vegetables",
"Nutrition": "B1"
}]') j;

【讨论】:

  • 非常感谢。然而,XML 文件的元素比这多得多,并且到期日期内的节点也更多且不可预测。此外,还有 5 个以上类似于 Expiry Date 的元素。如何在不必手动列出所有列的情况下实现相同的目标?
  • 好吧,恐怕我不知道。但是,您可以使用json_object_keys 提取元素名称列表,然后使用文本编辑器进行一些操作,以便更轻松地列出所有列,而不会出现(或更少?)错误。
  • 顺便说一句,如果Expiry Date 的结构是动态的,那么为什么不将它作为表中的 JSON(B) 列呢?这可能不是最方便使用的东西,但可能是最好的,至少您不会丢失数据。
  • 哦,这正是我几分钟前刚想出来的,哈哈哈。但是,如果我只是将确切的 JSON 文件加载到 Postgres 中,我将拥有 jsonb 类型但会丢失 Nutrition 字段。
  • 那么,为什么不用混合结构、常规列(如 id、type、营养)和 JSON 中的结构化列(如 expiry_date,...)?这将为您提供两全其美的优势,即键和细节。
【解决方案2】:

我已经找到了解决方案。使用 Python,我通读 XML 文件以获取所有可能的列名,然后在每个列名中,我读入它的子元素并将其写入 Postgres 中的 jsonb。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-04
    • 2021-11-15
    • 2016-01-12
    • 2013-11-07
    • 1970-01-01
    • 2010-09-18
    • 2016-05-10
    • 2016-06-26
    相关资源
    最近更新 更多