【问题标题】:SQLAlchemy query adding pseudo-column of related data as an array of dictsSQLAlchemy 查询将相关数据的伪列添加为字典数组
【发布时间】:2020-10-16 15:23:18
【问题描述】:

以下内容涉及用 python 编写并使用 SQLAlchemy 连接到 postgres (v9.5) 关系数据库的 Web 应用程序后端。

假设我们有两个表:itemsrelations。每个项目都有一个 ID,并且可能与多个其他项目相关。此类关系被持久化在关系表中,该表存储了它自己的 ID、两个相关项的 ID 以及关系的名称。

这是一些示例数据:

     items:                               relations:

  id      name                id     item1_id  item2_id    name
---------------              ----------------------------------
  1       car                  1        1         2       weight
  2       boat                 2        1         3       colour
  3       bike                 3        1         4        age
  4       jet-pack             4        5         1        age
  5       plane
  6       rocket          

因此,例如 carbike 是通过颜色相关的。

我正在寻找用于数据库查询的 SQLAlchemy 代码提取,以返回所有 items 以及额外的 derived-pseudo-column包含每个元组的关系数据作为结构数组:

 id       name                                 relations
---------------------------------------------------------------------------------
  1       car            [ { 2, weight }, { 3, colour }, { 4, age }, { 5, age } ]
  2       boat           [ { 1, weight } ]
  3       bike           [ { 1, colour } ]
  4       jet-pack       [ { 1, age } ]
  5       plane          [ { 1, age } ]
  6       rocket         []

一个好的第一步是在尝试转换为 SQLAlchemy 之前生成 SQL 查询。最接近我已经实现的上述目标:

SELECT i.*, 
  (SELECT array_agg(row(CASE WHEN r.item1_id=i.id THEN r.item2_id ELSE r.item1_id END, i.name)) 
   AS relations from relations r 
   WHERE r.item1_id=i.id OR r.item2_id=i.id) 
FROM items i ;

但更好一点的是将关系实际输出为 json:

SELECT i.*,
  (SELECT jsonb_agg(jsonb_build_object('item', CASE WHEN r.item1_id=i.id THEN r.item2_id ELSE r.item1_id END, 'relation', r.name))     
     AS relations
     FROM relations r   
     WHERE r.item1_id=i.id OR r.item2_id=i.id)
  FROM items i;

产生:

 id       name                                 relations
---------------------------------------------------------------------------------
  1       car            [ { "item": 2, "relation": "weight" }, { "item": 3, "relation": "colour" }, { "item": 4, "relation": "age" }, { "item": 5, "relation": "age" } ]
  2       boat           [ { "item": 1, "relation": "weight" } ]
  3       bike           [ { "item": 1, "relation": "colour" } ]
  4       jet-pack       [ { "item": 1, "relation": "age" } ]
  5       plane          [ { "item": 1, "relation": "age" } ]
  6       rocket         []

如何在 sqlalchemy 中实现这个子查询?

【问题讨论】:

    标签: python python-3.x postgresql sqlalchemy postgresql-9.5


    【解决方案1】:

    在浏览了 SQLalchemy 文档和许多网站之后,我在这里找到了一个基于相关子查询的解决方案:

    Can we make correlated queries with SQLAlchemy - 答案 #1。

    如下调整会产生我想要的结果:

    from sqlalchemy import select, func, table, Column, Integer, Text, case
    from sqlalchemy.sql.expression import or_
    
    
    items     = table('items',     Column('id', Integer), 
                                   Column('name', Text))
    
    relations = table('relations', Column('id', Integer), 
                                   Column('item1_id', Integer), 
                                   Column('item2_id', Integer), 
                                   Column('name', Text))
    
    
    subquery = select( [ func.jsonb_agg(
                           func.jsonb_build_object(
                             'item', case( [ ( relations.c.item1_id == items.c.id, relations.c.item2_id ) ],
                                           else_ = relations.c.item1_id),
                             'relation', relations.c.name
                           )
                         )
                       ]
                     ).where(or_(relations.c.item1_id == items.c.id, relations.c.item2_id == items.c.id) \
                     .correlate(items)
    
    query = (
        select([items.*, subquery.label('relations')]).select_from(items)
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      • 2021-07-14
      • 2017-05-26
      • 2016-01-01
      • 1970-01-01
      相关资源
      最近更新 更多