将连接添加到已具有select_from()的SQL Alchemy表达式

Mig*_*ell 5 python sql sqlalchemy

注意:这是关于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
Run Code Online (Sandbox Code Playgroud)
SELECT bmt_gene.id 
FROM bmt_gene 
WHERE bmt_gene.ensembl_id = %s
Run Code Online (Sandbox Code Playgroud)

但是,如果您尝试以相同的方式添加JOIN,您将获得异常:

q = select([bmt_gene.c.id]).select_from(bmt_gene)
q = q.join(bmt_gene_name)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)
(SELECT bmt_gene.id AS id FROM bmt_gene)
JOIN bmt_gene_name ON id = bmt_gene_name.gene_id
Run Code Online (Sandbox Code Playgroud)

但我真正想要的是:

SELECT
     bmt_gene.id AS id 
FROM
     bmt_gene
     JOIN bmt_gene_name ON id = bmt_gene_name.gene_id
Run Code Online (Sandbox Code Playgroud)

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

这可以在SQL Alchemy中完成吗?

Aud*_*kas 6

第一个错误(NoForeignKeysError)意味着您的表缺少外键定义.如果您不想手动编写join子句,请修复此问题:

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')),
    # ...
)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

您在连接中看到子查询的原因是该Select对象被视为一个表(实质上就是它),您要求它连接到另一个表.


bri*_*ssy 5

select_from您可以使用属性访问当前查询froms,然后将其与另一个表连接并更新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)
)
Run Code Online (Sandbox Code Playgroud)