[MSSQL] Jak zabezpieczyc pole przed zmiana
Adam - 24-12-2006 00:37
[MSSQL] Jak zabezpieczyc pole przed zmiana
Witam, zalozmy ze mam tabele i w tej tabeli kolumne STATUS. Wartosci w kolumnie status moga sie zmieniac tylko rosnąco. Jak po stronie bazy danych zrealizowac zabezpieczenie przed zmiana w dół - tak zeby ze statusu na przykład 5 nie dalo sie zejsc na status 4. Baza to MSSQL. Moglbym co prawda poslugiwac sie procedurami i to za ich pomoca robic wrzucanie rekordów oraz update i to w nich (procedurach) zawrzec taka obsluge ale interesuje mnie rozwiazanie dla zwykłego UPDATE. Triggery? Ale jak?
select @status_przed = status from tabela select @status_po = status from insert if @status_po < @status_przed begin co rob? :) end
Prosze o pomoc
-- Pozdrawiam
Adam - 24-12-2006 00:37
Dnia Sun, 17 Dec 2006 20:16:10 +0100, Adam napisał(a):
> select @status_przed = status from tabela > select @status_po = status from insert > if @status_po < @status_przed > begin > co rob? :) > end
OK, juz wiem. No chyba ze jest lepsze rozwiazanie to z przyjemnoscia poslucham.
create trigger costam on tabela.baza for update as begin
declare @st_old int, @st_new int
select @st_old=status from deleted select @st_new=status from inserted
if(@st_new<@st_old) begin rollback end
end
Marcin A. Guzowski - 24-12-2006 00:37
Adam napisał(a): > OK, juz wiem. No chyba ze jest lepsze rozwiazanie to z przyjemnoscia > poslucham. > > create trigger costam on tabela.baza > for update > as > begin > > declare > @st_old int, > @st_new int > > select @st_old=status from deleted > select @st_new=status from inserted > > if(@st_new<@st_old) > begin > rollback > end > > end
Nie jest to dobrze napisany kod triggera. Każdy trigger odpala się raz dla całej transakcji - musi być więc przystosowany do operacji na zbiorach (sytuacja update'u kilku rekordów), żadne przypisywanie do zmiennych i instrukcje warunkowe IF nie wchodzą więc w grę (chyba że robisz to w kursorze, ale rzeźby nie zakładamy).
-- Pozdrawiam, Marcin Guzowski http://guzowski.info
adam - 24-12-2006 00:37
Marcin A. Guzowski napisał(a):
> Nie jest to dobrze napisany kod triggera. Każdy trigger odpala się raz > dla całej transakcji - musi być więc przystosowany do operacji na > zbiorach (sytuacja update'u kilku rekordów), żadne przypisywanie do > zmiennych i instrukcje warunkowe IF nie wchodzą więc w grę (chyba że > robisz to w kursorze, ale rzeźby nie zakładamy).
Wtrace sie - jak powinien wygladac taki trigger dla updateu wielu rekordów i to bez kursora?
Marcin A. Guzowski - 24-12-2006 00:37
adam napisał(a): > Marcin A. Guzowski napisał(a): > >> Nie jest to dobrze napisany kod triggera. Każdy trigger odpala się raz >> dla całej transakcji - musi być więc przystosowany do operacji na >> zbiorach (sytuacja update'u kilku rekordów), żadne przypisywanie do >> zmiennych i instrukcje warunkowe IF nie wchodzą więc w grę (chyba że >> robisz to w kursorze, ale rzeźby nie zakładamy). > > Wtrace sie - jak powinien wygladac taki trigger dla updateu wielu > rekordów i to bez kursora?
Podobno przykład wart jest tysiąca słów, więc:
CREATE TABLE tabela ( wiersz int IDENTITY(1,1) PRIMARY KEY, poleA int, poleB int, status int )
zadanie jak w pierwszym poście w wątku: zabezpieczyć się przed zmianą wartości status z większej na mniejszą (czyli jeżeli nastąpi taka próba - cały update ma być wycofany).
Trigger (typu AFTER) powinien wyglądać tak:
CREATE TRIGGER trig_status ON tabela FOR UPDATE AS BEGIN IF EXISTS( SELECT 1 FROM tabela T INNER JOIN deleted D ON (T.wiersz = D.wiersz and T.status < D.status) ) BEGIN ROLLBACK TRAN RAISERROR(N'Nieobsługiwana zmiana statusu.',11,1) END END
-- Pozdrawiam, Marcin Guzowski http://guzowski.info
Krzysztof - 24-12-2006 00:37
> Podobno przykład wart jest tysiąca słów, więc: > > CREATE TABLE tabela > ( > wiersz int IDENTITY(1,1) PRIMARY KEY, > poleA int, > poleB int, > status int > ) > > zadanie jak w pierwszym poście w wątku: zabezpieczyć się przed zmianą > wartości status z większej na mniejszą (czyli jeżeli nastąpi taka > próba - cały update ma być wycofany). > > Trigger (typu AFTER) powinien wyglądać tak: > > CREATE TRIGGER trig_status ON tabela > FOR UPDATE > AS > BEGIN > IF EXISTS( > SELECT 1 FROM tabela T INNER JOIN deleted D > ON (T.wiersz = D.wiersz > and T.status < D.status) > ) > BEGIN > ROLLBACK TRAN > RAISERROR(N'Nieobsługiwana zmiana statusu.',11,1) > END > END > > Mam pytanie czy jeśli jest to wykonywane w transakcji (tryb inny niz read uncommited) triger (after) bedzie widzial nowe dane w tabeli "tabela T" czy tez ze wzgledu na transakcje nie bedzie ich widzial i trzeba czytac nie z "tabela T" tylko z "inserted"?
Krzysztof
PS. sprawdzilbym to sam ale nie mam teraz sql'a pod reka a mnie to nurtuje.
-- Wysłano z serwisu OnetNiusy: http://niusy.onet.pl
Marcin A. Guzowski - 24-12-2006 00:37
Krzysztof napisał(a): >> Podobno przykład wart jest tysiąca słów, więc: >> >> CREATE TABLE tabela >> ( >> wiersz int IDENTITY(1,1) PRIMARY KEY, >> poleA int, >> poleB int, >> status int >> ) >> >> zadanie jak w pierwszym poście w wątku: zabezpieczyć się przed zmianą >> wartości status z większej na mniejszą (czyli jeżeli nastąpi taka >> próba - cały update ma być wycofany). >> >> Trigger (typu AFTER) powinien wyglądać tak: >> >> CREATE TRIGGER trig_status ON tabela >> FOR UPDATE >> AS >> BEGIN >> IF EXISTS( >> SELECT 1 FROM tabela T INNER JOIN deleted D >> ON (T.wiersz = D.wiersz >> and T.status < D.status) >> ) >> BEGIN >> ROLLBACK TRAN >> RAISERROR(N'Nieobsługiwana zmiana statusu.',11,1) >> END >> END >> >> > Mam pytanie czy jeśli jest to wykonywane w transakcji (tryb inny niz read > uncommited) triger (after) bedzie widzial nowe dane w tabeli "tabela T" czy tez > ze wzgledu na transakcje nie bedzie ich widzial i trzeba czytac nie z "tabela T" > tylko z "inserted"?
Trigger wywoływany jest na koniec transakcji (stąd AFTER) i będąc jej częścią widzi wszystkie zmiany w niej dokonane. Widzi więc już zmodyfikowane rekordy w tabeli T (czyli aktualność tabeli T jest taka sama jak tabeli inserted). Natomiast aby pobrać dane sprzed momentu otwarcia transakcji, trzeba czytać tabelę deleted (co z resztą ma miejsce w przedstawionym przeze mnie przykładzie).
-- Pozdrawiam, Marcin Guzowski http://guzowski.info
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
Zdalny =?ISO-8859-2?Q?dost=EAp_do_MSSQL_bez_zarz=B1dzani?==?ISO-8859-2?Q?a?=
[MSSQL] =?ISO-8859-2?Q?zgodno=B6ci_z_licencjami_Microsoft_?==?ISO-8859-2?Q?SQL_Server?=
[MSSQL 2k] - jak =?ISO-8859-2?Q?pod=B3=B1czy=E6_serwer_na_?==?ISO-8859-2?Q?porcie_innym_ni=BF_1433=3F?=
MSSQL Express czy Oracle Express
MSSQL 2005 i uruchamianie procedury o =?ISO-8859-2?Q?okre=B6lone?==?ISO-8859-2?Q?j_godzinie?=
[MSSQL] ACCESS - SQL =?ISO-8859-2?Q?B=B3ad_w_konwersji_lic?==?ISO-8859-2?Q?zb?=
[MSSQL 2000] =?ISO-8859-2?Q?wywo=B3anie_procesu_z_poziomu_?==?ISO-8859-2?Q?job=27a?=
[MSSQL 2K] =?ISO-8859-2?Q?Wp=B3yw_ustawie=F1_regionalnych_?==?ISO-8859-2?Q?serwera_na_zapytania?=
Pobierananie danych z innej bazy danych w MSSQL
Migracja MSSQL 2005 CTP na 2005 Express
zanotowane.pldoc.pisz.plpdf.pisz.plmelooonka.opx.pl
Cytat
Decede mihi sole - nie zasłaniaj mi słonca. Gdy kogoś kochasz, jesteś jak stworzyciel świata - na cokolwiek spojrzysz, nabiera to kształtu, wypełnia się barwą, światłem. Powietrze przytula się do ciebie, choćby był mróz, a ty masz w sobie tyle radości, że musisz ją rozdawać wokoło, bo się w tobie nie mieści Hoc fac - tak czyń. A tergo - od tyłu; z tyłu. I czarne włosy posiwieją. Safona |
|