Jump to content
Phear99

Criar sequences em trigger

Recommended Posts

Phear99

Boas pessoal,

Tenho um pequeno problema. Tenho uma tabela DOCUMENTS, na qual cada documento tem um número e um tipo. A ideia é que cada tipo de documento segue uma numeração independente, logo iria necessitar de uma sequence para cada tipo de documento.

Os tipos de documento existentes constam numa tabela DOCTYPES, e o campo tipo na tabela DOCUMENTS é uma chave estrangeira que referencia a DOCTYPES.

A minha ideia seria criar um trigger que, ao adicionar um novo tipo de documento, criasse uma sequence para cuidar da numeração desse novo tipo:

CREATE OR REPLACE TRIGGER TRG_DOCTYPES_INSERT
    AFTER INSERT ON DOCTYPES
    FOR EACH ROW
  BEGIN
    EXECUTE IMMEDIATE 'CREATE SEQUENCE SEQ_DOCUMENTS_'
      || :NEW.T
      || ' MINVALUE 1 START WITH 1 INCREMENT BY 1 NOCACHE';
  END;

Este código compila na perfeição. Mas, ao fazer:

INSERT INTO DOCTYPES VALUES ('FCT', 'Factura');

recebo a mensagem:

Error starting at line 3 in command:
INSERT INTO DOCTYPES VALUES ('FCT', 'Factura')
Error report:
SQL Error: ORA-04092: cannot COMMIT in a trigger
ORA-06512: at "USER.TRG_DOCTYPES_INSERT", line 2
ORA-04088: error during execution of trigger 'USER.TRG_DOCTYPES_INSERT'
04092. 00000 -  "cannot %s in a trigger"
*Cause:    A trigger attempted to commit or rollback.
*Action:   Rewrite the trigger so it does not commit or rollback.

Existe alguma forma de eu contornar este "cannot COMMIT in a trigger" ou existe alguma maneira mais elegante de eu conseguir uma numeração distinta para cada tipo de documento? 🤔


Programei: VB6, VB.NET, ANSI C, C++, HTML, XHTML, CSS, PHP, ASP, HASKELL, JAVAI'm so good that I quit because the compiler is slower than me.

Share this post


Link to post
Share on other sites
M6

Tanto quanto sei não podes usar statements DDL dentro de um trigger dado que são vistos como commit implicito e ios commits e rollbacks não são permitidos nos triggers.

Podes experimentar usar AUTONOMUS_TRANSACTION para tentar evitar o problema do commit no trigger, mas nunca experimentei pelo que não garanto resultados. :)


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
Phear99

Gostei da ideia e tentei implementar, mas de momento não tenho previlégios suficientes. Estou à espera da resposta do administrador.

Entretanto, aceitam-se mais ideias.


Programei: VB6, VB.NET, ANSI C, C++, HTML, XHTML, CSS, PHP, ASP, HASKELL, JAVAI'm so good that I quit because the compiler is slower than me.

Share this post


Link to post
Share on other sites
mauro.edgar

Sim, faz assim que funciona de certeza:

CREATE OR REPLACE TRIGGER TRG_DOCTYPES_INSERT
    AFTER INSERT ON DOCTYPES
    FOR EACH ROW
DECLARE
    PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
    EXECUTE IMMEDIATE 'CREATE SEQUENCE SEQ_DOCUMENTS_' || :new.t ||
                      ' MINVALUE 1 START WITH 1 INCREMENT BY 1 NOCACHE';
EXCEPTION
    WHEN OTHERS THEN
        NULL;
END;

Share this post


Link to post
Share on other sites
Phear99

Este tópico já é velhinho, já não tem propósito, nem a resposta me é útil, mas visto que nunca cheguei a conseguir resolver isto, vou manter NOT SOLVED com esperança que venha a ajudar alguém.

@mauro.edgar:

Tal como disse no post anterior, não tenho privilégios suficientes para usar AUTONOMOUS_TRANSACTION.


Programei: VB6, VB.NET, ANSI C, C++, HTML, XHTML, CSS, PHP, ASP, HASKELL, JAVAI'm so good that I quit because the compiler is slower than me.

Share this post


Link to post
Share on other sites
joze_n

Tanto quanto sei, contornar a criação de sequences sem conseguir fazer um trigger com o pragma autonomous_transaction é impossível.

A solução, a meu ver é indexares a tua tabela por tipo de documento e número de documento, e geras os códigos à mão, tipo:

select coalesce(max(codigo),0)+1 into novo_codigo from tabela where tipodocumento= :tipo;

Share this post


Link to post
Share on other sites
M6

Tanto quanto sei, contornar a criação de sequences sem conseguir fazer um trigger com o pragma autonomous_transaction é impossível.

A solução, a meu ver é indexares a tua tabela por tipo de documento e número de documento, e geras os códigos à mão, tipo:

select coalesce(max(codigo),0)+1 into novo_codigo from tabela where tipodocumento= :tipo;

Esta técnica só funcionará se o novo_codigo for UNIQUE, caso contrário corre-se o risco de obter clashing the valores.


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
Phear99

Assumindo uma boa prática em que nunca um registo é efectivamente removido, estão sim, isto funcionaria. Mas é uma alternativa muito pouco elegante e robusta. Bastava uma remoção e isto rebentava como fogo de artifício.


Programei: VB6, VB.NET, ANSI C, C++, HTML, XHTML, CSS, PHP, ASP, HASKELL, JAVAI'm so good that I quit because the compiler is slower than me.

Share this post


Link to post
Share on other sites
M6

Assumindo uma boa prática em que nunca um registo é efectivamente removido, estão sim, isto funcionaria. Mas é uma alternativa muito pouco elegante e robusta. Bastava uma remoção e isto rebentava como fogo de artifício.

Mas isso é se se basear a contagem na própria tabela.

Se se recorrer a uma tabela de controlo de indíces, esse problema deixa de existir.


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
Phear99

Isso basicamente seria uma tabela para imitar as sequences  🤔. Não tinha pensado nisso, e não vejo problemas com essa resolução.


Programei: VB6, VB.NET, ANSI C, C++, HTML, XHTML, CSS, PHP, ASP, HASKELL, JAVAI'm so good that I quit because the compiler is slower than me.

Share this post


Link to post
Share on other sites
renafi

Não sei se já resolveste isto ou não, mas não podes executar instruções DDL num trigger... nem com a autonomous transaction...

Os triggers ficam associados às instruções que estão dependentes....  Quer dizer, se depois do insert na tabela, fizeres rollback... já não te servia de nada, porque a criação da sequencia executava, e fazia commit.

A UNICA forma de, se quiseres mesmo, te safares disto é: calendarizar um job para executar a instrução... Mas que não é uma coisa muito bem feita, não é.


Oracle Certified Professional - AdministraçãoOracle Certified Professional - Pl/sqlMCPD - Microsoft Certified Professional DeveloperMCTS - Microsoft Certified Technology Specialist

Share this post


Link to post
Share on other sites
jsWizard

E que tal uma coluna na tabela DOCTYPES chamada DOC_SEQ number(24) not null default 0;

depois, cada vez que vais criar um doc, incrementas este valor e usas no documento. não ?

é que parece-me grande maluqueira o que estão a tentar fazer... adicionar sequências por cada registo novo.. humm.. não me parece bem.

além disso, com a sequência nunca garantes que os documentos fiquem com numeração seguida.. já que a sequência avança sempre, mesmo que dê erro. Por isso ficavam "buracos" na numeração dos documentos. (não sei se é o caso, mas normalmente os documentos legais não podem ter buracos.. por exemplo.. facturas!)

Share this post


Link to post
Share on other sites
M6

jsWizard, essa solução já foi dada em Julho deste ano...


10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites
jsWizard

foi? ups.. não reparei. Mas tive a ler melhor agora e continuo a não ver em lado nenhum esta solução.. será que sou eu ou és tu que estás a ver mal? :confused: (eu dormi pouco hoje.. por isso eventualmente sou eu que estou a ver mal :) )

Share this post


Link to post
Share on other sites
M6
Se se recorrer a uma tabela de controlo de indíces, esse problema deixa de existir.

10 REM Generation 48K!
20 INPUT "URL:", A$
30 IF A$(1 TO 4) = "HTTP" THEN PRINT "400 Bad Request": GOTO 50
40 PRINT "404 Not Found"
50 PRINT "./M6 @ Portugal a Programar."

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.