Home Page
Articoli
Tips & Tricks
News
Forum
Archivio Forum
Blogs
Sondaggi
Rss
Video
Utenti
Chi Siamo
Contattaci
Username:
Password:
Login
Registrati ora!
Recupera Password
Home Page
Stanze Forum
SQL Server 2000/2005/2008, Express, Access, MySQL, Oracle
Trigger di inserimento
mercoledì 12 aprile 2006 - 16.35
Elenco Threads
Stanze Forum
Aggiungi ai Preferiti
Cerca nel forum
scandian
Profilo
| Newbie
20
messaggi | Data Invio:
mer 12 apr 2006 - 16:35
ciao.
io avrei questo problema.
dovrei creare un trigger su una vista che viene lanciato quando avviene un inserimento.
il problema è che ogni riga nuova aggiunta sulla vista, il trigger dovrebbe richiamare una funzione che gli restituisce un int, ma deve passare a questa funzione dei parametri ricavati dalle colonne dei nuovi campi inseriti.
in oracle sarebbe cosi
CREATE OR REPLACE TRIGGER WKS33_CTRL_TYPES_BI INSTEAD OF INSERT ON WKS33_VT_CTRL_TYPES
FOR EACH ROW
DECLARE
DescrID SYS10_DICTIONARY.DESCR_ID%TYPE;
BEGIN
DescrID := Sys03_Sequences_Next(:NEW.COMPANY_ID,:NEW.SITE_ID,'SYS10_DICTIONARY_VT','DESCR_ID');
INSERT INTO WKS33_CTRL_TYPES ( COMPANY_ID, SITE_ID, CTRL_TYPE_ID, DESCR_ID, STATUS, TIMESTAMP, USER_ID) VALUES ( :NEW.COMPANY_ID, :NEW.SITE_ID, :NEW.CTRL_TYPE_ID, DescrID, NVL(:NEW.STATUS,'E'), NVL(:NEW.TIMESTAMP,NVL(:NEW.ROW_VERSION,0)), :NEW.USER_ID);
INSERT INTO SYS10_DICTIONARY ( COMPANY_ID, SITE_ID, DESCR_ID, LANGUAGE_ID, DESCRIPTION
, USER_ID)
VALUES ( :NEW.COMPANY_ID,:NEW.SITE_ID, DescrID, :NEW.LANGUAGE_ID_SYS10, :NEW.DESCRIPTION
, :NEW.USER_ID);
END;
ma in sql non ho la possibilità di eseguire il trigger di inserimento come in oracle for each row????
lbenaglia
Profilo
| Guru
5.625
messaggi | Data Invio:
mer 12 apr 2006 - 16:43
>ma in sql non ho la possibilità di eseguire il trigger di inserimento
>come in oracle for each row????
Se intendi SQL Server la risposta è no.
Prova a postare un *piccolo* esempio in Transact SQL con la struttura delle tabelle (CREATE TABLE), alcune righe di prova (INSERT INTO) ed il risultato che vorresti ottenere, e vedremo di darti una mano.
Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
scandian
Profilo
| Newbie
20
messaggi | Data Invio:
mer 12 apr 2006 - 16:54
praticamente lo script che dovrei fare è quello scritto sopra, potrei farlo con un ciclo per ogni riga inserita, ma non capisco come richiamare n volte la funzione, passandoci i campi delle nuove righe inserite
lbenaglia
Profilo
| Guru
5.625
messaggi | Data Invio:
mer 12 apr 2006 - 17:19
>praticamente lo script che dovrei fare è quello scritto sopra,
Dato che non conosco il PL/SQL difficilmente potrò aiutarti
>potrei farlo con un ciclo per ogni riga inserita, ma non capisco
>come richiamare n volte la funzione, passandoci i campi delle
>nuove righe inserite
Lavorare row-by-row è la cosa più sbagliata che si possa fare con un RDBMS dato che i db engine sono progettati per offrire le massime prestazioni con operazioni set-based.
Se mi posti l'esempio che ti ho chiesto potremo cercare di individuare insieme una soluzione, altrimenti in bocca al lupo
Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
Ciciu
Profilo
| Senior Member
233
messaggi | Data Invio:
mer 12 apr 2006 - 18:59
Ciao.
Purtroppo è vero... SQLServer ragiona in maniera nettamente differente da Oracle.
Mentre Oracle ci mette a disposizione, for each row, le strutture :new e :old, SQLServer ci mette a disposizione due tabelle virtuali, che sono inserted e deleted.
Queste tabelle possono essere interrogate come qualunque altra tabella ma, ovviamente, NON possono essere aggiornate. Esiste anche la possibilità di effettuare delle join che coinvolgono queste tabelle ed altre tabelle "reali", per esempio per implementare un trigger che controlli l'integrità referenziale prima di una cancellazione.
Tipicamente, per quella che è la mia esperienza, le prime righe da inserire in un trigger di SQLServer sono :
if @@rowcount=0 return
if (select count(*) from inserted)>(select count(*) from deleted)
select @update_type = 'I'
else if (select count(*) from inserted)<(select count(*) from deleted)
select @update_type = 'D'
else if (select count(*) from inserted)=(select count(*) from deleted)
select @update_type = 'U'
La variabile @update_type è un char(1), ed è un surrogato delle booleane "inserted", "updated" e "deleted".
A questo punto, la sola cosa che Ti resta da fare è aprire un cursore sulla inserted (o sulla deleted o sulle due in join, per trappare eventuali update) e, per ogni record, lanciare la Tua procedure e le Tue insert...
declare crsUpd CURSOR local FAST_FORWARD FOR
select isnull(od_parte, '') as ODParte, isnull(od_vers, '') as ODVers
from inserted
open crsUpd
FETCH NEXT FROM crsUpd INTO @ODParte, @ODVers
WHILE @@FETCH_STATUS = 0
begin
-- Uso @ODParte e @ODVers
FETCH NEXT FROM crsUpd INTO @ODParte, @ODVers
end;
if cursor_status('local', 'crsUpd')>=0 close crsUpd
deallocate crsUpd
Altra differenza : i cursori di Oracle sono tipicamente "locali" al trigger. Quelli di SQLServer sono tipicamente "globali". Se un trigger si schianta su un trigger globale, quandorientrerainel trigger lo troverai aperto...
Per evitare casini, io ho sempre usato triggers definiti locali e, soprattutto, definiti FAST FORWARD.
Spero Ti sia utile.
Ciao - Fabio
Fabio G
lbenaglia
Profilo
| Guru
5.625
messaggi | Data Invio:
mer 12 apr 2006 - 21:18
>Tipicamente, per quella che è la mia esperienza, le prime righe
>da inserire in un trigger di SQLServer sono :
>
> if @@rowcount=0 return
>
>if (select count(*) from inserted)>(select count(*) from deleted)
> select @update_type = 'I'
>else if (select count(*) from inserted)<(select count(*) from
>deleted)
> select @update_type = 'D'
>else if (select count(*) from inserted)=(select count(*) from
>deleted)
> select @update_type = 'U'
E' possibile definire singolarmente uno o più trigger di insert, delete ed update rendendo superflui quei controlli.
>A questo punto, la sola cosa che Ti resta da fare è aprire un
>cursore sulla inserted (o sulla deleted o sulle due in join,
>per trappare eventuali update) e, per ogni record, lanciare la
>Tua procedure e le Tue insert...
Perché?
E' possibile scrivere un singolo comando di INSERT (o UPDATE o DELETE) senza la necessità di definire cursori, semplicemente facendo le dovute JOIN con le tabelle virtuali INSERTED e DELETED.
>Altra differenza : i cursori di Oracle sono tipicamente "locali"
>al trigger. Quelli di SQLServer sono tipicamente "globali".
Questo era vero fino alla versione 7.0 di SQL Server.
I BOL recitano: "Note If neither GLOBAL or LOCAL is specified, the default is controlled by the setting of the default to local cursor database option. In SQL Server version 7.0, this option defaults to FALSE to match earlier versions of SQL Server, in which all cursors were global".
http://msdn.microsoft.com/library/en-us/tsqlref/ts_de-dz_31yq.asp
Ciao!
--
Lorenzo Benaglia
Microsoft MVP - SQL Server
http://blogs.dotnethell.it/lorenzo/
http://italy.mvps.org
Ciciu
Profilo
| Senior Member
233
messaggi | Data Invio:
gio 13 apr 2006 - 09:10
>>Tipicamente, per quella che è la mia esperienza, le prime righe
>>da inserire in un trigger di SQLServer sono :
>>
>> if @@rowcount=0 return
>>
>>if (select count(*) from inserted)>(select count(*) from deleted)
>> select @update_type = 'I'
>>else if (select count(*) from inserted)<(select count(*) from
>>deleted)
>> select @update_type = 'D'
>>else if (select count(*) from inserted)=(select count(*) from
>>deleted)
>> select @update_type = 'U'
>
>E' possibile definire singolarmente uno o più trigger di insert,
>delete ed update rendendo superflui quei controlli.
Hai perfettamente ragione. Ma, per logiche simili, è (spesso) più manutenibile un trigger che si occupa dei tre aggiornamenti, piuttosto che tre trigger... Se sei costretto a fare una modifica alla logica di funzionamento, Ti ritroveresTi a doverla replicare su 3 trig. Ovviamente questo è un discorso impossibile da generalizzare : di volta in volta bisogna verificare la strada migliore...
>
>>A questo punto, la sola cosa che Ti resta da fare è aprire un
>>cursore sulla inserted (o sulla deleted o sulle due in join,
>>per trappare eventuali update) e, per ogni record, lanciare la
>>Tua procedure e le Tue insert...
>
>Perché?
>E' possibile scrivere un singolo comando di INSERT (o UPDATE
>o DELETE) senza la necessità di definire cursori, semplicemente
>facendo le dovute JOIN con le tabelle virtuali INSERTED e DELETED.
Anche in questo caso, è necessario verificare caso per caso... E' possibile che esistano (ed esistono, credimi !) casi in cui non riesci a ricondurre la logica di un trigger ad una "banale" istruzione SQL... Certo è che nei casi in cui è possibile ricondurre il tutto ad una serie di comandi SQL legati a queste tabelle virtuali, le performances del trigger ne beneficiano enormemente...
>
>>Altra differenza : i cursori di Oracle sono tipicamente "locali"
>>al trigger. Quelli di SQLServer sono tipicamente "globali".
>
>Questo era vero fino alla versione 7.0 di SQL Server.
>I BOL recitano: "Note If neither GLOBAL or LOCAL is specified,
>the default is controlled by the setting of the default to local
>cursor database option. In SQL Server version 7.0, this option
>defaults to FALSE to match earlier versions of SQL Server, in
>which all cursors were global".
>
http://msdn.microsoft.com/library/en-us/tsqlref/ts_de-dz_31yq.asp
Devo darTi una triste notizia... L'installazione che ho in locale di SQLServer 2005 (Developer Edition) è assolutamente standard (non conoscendo benissimo il prodotto dal punto di vista strettamente sistemistico ho fatto l'installazione in modalità "Next,Next,Next") : ho subito verificato la configurazione dei cursori sul database e.... Default Cursor è su GLOBAL !!! Del resto, a pensarci bene, è quello che dicono i BOL : se nella dichiarazione del cursore non specifichi alcuno scope, viene preso il default del database (GLOBAL, per l'appunto). Solo nella versione 7, l'assenza di modificatori veniva presa come FALSE, poiché l'impostazione a libello di DB era probabilmente differente, in quanto richiedeva True/False per determinare se utilizzare cursori globali. Questa, almeno, è la mia interpretazione di quanto hai riportato...
Questo
>
>Ciao!
Cia'
Fabio
>
>--
>Lorenzo Benaglia
>Microsoft MVP - SQL Server
>
http://blogs.dotnethell.it/lorenzo/
>
http://italy.mvps.org
Fabio G
Torna su
Stanze Forum
Elenco Threads
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?
Dopo esserti registrato potrai chiedere
aiuto sul nostro
Forum
oppure aiutare gli altri
Consulta le
Stanze
disponibili.
Registrati ora !