[英]SQLAlchemy query adding pseudo-column of related data as an array of dicts
以下内容涉及用 Python 编写并使用 SQLAlchemy 与 postgres (v9.5) 关系数据库接口的 Web 应用程序后端。
假设我们有两个表: items和links 。 每个项目都有一个 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.