SQLAlchemy:在 MySQL 上使用自联接创建删除查询

Posted

技术标签:

【中文标题】SQLAlchemy:在 MySQL 上使用自联接创建删除查询【英文标题】:SQLAlchemy: Create delete query using self-join on MySQL 【发布时间】:2013-02-22 11:58:11 【问题描述】:

我正在尝试在 SQLAlchemy + mysql 中复制以下查询,但没有运气......

delete paths from paths
join paths as p1 on p1.ancestor = <ID>
where paths.descendant = p1.descendant;

SQLAlchemy 似乎忽略了我放入删除查询的任何连接。我也尝试使用子查询而不是连接,但这在 MySQL 中是不允许的(不能从要删除的同一个表中选择)。任何帮助将不胜感激。

更新: 是的,我正在尝试使用 ORM 层。这是我尝试过的查询:

p1 = aliased(Path, name="p1")
db.session.query(Path).join(
    p1, p1.ancestor==<ID>
)
.filter(
    Path.descendant==p1.Path.descendant
).delete()

还有子查询变体,但这在 MySQL 上不起作用,所以对我没用:

q = db.session.query(Path.descendant).filter(Path.ancestor==<ID>).subquery()
db.session.query(Path).filter(Path.descendant.in_(q)).delete(synchronize_session='fetch')

【问题讨论】:

你用的是orm层还是sql层?你能包括你试过的sn-p吗? ORM,但很乐意使用任何有助于我们实现查询的东西。我更新了我的问题,到目前为止我的尝试都失败了。 相关:***.com/questions/25395756/… 【参考方案1】:

SQLAlchemy 目前支持跨 Postgresql、MySQL 等的 UPDATE..FROM,但我们还没有尝试支持 DELETE..JOIN。

但是,就生成 SQL 字符串而言,它似乎确实有效(几乎?):

class Path(Base):
    __tablename__ = "path"

    id = Column(Integer, primary_key=True)
    descendant = Column(Integer)
    ancestor = Column(Integer)

j = join(Path, p1, p1.ancestor == 5)
d = delete(j).where(Path.descendant == p1.descendant)
print d

打印:

DELETE FROM path JOIN path AS p1 ON p1.ancestor = :ancestor_1 
 WHERE path.descendant = p1.descendant

但是,我的 MySQL 数据库不接受这个,默认情况下它会呈现 INNER JOIN,但会失败,但如果我修改 MySQL 编译器不这样做,仍然会失败:

s.execute(d)

(ProgrammingError) (1064, "You have an error in your SQL syntax; check the manual that 
corresponds to your MySQL server version for the
right syntax to use near 'JOIN path AS p1 ON p1.ancestor = 5 WHERE
path.descendant = p1.descendant' at line 1") 'DELETE FROM path JOIN
path AS p1 ON p1.ancestor = %s WHERE path.descendant = p1.descendant'
(5,)

看起来像您的 SQL 逐字记录(哦,除了“从路径中删除路径”之外?对吗?)?

无论如何,如果内置编译器没有这样做,您的选择是使用session.execute("some sql") 或使用compiler extension 构建自定义构造。

【讨论】:

嗨,谢谢。不确定这是否适用于所有数据库,但是是的,MySQL 需要“DELETE paths FROM paths”。不过差不多了! 它不适用于任何其他数据库。 MySQL 有很多很多完全是他们自己发明的语法。【参考方案2】:

你可以使用prefixes关键字参数:

j = join(table1, table2, table1.c.key==table2.c.key)
stmt = delete(j, prefixes=[table1_name])
session.execute(stmt)

prefixes 关键字只是在语句关键字之后添加一个或多个表达式,即 SELECT、INSERT、UPDATE 或 DELETE。

在这种情况下,delete(j) 语句生成表达式:"DELETE FROM table1 INNER JOIN table2 ON table1.key=table2.key"。 当我们添加prefixes参数表达式变为:"DELETE table1 FROM table1 INNER JOIN table2 ON table1.key=table2.key",即是正确的MySQL查询。

【讨论】:

以上是关于SQLAlchemy:在 MySQL 上使用自联接创建删除查询的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 自联接表 Next/Prev 行性能

自联接的困难 MySQL 更新查询

Mysql 自联接性能

查看在表上具有自联接

Spring Boot JPA:在自联接关系中的 JSON 视图上递归

LINQ 查询中的自联接并返回视图