向已有 select_from() 的 SQL Alchemy 表达式添加连接

Adding a join to an SQL Alchemy expression that already has a select_from()

注意:这是关于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: Can't find any foreign key relationships between 'Select object' and '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

编辑:添加 JOIN 必须在创建初始查询表达式 q 之后。我的想法是创建一个基本的查询框架,然后遍历用户请求的所有连接并将它们添加到查询中。

这可以在 SQL Alchemy 中完成吗?

第一个错误 (NoForeignKeysError) 表示您的 table 缺少外键定义。如果您不想手动编写连接子句,请修复此问题:

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 表达式语言中的连接工作方式与您的预期略有不同。您需要在加入所有 table 的地方创建 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 对象被视为您要求连接到另一个 table 的 table(本质上是) .

您可以使用 froms 属性访问查询的当前 select_from,然后将其与另一个 table 连接并更新 select_from.

如文档中所述,调用 select_from 通常会将另一个选择 table 添加到 FROM 列表中,但是:

Passing a Join that refers to an already present Table or other selectable will have the effect of concealing the presence of that selectable as an individual element in the rendered FROM list, instead rendering it into a JOIN clause.

因此您可以像这样添加一个连接,例如:

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)
)