oracle 触发器 upsert,如何使SQLAlchemy insert与Postgres多处理proof upsert触发器一起工作?...
我有多處理應(yīng)用程序,需要upsert(插入,如果存在更新)功能。在
我決定使用觸發(fā)器解決方案來接近upsert。(為每個名為is_upsert的啟用upsert的表添加額外的列,在觸發(fā)器檢查此字段時,如果為false,則執(zhí)行正常插入,但如果為true,則執(zhí)行upsert邏輯-嘗試更新,如果由于記錄不存在而失敗,則嘗試插入)。在
觸發(fā)邏輯如下:CREATE OR REPLACE FUNCTION upsert_trigger_function_{table}()
RETURNS TRIGGER AS $upsert_trigger_function$
DECLARE
row record;
BEGIN
RAISE NOTICE 'upsert trigger fired, upsert is %%', NEW.{upsert_column};
IF NEW.{upsert_column} THEN
NEW.{upsert_column} := false;
LOOP
UPDATE {table} SET
{update_set}
WHERE
{update_where}
;
IF found THEN
RETURN NULL;
END IF;
BEGIN
INSERT INTO {table} SELECT NEW.*;
RETURN NULL;
EXCEPTION WHEN unique_violation THEN
-- loop
END;
END LOOP;
RETURN NULL;
ELSE
RETURN NEW;
END IF;
END;
$upsert_trigger_function$ LANGUAGE plpgsql;
測試對象(add\u upsert只需安裝上述觸發(fā)器):
^{pr2}$
測試腳本from sqlalchemy.engine import create_engine
from pipelines.settings_proxy import TEST_DB
from sqlalchemy.orm.session import sessionmaker
from test_pipelines.test_persistence.mock_items import SimpleItem
from test_pipelines.test_persistence.helpers import random_simple_item
def main():
engine = create_engine(TEST_DB)
values = random_simple_item(_upsert=True)
session = sessionmaker(engine)()
si = SimpleItem(**values)
session.add(si)
session.commit()
si = SimpleItem(**values)
si.price = 1
session.merge(si)
session.commit()
它在使用SQL statesments時可以正常工作,但是當(dāng)我將它與SQLAlchemy ORM add object一起使用時,它就有了Traceback (most recent call last):
File "pipelines/persistence/experiment_with_upsert_field.py", line 59, in
main()
File "pipelines/persistence/experiment_with_upsert_field.py", line 27, in main
session.commit()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 801, in commit
self.transaction.commit()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 392, in commit
self._prepare_impl()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 372, in _prepare_impl
self.session.flush()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 2019, in flush
self._flush(objects)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 2137, in _flush
transaction.rollback(_capture_exception=True)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/util/compat.py", line 184, in reraise
raise value
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/session.py", line 2101, in _flush
flush_context.execute()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
rec.execute(self)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
uow
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/persistence.py", line 174, in save_obj
mapper, table, insert)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/orm/persistence.py", line 800, in _emit_insert_statements
execute(statement, params)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 914, in execute
return meth(self, multiparams, params)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
compiled_sql, distilled_params
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/base.py", line 1159, in _execute_context
result = context._setup_crud_result_proxy()
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/default.py", line 828, in _setup_crud_result_proxy
self._setup_ins_pk_from_implicit_returning(row)
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/default.py", line 893, in _setup_ins_pk_from_implicit_returning
for col in table.primary_key
File "/home/sebastian/local/virtualenvs/perception/lib/python3.4/site-packages/sqlalchemy/engine/default.py", line 891, in
for col, value in [
TypeError: 'NoneType' object is not subscriptable
在深處升起sqlalchemy.engine.default. 我確信這是因為我的觸發(fā)器在執(zhí)行UPSERT時返回NULL,而SQLAlchemy嘗試使用RETURNING語句傳播帶有插入ID的對象。它顯然失敗了,因為它不可能從它的從屬INSERT/UPDATE在觸發(fā)器中獲取正確的ID,同時阻止正常的正常插入。在
請注意,我已經(jīng)將upsert作為一個特殊函數(shù)進(jìn)行了測試,但這對我來說并不適用,因為我犧牲了SQLAlchemy在更新復(fù)雜項(那些與其他項有關(guān)系的項)方面的幫助。在
所以我的問題是:如何告訴SQLAlchemy避免加載插入的對象ID?
總結(jié)
以上是生活随笔為你收集整理的oracle 触发器 upsert,如何使SQLAlchemy insert与Postgres多处理proof upsert触发器一起工作?...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java搭配oracle,Java联接O
- 下一篇: oracle的cv函数,cv_wait