我已经阅读了不少资源(ao。1,2),但我无法在sqlalchemy中使用Postgresql的ON CONFLICT IGNORE行为。
我已使用this accepted answer作为基础,但它提供了
SAWarning: Can't validate argument 'append_string'; can't locate any SQLAlchemy dialect named 'append'
我尝试将postgresql方言添加到@compile子句中,重命名我的对象,但它不起作用。
我也尝试使用str(insert())+ " ON CONFILCT IGNORE"
而没有结果。 (顺便说一句,这并不奇怪)
如何才能将On CONFLICT IGNORE
添加到我的插页中?我喜欢建议的解决方案,因为我可以看到自己不希望每个IGNORE
上的INSERT
行为
PS。使用python 2.7(不要介意升级到3.4 / 3.5),最新的sqlalchemy(1.x)
答案 0 :(得分:15)
将您的数据结构转换为字典。来自熊猫,它是
import pandas
from sqlalchemy import MetaData
from sqlalchemy.dialects.postgresql import insert
import psycopg2
# The dictionary should include all the values including index values
insrt_vals = df.to_dict(orient='records')
通过sqlalchemy
连接到数据库engine = sqlalchemy.create_engine("postgresql://user:password@localhost/postgres")
connect = engine.connect()
meta = MetaData(bind=engine)
meta.reflect(bind=engine)
为名为db table
tstbl
构建插入语句
table = meta.tables['tstbl']
insrt_stmnt = insert(table).values(insrt_vals)
# Where colA and colB are the columns to check for the conflict
do_nothing_stmt = insrt_stmnt.on_conflict_do_nothing(index_elements=['colA','colB'])
执行
results = engine.execute(do_nothing_stmt)
# Get number of rows inserted
rowcount = results.rowcount
此方法不适用于NaT
开箱即用。
tst_df = pd.DataFrame({'colA':['a','b','c','a','z', 'q'],
'colB': pd.date_range(end=datetime.datetime.now() , periods=6),
'colC' : ['a1','b2','c3','a4','z5', 'q6']})
insrt_vals = tst_df.to_dict(orient='records')
engine = sqlalchemy.create_engine("postgresql://user:password@localhost/postgres")
connect = engine.connect()
meta = MetaData(bind=engine)
meta.reflect(bind=engine)
table = meta.tables['tstbl']
insrt_stmnt = insert(table).values(insrt_vals)
do_nothing_stmt = insrt_stmnt.on_conflict_do_nothing(index_elements=['colA','colB'])
results = engine.execute(do_nothing_stmt)
答案 1 :(得分:3)
你不需要这个,使用存在条件来防止插入重复。
例如:
INSERT INTO table (unique_name)
SELECT 'some_string'
WHERE NOT EXISTS(SELECT 1 FROM table WHERE unique_name = 'some_string')
你也可以
INSERT INTO table (unique_name)
VALUES('some_string')
ON CONFLICT (unique_name) DO NOTHING
但如果您需要insert或在单个查询中更新,那么这是您的示例:
INSERT INTO distributors (did, dname)
VALUES (5, 'Gizmo Transglobal'), (6, 'Associated Computing, Inc')
ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;
这是PostgreSQL文档中的一个示例。
答案 2 :(得分:3)
这适用于Postgresql 9.5:
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def prefix_inserts(insert, compiler, **kw):
return compiler.visit_insert(insert, **kw) + " ON CONFLICT DO NOTHING"
我将它用于bulk_insert_mappings
。但它确实没有ON CONFLICT DO NOTHING
可选
答案 3 :(得分:1)
这是尼克拉斯答案的扩展。
基本上,使用线程本地状态和上下文管理器使附加ON CONFLICT DO NOTHING
为可选。不过,这仍然是一个大问题。
它也只钩住postgres特定的语句,而不从文本手动构造sql查询。
import threading
from contextlib import contextmanager
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
from sqlalchemy.dialects.postgresql.dml import OnConflictDoNothing
state = threading.local()
@contextmanager
def on_conflict_do_nothing():
state.active = True
yield
del state.active
@compiles(Insert, 'postgresql')
def prefix_inserts(insert, compiler, **kw):
if getattr(state, "active", False):
insert._post_values_clause = OnConflictDoNothing()
return compiler.visit_insert(insert, **kw)
答案 4 :(得分:0)
这适用于Postgresql 10.5和Sqlalchemy 1.3.6:
from sqlalchemy.dialects.postgresql import insert
table_info = {
'tableTime': '',
'deploymentID': '',
'tableData': ''
}
insert_table = insert(Table).values(table_info)
insert_table_sql = insert_table.on_conflict_do_nothing(
index_elements=['tableTime', 'deploymentID']
)
db.session.execute(insert_table_sql)
db.session.commit()