向已有 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 表达式添加连接的主要内容,如果未能解决你的问题,请参考以下文章

T_SQL 语句想已有数据表添加约束

Sql Server 强制断开数据库已有连接的方法

SQL server 管理表数据

elementUi 怎么向已有数据表格添加数据

sql文件执行失败已有主键

为某些语法提供警告