PostgreSQL - 使用SQLAlchemy的INSERT from SELECT插入不存在的数据

20

正如这里所指出的,在postgresql 9.1+中可以进行以下操作

INSERT INTO example_table
    (id, name)
SELECT 1, 'John'
WHERE
    NOT EXISTS (
        SELECT id FROM example_table WHERE id = 1
    );
我一直在尝试使用SQLAlchemy 0.9的版本进行操作,他们引入了INSERT from SELECT 方法,理论上应该可以处理上述问题。
如果可能的话,如何实现?(因为我想利用result.inserted_primary_key,而在使用原始SQL时无法返回它)
我如何在“from_select”部分中使用 bindparams,因为似乎只有在选择表列时才能使用它。
例如:
insrt = example_table.insert().
    from_select(['id', 'name'],
    example_table.select().
    where(~exists(select([example_table.c.id],
    example_table.c.id == 1))))

result = session.execute(insrt)

if result.is_insert:
    print 'do something with result.inserted_primary_key'

1
只有在您已经知道主键并且希望在其不存在时创建它时,才可以安全地执行您给出的命令。如果您使用非唯一键进行操作,则会受到竞争条件的影响,这可能导致多个插入同时成功运行。即使如此,该命令也不一定会成功,如果与另一个并发插入冲突,则可能会失败并显示唯一性冲突错误。要了解更多信息,请阅读关于PostgreSQL中upsert的其他讨论。 - Craig Ringer
许多,许多,许多的讨论。我正在使用的关键字是唯一的,不应该(希望如此)存在并发插入的问题。我在这里遇到的问题是sqlalchemy的语法,并让它在选择时使用我的自定义参数(通过bindparams或任何其他方式),而不是使用表列。 - 7wonders
它似乎在8.4.11中也能正常工作。 - rapto
1个回答

24
from sqlalchemy import *

"""
INSERT INTO example_table
    (id, name)
SELECT 1, 'John'
WHERE
    NOT EXISTS (
        SELECT id FROM example_table WHERE id = 1
    );
"""

m = MetaData()

example_table = Table("example_table", m,
                        Column('id', Integer),
                        Column('name', String)
                    )

sel = select([literal("1"), literal("John")]).where(
           ~exists([example_table.c.id]).where(example_table.c.id == 1)
      )

ins = example_table.insert().from_select(["id", "name"], sel)
print(ins)

输出:

INSERT INTO example_table (id, name) SELECT :param_1 AS anon_1, :param_2 AS anon_2 
WHERE NOT (EXISTS (SELECT example_table.id 
FROM example_table 
WHERE example_table.id = :id_1))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接