在sqlalchemy

时间:2015-10-23 16:28:38

标签: python sql postgresql sqlalchemy

我已经阅读了不少资源(ao。12),但我无法在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)

5 个答案:

答案 0 :(得分:15)

使用Postgres 9.6.1,sqlachemy 1.1.4和psycopg2 2.6.2:

  1. 将您的数据结构转换为字典。来自熊猫,它是

    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')
    
  2. 通过sqlalchemy

    连接到数据库
    engine = sqlalchemy.create_engine("postgresql://user:password@localhost/postgres")
    connect = engine.connect()
    meta = MetaData(bind=engine)
    meta.reflect(bind=engine)
    
  3. 为名为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'])
    
  4. 执行

    results = engine.execute(do_nothing_stmt)
    # Get number of rows inserted
    rowcount = results.rowcount
    
  5. 警告:

    此方法不适用于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()