这里一个非常常见的问题是如何进行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语法的替代品,随着时间的推移,它已经成长为一些无关的细节.我正在研究明确的答案.
这些技术对于"插入如果不存在,否则什么都不做"也很有用,即"插入...复制键忽略".
我想从数据库中获取一个对象(如果它已经存在)(基于提供的参数),或者如果不存在则创建它.
Django get_or_create(或来源)这样做.SQLAlchemy中是否有等效的快捷方式?
我目前正在明确地写出这样的:
def get_or_create_instrument(session, serial_number):
instrument = session.query(Instrument).filter_by(serial_number=serial_number).first()
if instrument:
return instrument
else:
instrument = Instrument(serial_number)
session.add(instrument)
return instrument
Run Code Online (Sandbox Code Playgroud) 我想创建一个函数,给定表的名称,返回具有该表名的模型.例如:
class Model(Base):
__tablename__ = 'table'
...a bunch of Columns
def getModelFromTableName(tablename):
...something magical
Run Code Online (Sandbox Code Playgroud)
所以getModelFromTableName('table')应该返回Model类.
我的目标是在我正在制作的简单表单生成器中使用该函数,因为FormAlchemy不能与python3.2一起工作,我希望它能很好地处理外键.
任何人都可以给我任何关于如何让getModelFromTableName工作的指针吗?
这是我的一个想法(可能完全错误,我之前没有使用过meta类)
如果我要使我的Model类继承自Base以及其他一些类(TableReg)并具有TableReg商店Model的类meta,该怎么办?tablename在某些全局字典或Singleton中.
我意识到这可能是完全关闭的,因为Base的元类做了一些非常重要且非常好的东西,我不想打破,但我认为必须有一种方法让我在元类中附加一些构造函数代码我的模特 或者我不明白.
我有多个进程,可能会在数据库中插入重复的行。这些插入不会很频繁地发生(每小时几次),因此它对性能并不重要。
在进行插入之前,我已经尝试过存在检查,如下所示:
#Assume we're inserting a camera object, that's a valid SQLAlchemy ORM object that inherits from declarative_base...
try:
stmt = exists().where(Camera.id == camera_id)
exists_result = session.query(Camera).with_lockmode("update").filter(stmt).first()
if exists_result is None:
session.add(Camera(...)) #Lots of parameters, just assume it works
session.commit()
except IntegrityError as e:
session.rollback()
Run Code Online (Sandbox Code Playgroud)
我exist()遇到的问题是检查不会锁定表,因此,多个进程可能会尝试同时插入同一对象。在这种情况下,一个过程通过插入成功,而其他过程则由于IntegrityError异常而失败。虽然这样做有效,但对我来说感觉并不“干净”。
我真的很想在进行exists()检查之前锁定Camera表。
我有一个带有 timescaledb 扩展名的 postgres 数据库。
我的主索引是一个时间戳,我想选择最新的行。
如果我碰巧知道在某个时间之后发生了最新的行,那么我可以使用如下查询:
query = 'select * from prices where time > %(dt)s'
Run Code Online (Sandbox Code Playgroud)
这里我指定了一个日期时间,并使用 psycopg2 执行查询:
# 2018-01-10 11:15:00
dt = datetime.datetime(2018,1,10,11,15,0)
with psycopg2.connect(**params) as conn:
cur = conn.cursor()
# start timing
beg = datetime.datetime.now()
# execute query
cur.execute(query, {'dt':dt})
rows = cur.fetchall()
# stop timing
end = datetime.datetime.now()
print('took {} ms'.format((end-beg).total_seconds() * 1e3))
Run Code Online (Sandbox Code Playgroud)
定时输出:
took 2.296 ms
Run Code Online (Sandbox Code Playgroud)
但是,如果我不知道输入上述查询的时间,我可以使用如下查询:
took 2.296 ms
Run Code Online (Sandbox Code Playgroud)
我以类似的方式执行查询
query = 'select * from prices order by time desc limit 1'
Run Code Online (Sandbox Code Playgroud)
定时输出: …
遵循这个问题:
\n\n正如 Ilja Everil\xc3\xa4 在他的回答中提到的,我创建了一个表对象:
\n\nfrom sqlalchemy import *\nmetadata = MetaData()\nidTagTable = Table(\'id_tag\', metadata,\n Column(\'id\', String(255), primary_key = True), \n Column(\'category\', String(20), nullable = False),\n Column(\'createddate\', Date, nullable = False),\n Column(\'updatedon\', Date, nullable = False)\n )\nRun Code Online (Sandbox Code Playgroud)\n\n创建表对象后,我更改了插入和更新语句:
\n\ninsert_statement = sqlalchemy.dialects.postgresql.insert(idTagTable)\nupsert_statement = insert_statement.on_conflict_do_update(\n constraint=PrimaryKeyConstraint(\'id\'),\n set_={"updatedon": insert_statement.excluded.updateon,\n "category":insert_statement.excluded.category}\n)\ninsert_values = df.to_dict(orient=\'records\')\nconn.execute(upsert_statement, insert_values)\nRun Code Online (Sandbox Code Playgroud)\n\n现在我收到编程错误:
\n\nTraceback (most recent call last):\n\nFile "<ipython-input-66-0fc6a1bf9c6b>", line 7, in <module>\nconn.execute(upsert_statement, insert_values)\n\nFile "/home/ubuntu/anaconda2/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 945, in execute\nreturn meth(self, multiparams, params)\n\nFile "/home/ubuntu/anaconda2/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", …Run Code Online (Sandbox Code Playgroud) 我目前正在使用 SQLAlchemy ORM 来处理我的数据库操作。现在我有一个需要ON CONFLICT (id) DO UPDATE. 该方法on_conflict_do_update()似乎是正确的使用方法。但这里的帖子说代码必须切换到 SQLAlchemy 核心,并且缺少高级 ORM 功能。我对这个说法感到困惑,因为我认为像下面的演示这样的代码可以实现我想要的,同时保留 SQLAlchemy ORM 的功能。
class Foo(Base):
...
bar = Column(Integer)
foo = Foo(bar=1)
insert_stmt = insert(Foo).values(bar=foo.bar)
do_update_stmt = insert_stmt.on_conflict_do_update(
set_=dict(
bar=insert_stmt.excluded.bar,
)
)
session.execute(do_update_stmt)
Run Code Online (Sandbox Code Playgroud)
我还没有在我的项目上测试它,因为它需要大量的修改。请问这是否是处理ON CONFLICT (id) DO UPDATESQLALchemy ORM 的正确方法?
sqlalchemy ×5
python ×3
postgresql ×2
django ×1
foreign-keys ×1
orm ×1
psycopg2 ×1
python-3.x ×1
sql ×1
sql-merge ×1
timescaledb ×1
upsert ×1