Witam! Z MSSQL mam do czynienia od niedawna - wcześniej był Firebird.
Natknąłem się na taki oto problem: mam kilkadziesiąt tabel, zaistniała potrzeba monitorowania wprowadzanych i edytowanych danych. Całość zrobiłem na triggerach i działa. Chciałbym jednak zrobić coś uniwersalnego - gdyż każda zmiana w bazie pociąga za sobą edycję triggera. Najprościej by było jeśli trigger wywołałby procedurę z 3 parametrami - nazwa tabelki, tabela inserted,tabela updated. Niestety nie wiem jak przekazać w parametrach tabele tymczasowe inserted/updated.
Robiłem też próby w samym triggerze - wylistowanie wszystkich pól, odszukanie tych które się zmieniły:
BEGIN varchar(64) -- tutaj nazwa tabeli = 'areas' -- zmienne pomocnicze varchar(50) varchar(1) VARCHAR() VARCHAR() DECLARE cur INSENSITIVE CURSOR FOR select col.name from sysobjects obj inner join syscolumns col on obj.id = col.id where obj.name = @tabela
OPEN cur -- analiza wszystkich kolumn WHILE 1 = 1 BEGIN FETCH cur INTO @colname <0 BREAK
=FROM Deleted) =FROM Inserted)
if (@oldValue!=@newValue) EXECUTE InsertLog 1,@tabela,@colname,@opmode,@newValue,@oldValue
END
DEALLOCATE cur END
Działa,oraz SELECTnie zwracają wartości kolumny, lecz jej nazwę. Czy da sie temu jakoś zaradzić?
Moje pytania: 1.aby pobrały prawidłowe wartości - ZAKŁADAM, że za każdym razem aktualizowany/wkładany jest 1 wiersz? 2. Czy i jak można to wszystko zapisać w procedurze i np w kilku tabelkach w triggerach tylko wywołać EXECUTE nazwaproc nazwa_tabelki,updated,inserted ? 3. Jak pobrać wewnątrz triggera nazwę tabeli której on dotyczy (aby weliminować= 'areas')?
pozdrawiam
AMP
MSSQL, Trigger, rejestrowanie zmian, tabele updated i inserted
Witam! Z MSSQL mam do czynienia od niedawna - wcześniej był Firebird.
Natknąłem się na taki oto problem: mam kilkadziesiąt tabel, zaistniała potrzeba monitorowania wprowadzanych i edytowanych danych. Całość zrobiłem na triggerach i działa. Chciałbym jednak zrobić coś uniwersalnego - gdyż każda zmiana w bazie pociąga za sobą edycję triggera. Najprościej by było jeśli trigger wywołałby procedurę z 3 parametrami - nazwa tabelki, tabela inserted,tabela updated. Niestety nie wiem jak przekazać w parametrach tabele tymczasowe inserted/updated.
Robiłem też próby w samym triggerze - wylistowanie wszystkich pól, odszukanie tych które się zmieniły:
BEGIN varchar(64) -- tutaj nazwa tabeli = 'areas' -- zmienne pomocnicze varchar(50) varchar(1) VARCHAR() VARCHAR() DECLARE cur INSENSITIVE CURSOR FOR select col.name from sysobjects obj inner join syscolumns col on obj.id = col.id where obj.name = @tabela
OPEN cur -- analiza wszystkich kolumn WHILE 1 = 1 BEGIN FETCH cur INTO @colname <0 BREAK
=FROM Deleted) =FROM Inserted)
if (@oldValue!=@newValue) EXECUTE InsertLog 1,@tabela,@colname,@opmode,@newValue,@oldValue
END
DEALLOCATE cur END
oraz nie zwracają wartości kolumny, lecz jej nazwę. Czy da sie temu jakoś zaradzić?
Moje pytania: aby pobrały prawidłowe wartości - ZAKŁADAM, że za każdym razem aktualizowany/wkładany jest 1 wiersz? 2. Czy i jak można to wszystko zapisać w procedurze i np w kilku tabelkach w triggerach tylko wywołać EXECUTE nazwaproc nazwa_tabelki,updated,inserted ? 3. Jak pobrać wewnątrz triggera nazwę tabeli której on dotyczy (aby = 'areas')?
AMP pisze:
Na pewno trzeba użyć dynamicznego SQLa. Coś w stylu: SET=+ ' FROM Deleted')
Ja niedawno podszedłem do problemu zupełnie inaczej. Generuję kod trigera na podstawie nazwy monitorowanej tabeli, który nie odwołuje się do tabel systemowych, nie potrzebuje dynamicznego SQLa, kursorów itp.
Pozdrawiam
Witam! Z MSSQL mam do czynienia od niedawna - wcześniej był Firebird.
Natknąłem się na taki oto problem: mam kilkadziesiąt tabel, zaistniała potrzeba monitorowania wprowadzanych i edytowanych danych. Całość zrobiłem na triggerach i działa. Chciałbym jednak zrobić coś uniwersalnego - gdyż każda zmiana w bazie pociąga za sobą edycję triggera. Najprościej by było jeśli trigger wywołałby procedurę z 3 parametrami - nazwa tabelki, tabela inserted,tabela updated. Niestety nie wiem jak przekazać w parametrach tabele tymczasowe inserted/updated.
Robiłem też próby w samym triggerze - wylistowanie wszystkich pól, odszukanie tych które się zmieniły:
BEGIN varchar(64) -- tutaj nazwa tabeli = 'areas' -- zmienne pomocnicze varchar(50) varchar(1) VARCHAR() VARCHAR() DECLARE cur INSENSITIVE CURSOR FOR select col.name from sysobjects obj inner join syscolumns col on obj.id = col.id where obj.name = @tabela
OPEN cur -- analiza wszystkich kolumn WHILE 1 = 1 BEGIN FETCH cur INTO @colname <0 BREAK
=FROM Deleted) =FROM Inserted)
if (@oldValue!=@newValue) EXECUTE InsertLog 1,@tabela,@colname,@opmode,@newValue,@oldValue
END
DEALLOCATE cur END
oraz nie zwracają wartości kolumny, lecz jej nazwę. Czy da sie temu jakoś zaradzić?
Moje pytania: aby pobrały prawidłowe wartości - ZAKŁADAM, że za każdym razem aktualizowany/wkładany jest 1 wiersz? 2. Czy i jak można to wszystko zapisać w procedurze i np w kilku tabelkach w triggerach tylko wywołać EXECUTE nazwaproc nazwa_tabelki,updated,inserted ? 3. Jak pobrać wewnątrz triggera nazwę tabeli której on dotyczy (aby = 'areas')?
!
AMP : Nie rozumien w czym problem?
Odpowiednie tabele nazywaja sie juz inserted/updated/deleted; nazwa tabeli na ktorej trigger dotyczny nie moze byc zmienna, skladnia definicji triggera okresla czy jest on przy/po/zamiast oraz jaki rodzaj akcji wstawienie/zmiana/usuniecie.
Gdzie Create or alter trigger nazwa_triggera on nazwa_tabeli after delete ?
Triggery trzeba projektowac bardzo ostroznie; kod powinien byc jak najprostszy i minimalny (czyli bez kursorow); Funkcjonalnosci dla roznych wariantow for/after/instead of oraz on insert/update/delete powinny byc napisane w osobnych triggerach; w przeciwnym wypadku bardzo spadnie wydajnosc albo nawet bedzie sie zakleszczac.
Na pewno trzeba użyć dynamicznego SQLa. Coś w stylu: =+ ' FROM Deleted')
- Pokaż cytowany tekst -
To już testowałem. EXEC nie "widzi" tabeli Deleted.
Skoro tak się nie da w ostateczności będę musiał wszystkie zapytania do bazy robić za pomocą procedur - ale wtedy wracam do na start - bo znów będzie tyle procedur ile monitorowanych tabel.