【问题标题】:SQLAlchemy insert from select raises bindparam error从 select 中插入 SQLAlchemy 引发 bindparam 错误
【发布时间】:2019-12-11 22:22:25
【问题描述】:

在 PostgreSQL 上使用 SQLAlchemy,我尝试提高插入性能(大约要插入 100k egdes),在单个查询中对一条边及其节点执行“嵌套插入”。

使用Insert.from_select,我得到以下错误,我真的不明白为什么。

CompileError: bindparam() name 'name' is reserved for automatic usage in the VALUES or SET clause of this insert/update statement.   Please use a name other than column name when using bindparam() with insert() or update() (for example, 'b_name').
from sqlalchemy import *

metadata = MetaData()

node = Table('node', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
)

edge = Table('edge', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('source_id', Integer(), ForeignKey(node.c.id)),
    Column('target_id', Integer(), ForeignKey(node.c.id)),
)

engine = create_engine('postgres://postgres:postgres@db:5432')
metadata.create_all(engine)

e1_source = insert(node).values(name='e1_source').returning(node.c.id).cte('source')
e1_target = insert(node).values(name='e1_target').returning(node.c.id).cte('target')
e1 = insert(edge).from_select(
  ['source_id', 'target_id', 'name'],  # bindparam error
  # ['source_id', 'target_id', 'b_name'],  # key error
  # [edge.c.source_id, edge.c.target_id, edge.c.name],  # bindparam error
  select([
    e1_source.c.id,
    e1_target.c.id,
    literal('e1'),
  ])
)
engine.execute(e1)

编辑:下面是我预期生成的 SQL 查询。不过,我仍然愿意接受任何建议来实现我的目的。

CREATE TABLE node (
   id SERIAL PRIMARY KEY,
   name VARCHAR
);

CREATE TABLE edge (
   id SERIAL PRIMARY KEY,
   source_id INTEGER REFERENCES node (id),
   target_id INTEGER REFERENCES node (id),
   name VARCHAR
);

WITH source AS (
  INSERT INTO node (name)
  VALUES ('e1_source')
  RETURNING id
), target as (
  INSERT INTO node (name)
  VALUES ('e1_target')
  RETURNING id
)
INSERT INTO edge (source_id, target_id, name)
SELECT source.id, target.id, 'e1'
FROM source, target;

【问题讨论】:

  • 当他尝试插入时看看这个stackoverflow.com/questions/41724658/… 使用 insert_ignore
  • 感谢您的帮助,但我没有看到问题之间的关系,除了他也遇到了binparam 错误。我终于找到了我的解决方案。

标签: python postgresql sqlalchemy


【解决方案1】:

我终于弄清楚了 SQLAlchemy 在哪里隐式使用 bindparam 来解决我的问题:在节点查询中,而不是在我最初想到的边缘查询中。

但我仍然不确定这是否是使用 SQLAlchemy 执行嵌套插入查询的正确方法,以及它是否会缩短执行时间。

e1_source = insert(node).values(name=bindparam('source_name')).returning(node.c.id).cte('source')
e1_target = insert(node).values(name=bindparam('target_name')).returning(node.c.id).cte('target')
e1 = insert(edge).from_select(
  ['source_id', 'target_id', 'name'],
  select([
    e1_source.c.id,
    e1_target.c.id,
    literal('e1'),
  ])
)
engine.execute(e1, {
    'source_name': 'e1_source',
    'target_name': 'e1_target',
})

【讨论】:

    猜你喜欢
    • 2020-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多