如何使用 SQLAlchemy 和 Postgres RETURNING 从一个 table 中删除行并插入另一个行?

How can I delete rows from one table and insert into another using SQLAlchemy and Postgres RETURNING?

我想使用带有 Postgres 数据库的 SQLAlchemy 将行从一个 table 移动到另一个(Stack Overflow 上还有其他关于移动数据的问题,但他们并不关注使用SQL炼金术。

方法是将 DELETERETURNING 一起使用,然后将行插入到另一个 table。

我正在使用:SQLAlchemy 1.0.12、Postgres 9.4 和 Python 2.7.11。

正在设置 tables

以下 SQL 创建 table 并插入一行数据:

create table example1 (
    id integer,
    value_a integer,
    value_b integer,
    CONSTRAINT example1_pkey PRIMARY KEY (id)
);
create table example2 (
    id integer,
    value_a integer,
    value_b integer,
    CONSTRAINT example2_pkey PRIMARY KEY (id)
);

insert into example1 values (18, 1, 9);

使用 SQLAlchemy

创建 tables

以下 SQLAlchemy 代码创建相同的 tables 并插入一行数据:

from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class ExampleOne(Base):
    __tablename__ = 'example1'

    id = Column(Integer, primary_key=True)
    value_a = Column(Integer)
    value_b = Column(Integer)


class ExampleTwo(Base):
    __tablename__ = 'example2'

    id = Column(Integer, primary_key=True)
    value_a = Column(Integer)
    value_b = Column(Integer)


Base.metadata.create_all(session.bind)

with session.begin():
    session.add(ExampleOne(id=18, value_a=1, value_b=9))

我想实现的查询

这是我希望运行(独立运行)的SQL查询:

with output as (delete from example1 where value_a < 10 returning id, value_a)
insert into example2 (id, value_a, value_b)
select id, value_a, 3 from output;

SQL到目前为止的炼金术查询

到目前为止我构建的查询是:

query = insert(ExampleTwo, inline=True).from_select(
    ['id', 'value_a', 'value_b'],
    select(
        ['id', 'value_a', literal(3)]
    ).where(
        select([
            'id', 'value_a',
        ]).select_from(
            delete(ExampleOne).where(
                ExampleOne.value_a < 10,
            ).returning(
                ExampleOne.id,
                ExampleOne.value_a,
            )
        )
    )
)

session.execute(query)

问题

错误是:

  File ".../lib/python2.7/site-packages/sqlalchemy/sql/selectable.py", line 41, in _interpret_as_from
    raise exc.ArgumentError("FROM expression expected")
sqlalchemy.exc.ArgumentError: FROM expression expected

问题似乎是 SQLAlchemy 无法将 DELETE ... RETURNING 查询识别为 INSERT 查询的 FROM 部分的有效表达式。

有没有办法让 SQLAlchemy 清楚这一点,或者是否有不同的方法在 SQLAlchemy 中创建给定查询?

您需要将 delete 表达式变成 CTE,因为您的原始 SQL 要求:

>>> output = delete(ExampleOne).where(
...     ExampleOne.value_a < 10,
... ).returning(
...     ExampleOne.id,
...     ExampleOne.value_a,
... ).cte('output')
>>> query = insert(ExampleTwo, inline=True).from_select(
...     ['id', 'value_a', 'value_b'],
...     select(
...         ['id', 'value_a', literal(3)]
...     ).select_from(output)
... )
>>> query.compile(engine)
WITH output AS 
(DELETE FROM example1 WHERE example1.value_a < %(value_a_1)s RETURNING example1.id, example1.value_a)
 INSERT INTO example2 (id, value_a, value_b) SELECT id, value_a, %(param_1)s AS anon_1 
FROM output

遗憾的是,.cte 仅适用于 SQLAlchemy 1.1 中的 delete 表达式,该版本目前尚未发布,因此您必须安装 SQLAlchemy源回购使这项工作:

pip install -e git+https://bitbucket.org/zzzeek/sqlalchemy#egg=sqlalchemy