【发布时间】:2015-10-31 01:39:45
【问题描述】:
我有两个名为 movimiento (id_operacion, id_pago, importe) 和 ticket (id_movimiento, id_localidad, nro_ticket, precio, impreso, id_movimiento_anterior) 的表,并且 ticket 表有一个插入后触发器,它从名为 funcion 的表中分配 nro_ticket 值,该表保存了序列值。
这是插入前触发器:
create or replace TRIGGER "TICKETS4_TST"."TRG_B_I_TICKET"
BEFORE INSERT ON TICKET REFERENCING NEW AS NEW
FOR EACH ROW
DECLARE
ticket NUMBER;
BEGIN
ticket := OBTENER_NUMERO_TICKET(SUBSTR(:new.id_localidad,0,9));
:new.nro_ticket := ticket;
END;
以及获取nro_ticket值的函数:
create or replace FUNCTION obtener_numero_ticket (id_fun IN VARCHAR2)
RETURN NUMBER
IS
nro_ticket NUMBER;
BEGIN
SELECT seq_ticket into nro_ticket FROM funcion where id_funcion = id_fun;
RETURN (nro_ticket + 1);
END obtener_numero_ticket;
这是插入后触发器:
create or replace TRIGGER "TICKETS4_TST"."TRG_A_I_TICKET"
AFTER INSERT ON TICKET REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
UPDATE funcion SET seq_ticket = :new.nro_ticket WHERE id_funcion= SUBSTR(:new.id_localidad,0,9);
END;
这是 SQLAlchemy 代码:
sql_movimientos = """INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('%s', '%s', '%s')
RETURNING id_movimiento INTO :id_movimiento"""
sql_tickets = """INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('%s', '%s', '%s',
'%s', '%s')
RETURNING nro_ticket INTO :nro_ticket"""
with db.session as session:
try:
cursor = session.connection().connection.cursor()
nuevo_id_movimiento = cursor.var(NUMBER)
nuevo_nro_ticket = cursor.var(NUMBER)
print sql_movimientos % (
movimiento.operacion, movimiento.pago, movimiento.importe)
session.execute(sql_movimientos % (
movimiento.operacion, movimiento.pago, movimiento.importe),
{'id_movimiento': nuevo_id_movimiento})
nuevo_id_movimiento = int(nuevo_id_movimiento.getvalue())
except Exception, e:
session.rollback()
raise e
try:
print sql_tickets % (nuevo_id_movimiento,
ticket.localidad.id, ticket.precio, ticket.impreso,
ticket.movimiento_anterior)
session.execute(sql_tickets % (nuevo_id_movimiento,
ticket.localidad.id, ticket.precio, ticket.impreso,
ticket.movimiento_anterior),
{'nro_ticket': nuevo_nro_ticket})
nuevo_nro_ticket = int(nuevo_nro_ticket.getvalue())
print nuevo_nro_ticket
except Exception, e:
session.rollback()
raise e
这就是 sqlalchemy 翻译查询的方式:
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO :id_movimiento
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('5725976', '------------------', '100',
'0', '')
RETURNING nro_ticket INTO :nro_ticket
17 << nro_ticket value
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO :id_movimiento
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('5725977', '-------------', '100',
'0', '')
RETURNING nro_ticket INTO :nro_ticket
17 << nro_ticket value
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO :id_movimiento
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('5725978', '----------------', '100',
'0', '')
RETURNING nro_ticket INTO :nro_ticket
17 << nro_ticket value
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO :id_movimiento
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('5725979', '--------------', '100',
'0', '')
RETURNING nro_ticket INTO :nro_ticket
17 << nro_ticket value
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO :id_movimiento
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES ('5725980', '--------------', '100',
'0', '')
RETURNING nro_ticket INTO :nro_ticket
17 << nro_ticket value
但如果在 SQLDeveloper 中作为匿名块执行相同的操作,我会得到正确的值:
declare
id_movimiento number;
nro_ticket number;
begin
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO id_movimiento;
DBMS_OUTPUT.put_line(id_movimiento);
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES (id_movimiento, '------------------', '100',
'0', '')
RETURNING nro_ticket INTO nro_ticket;
DBMS_OUTPUT.put_line(nro_ticket);
INSERT INTO movimiento (id_operacion, id_pago, importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO id_movimiento;
DBMS_OUTPUT.put_line(id_movimiento);
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES (id_movimiento, '--------------------', '100',
'0', '')
RETURNING nro_ticket INTO nro_ticket;
DBMS_OUTPUT.put_line(nro_ticket);
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO id_movimiento;
DBMS_OUTPUT.put_line(id_movimiento);
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES (id_movimiento, '---------------------', '100',
'0', '')
RETURNING nro_ticket INTO nro_ticket;
DBMS_OUTPUT.put_line(nro_ticket);
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO id_movimiento;
DBMS_OUTPUT.put_line(id_movimiento);
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES (id_movimiento, '--------------------', '100',
'0', '')
RETURNING nro_ticket INTO nro_ticket;
DBMS_OUTPUT.put_line(nro_ticket);
INSERT INTO movimiento (id_operacion, id_pago,
importe)
VALUES ('639086', '566365', '100')
RETURNING id_movimiento INTO id_movimiento;
DBMS_OUTPUT.put_line(id_movimiento);
INSERT INTO ticket (id_movimiento, id_localidad,
precio, impreso,
id_movimiento_anterior)
VALUES (id_movimiento, '---------------------', '100',
'0', '')
RETURNING nro_ticket INTO nro_ticket;
DBMS_OUTPUT.put_line(nro_ticket);
end;
哪个输出这个:
5725981
17 << nro_ticket value
5725982
18 << nro_ticket value
5725983
19 << nro_ticket value
5725984
20 << nro_ticket value
5725985
21 << nro_ticket value
所以我认为问题是 SQLALchemy,但我不明白为什么它不起作用。
【问题讨论】:
-
在您的第一个代码块中,您正在硬编码插入到票证表中的 id_movimiento 的值,在第二个代码块中您使用的是变量。在您的代码中,您显示了更新功能表的 seq_ticket 列的触发器,但是现在如何设置票表的 nro_ticket 列(它不是您的插入语句的一部分)。在 SQL Developer 中,您的代码全部在一个会话中执行,那么在 SQLAlchemy 中呢?您只显示了所涉及的 SQL 语句,而不是任何周围的代码。
-
@Sentinel 更新了它。我执行原始查询的原因是因为 session.add 不允许我使用 returning into,就像我之前的问题一样:stackoverflow.com/questions/31709252/…
-
在 oracle 中触发器按以下顺序触发 1) 所有 Before 语句触发 2) 所有在每行之前触发 3) 所有在每行之后触发 4) 所有 after 语句触发。在您的情况下,您有 2 和 3。如果 SQL Alchemy 正在批处理似乎可能的更新,那么您的插入后触发器将在所有插入前触发器都被触发之后才会触发。结果,多行获得相同的 nro_ticket 值,然后 seq_ticket 值多次更新为相同的值。在 SQLDev 中,每个语句一次处理一个,因此触发器按预期触发。
-
@Sentinel 这正是发生的事情,不幸的是我能够解决这个问题的唯一方法(我真的不想称之为“修复”,更多的是一个“短期问题solver") 是每次我向票证交易添加值时提交,这并没有像一开始计划的那样完全工作。问题是会话本身不会执行触发器,除非它提交到数据库中。
-
Leandro,这样的情况就是数据库序列的用途。
标签: python oracle triggers sqlalchemy