这里一个非常常见的问题是如何进行upsert,这是MySQL调用的INSERT ... ON DUPLICATE UPDATE,标准支持作为MERGE操作的一部分.
鉴于PostgreSQL不直接支持它(在第9.5页之前),你是如何做到这一点的?考虑以下:
CREATE TABLE testtable (
id integer PRIMARY KEY,
somedata text NOT NULL
);
INSERT INTO testtable (id, somedata) VALUES
(1, 'fred'),
(2, 'bob');
Run Code Online (Sandbox Code Playgroud)
现在,假设你想"UPSERT"的元组(2, 'Joe'),(3, 'Alan'),因此新表的内容是:
(1, 'fred'),
(2, 'Joe'), -- Changed value of existing tuple
(3, 'Alan') -- Added new tuple
Run Code Online (Sandbox Code Playgroud)
这是人们在讨论时所谈论的内容upsert.至关重要的是,任何方法在同一个表上存在多个事务时都必须是安全的 - 通过使用显式锁定,或以其他方式抵御由此产生的竞争条件.
关于PostgreSQL中的重复更新,在Insert上广泛讨论了这个主题?,但这是关于MySQL语法的替代品,随着时间的推移,它已经成长为一些无关的细节.我正在研究明确的答案.
这些技术对于"插入如果不存在,否则什么都不做"也很有用,即"插入...复制键忽略".
我正在尝试使用SQLAlchemy模块在python中编写批量upsert(而不是在SQL中!).
我在SQLAlchemy添加上收到以下错误:
sqlalchemy.exc.IntegrityError: (IntegrityError) duplicate key value violates unique constraint "posts_pkey"
DETAIL: Key (id)=(TEST1234) already exists.
Run Code Online (Sandbox Code Playgroud)
我有一个posts在id列上使用主键调用的表.
在这个例子中,我已经在db中有一行id=TEST1234.当我尝试db.session.add()使用id设置为的新帖子对象时TEST1234,我得到上面的错误.我的印象是,如果主键已经存在,记录将会更新.
如何仅使用基于主键的Flask-SQLAlchemy进行升级?有简单的解决方案吗?
如果没有,我总是可以检查并删除任何匹配id的记录,然后插入新记录,但这对我的情况来说似乎很昂贵,我不希望有很多更新.
我在这里遵循SQLAlchemy文档,以使用Postgres编写批量upsert语句。为了演示,我有一个简单的表MyTable:
class MyTable(base):
__tablename__ = 'mytable'
id = Column(types.Integer, primary_key=True)
test_value = Column(types.Text)
Run Code Online (Sandbox Code Playgroud)
创建通用插入语句非常简单:
from sqlalchemy.dialects import postgresql
values = [{'id': 0, 'test_value': 'a'}, {'id': 1, 'test_value': 'b'}]
insert_stmt = postgresql.insert(MyTable.__table__).values(values)
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是当我尝试添加upsert的“冲突时”部分。
update_stmt = insert_stmt.on_conflict_do_update(
index_elements=[MyTable.id],
set_=dict(data=values)
)
Run Code Online (Sandbox Code Playgroud)
尝试执行此语句会产生一个ProgrammingError:
from sqlalchemy import create_engine
engine = create_engine('postgres://localhost/db_name')
engine.execute(update_stmt)
>>> ProgrammingError: (psycopg2.ProgrammingError) can't adapt type 'dict'
Run Code Online (Sandbox Code Playgroud)
我认为我的误解是使用该on_conflict_do_update方法构造语句。有人知道如何构造此语句吗?我已经在StackOverflow上查看了其他问题(例如here),但似乎无法解决上述错误。