繁体   English   中英

SQLAlchemy 查询将相关数据的伪列添加为字典数组

[英]SQLAlchemy query adding pseudo-column of related data as an array of dicts

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

假设我们有两个表: itemslinks 每个项目都有一个 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          

因此,例如汽车自行车通过颜色相关。

我正在寻找用于数据库查询的 SQLAlchemy 代码提取,以返回所有项目以及包含每个元组作为结构数组的关系数据的额外派生伪列

 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 中实现?

经过 SQLalchemy 文档和许多网站的漫长旅程,我在这里找到了基于相关子查询的解决方案:

我们可以使用 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)
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM