stworzyłem coś takiego:
begin;
create table test (
id integer
);
insert into test(id) select generate_series(1,100);
create or replace function trg_check_max_4_updated_records()
returns trigger as $$
declare
counter_ integer := 0;
tablename_ text := 'temptable';
begin
raise notice 'trigger fired';
select count(42) into counter_
from pg_catalog.pg_tables where tablename = tablename_;
if counter_ = 0 then
raise notice 'Creating table %', tablename_;
execute 'create temporary table ' || tablename_ || ' (counter integer) on commit drop';
execute 'insert into ' || tablename_ || ' (counter) values(1)';
execute 'select counter from ' || tablename_ into counter_;
raise notice 'Actual value for counter= [%]', counter_;
else
execute 'select counter from ' || tablename_ into counter_;
execute 'update ' || tablename_ || ' set counter = counter + 1';
raise notice 'updating';
execute 'select counter from ' || tablename_ into counter_;
raise notice 'Actual value for counter= [%]', counter_;
if counter_ > 4 then
raise exception 'Cannot change more than 4 rows in one trancation';
end if;
end if;
return new;
end; $$ language plpgsql;
create trigger trg_bu_test before
update on test
for each row
execute procedure trg_check_max_4_updated_records();
update test set id = 10 where id <= 1;
update test set id = 10 where id <= 2;
update test set id = 10 where id <= 3;
update test set id = 10 where id <= 4;
update test set id = 10 where id <= 5;
rollback;
Główną ideą jest, aby mieć na spust „przed aktualizacją dla każdego wiersza, który tworzy” (jeśli to konieczne) tabeli tymczasowej (czyli spadła u koniec transakcji). W tej tabeli znajduje się tylko jeden wiersz z jedną wartością, czyli liczba zaktualizowanych wierszy w bieżącej transakcji. Dla każdej aktualizacji wartość jest zwiększana. Jeśli wartość jest większa niż 4, transakcja zostaje zatrzymana.
Ale myślę, że to niewłaściwe rozwiązanie twojego problemu. Na czym polega problem polegający na dwukrotnym uruchomieniu takiego błędnego zapytania, o którym piszesz, więc zmienisz 8 wierszy. Co powiesz na usuwanie wierszy lub ich obcinanie?
Zastanawiam się, czy użyć normalnego zapytania + wycofania, jeśli liczba dotkniętych błędów jest większa niż maksymalna, i wydaje się, że jest to najlepsza wartość, jaką widzę. Dobrze w 99% + będą dobre zapytania (4 zaktualizowane wiersze max), ale jest to tylko dodatkowe zabezpieczenie dla systemu. Tabela z tym "problemem" jest dość olbrzymia i krytyczna dla systemu, więc przywracanie jej po takim błędnym pytaniu może być bolesne dla wszystkich. Dziękuję wszystkim za odpowiedzi. Nie wiem, który z nich zaakceptować, ponieważ wszystkie one są pomocne :) – sbczk
Dlaczego chcesz to zrobić? Być może jest to o wiele łatwiejszy sposób niż takie dziwne zapytanie. Co więcej ... używanie licznika (jeśli było to możliwe) będzie wolniejsze, gdy tabela rośnie. –
Więc myślisz, że gdy zmienisz maksymalnie 4 wiersze, zapytanie nie może być źle wpisane? To brzmi jak jakieś fałszywe poczucie bezpieczeństwa. –