如何使用 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炼金术。
方法是将 DELETE
与 RETURNING
一起使用,然后将行插入到另一个 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
我想使用带有 Postgres 数据库的 SQLAlchemy 将行从一个 table 移动到另一个(Stack Overflow 上还有其他关于移动数据的问题,但他们并不关注使用SQL炼金术。
方法是将 DELETE
与 RETURNING
一起使用,然后将行插入到另一个 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