向已有 select_from() 的 SQL Alchemy 表达式添加连接
Posted
技术标签:
【中文标题】向已有 select_from() 的 SQL Alchemy 表达式添加连接【英文标题】:Adding a join to an SQL Alchemy expression that already has a select_from() 【发布时间】:2015-02-03 04:50:40 【问题描述】:注意:这是关于 SQL Alchemy 的表达式语言而不是 ORM 的问题
SQL Alchemy 可以很好地向现有查询添加 WHERE 或 HAVING 子句:
q = select([bmt_gene.c.id]).select_from(bmt_gene)
q = q.where(bmt_gene.c.ensembl_id == "ENSG00000000457")
print q
SELECT bmt_gene.id FROM bmt_gene WHERE bmt_gene.ensembl_id = %s
但是,如果您尝试以相同的方式添加 JOIN,则会出现异常:
q = select([bmt_gene.c.id]).select_from(bmt_gene)
q = q.join(bmt_gene_name)
sqlalchemy.exc.NoForeignKeysError:在“选择对象”和“bmt_gene_name”之间找不到任何外键关系
如果您指定列,它会创建一个子查询(无论如何这都是不完整的 SQL):
q = select([bmt_gene.c.id]).select_from(bmt_gene)
q = q.join(bmt_gene_name, q.c.id == bmt_gene_name.c.gene_id)
(SELECT bmt_gene.id AS id FROM bmt_gene) JOIN bmt_gene_name ON id = bmt_gene_name.gene_id
但我真正想要的是:
SELECT
bmt_gene.id AS id
FROM
bmt_gene
JOIN bmt_gene_name ON id = bmt_gene_name.gene_id
edit:添加 JOIN 必须在创建初始查询表达式 q 之后。我的想法是创建一个基本的查询框架,然后遍历用户请求的所有连接并将它们添加到查询中。
这可以在 SQL Alchemy 中完成吗?
【问题讨论】:
【参考方案1】:第一个错误 (NoForeignKeysError
) 表示您的表缺少外键定义。如果您不想手动编写连接子句,请修复此问题:
from sqlalchemy.types import Integer
from sqlalchemy.schema import MetaData, Table, Column, ForeignKey
meta = MetaData()
bmt_gene_name = Table(
'bmt_gene_name', meta,
Column('id', Integer, primary_key=True),
Column('gene_id', Integer, ForeignKey('bmt_gene.id')),
# ...
)
SQLAlchemy 表达式语言中的连接工作与您所期望的略有不同。您需要创建Join
对象,在其中加入所有表,然后才将其提供给Select
对象:
q = select([bmt_gene.c.id])
q = q.where(bmt_gene.c.ensembl_id == 'ENSG00000000457')
j = bmt_gene # Initial table to join.
table_list = [bmt_gene_name, some_other_table, ...]
for table in table_list:
j = j.join(table)
q = q.select_from(j)
您在联接中看到子查询的原因是 Select
对象被视为您要求联接到另一个表的表(本质上就是这样)。
【讨论】:
呃,这太糟糕了。我希望 sqlalchemy 连接组合更像 sqlkorma。在其中,您可以继续向查询添加连接。这真的是唯一的方法吗?【参考方案2】:您可以使用froms
属性访问查询的当前select_from
,然后将其与另一个表连接并更新select_from
。
如文档中所述,调用 select_from
通常会在 FROM 列表中添加另一个可选择项,但是:
传递引用已经存在的 Table 或其他可选择项的 Join 将具有隐藏该可选择项作为呈现的 FROM 列表中的单个元素的存在的效果,而不是将其呈现为 JOIN 子句。
所以你可以像这样添加一个连接,例如:
q = select([bmt_gene.c.id]).select_from(bmt_gene)
q = q.select_from(
join(q.froms[0], bmt_gene_name,
bmt_gene.c.id == bmt_gene_name.c.gene_id)
)
【讨论】:
以上是关于向已有 select_from() 的 SQL Alchemy 表达式添加连接的主要内容,如果未能解决你的问题,请参考以下文章