PostgreSQL - automatyzacja tabeli

0

Witam,
Mam taką tabelkę:
CREATE TABLEserver_commands"(
"id" serial,
"idcudaka" int4 ,
"idpolecenia" int4 ,
"czas" timestamp ,
"status" char(10) ,
"command" varchar(50) ,
"odpowiedz" varchar(80) ,
"czas2" timestamp ,
PRIMARY KEY ("id")
)

Potrzebuję następującego zachowania kolumny idpolecenia w tabeli server_commands.

Przy każdym dodaniu rekordu do tabeli przydzielony jest mu kolejny numer idpolecenia, ale numeracja jest w ramach każdego cudaka osobno, np.

dodajemy rekord dla cudaka "A" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "A" - otrzymuje on numer 2 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "A" - otrzymuje on numer 3 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 2 (id polecenia)
dodajemy rekord dla cudaka "C" - otrzymuje on numer 1 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 3 (id polecenia)
dodajemy rekord dla cudaka "B" - otrzymuje on numer 4 (id polecenia)

Numer jest inkrementowany od 0 do MAX_NUMBER. Po osiągnięciu MAX_NUMBER kolejnym przydzielonym numerem jest 0.
Przewiduję docelowo MAX_NUMBER jako 99999.

W bazie nie mogą się powtórzyć dwa rekordy, które będą miały jednakowy id_cudaka i idpolecenia. W szczególności przy próbie dodania takiego powtórzonego rekordu - można usuwać ten stary.

Wiecie może jak to zrobić??

Z góry dzięki za pomoc,
pozdrawiam Łukasz

0

tak wiem :d

musisz napisac trigger, ktory dla dodawanego rekordu policzy jakie idpolecenia wstawic

klopot taki ze przy wykonywaniu insert idpolecenia wstawiasz jako null, a trigger zrobi update na tym polu, po wyliczeniu

lub zrobic bardziej skomplikowana procedure wstawiania, ktora

  1. select isnull(max(idpolecenia),0)+1 into @nextIdPolecenia from Tabela where idcudaka=@idcudakaWstawianego
  2. insert into Tabela (..., idpolecenia, ...) values (..., @nextIdPolecenia, ...)
    najlepiej w transakcji to wykonaj, nie wiem jak w postrgesql sa izolowane transakcje, ale musisz sobie zapewnic taki poziom izolacji, ktory zagwarantuje ci ze po wykonaniu select z 1) nikt nie wstawi do tabeli rekordu o rowniez takim idpolecenia
    innymi slowy, juz na etapie select powinienes zablokowac jesli tabele do zapisu, aby nikt inny w tym czasie nie mogl wykonac zapisu
0

PostgreSQL nie posiada niestety takiego poziomu izolacji. Żeby to działało, system musi mieć poziom SERIALIZABLE - blokowanie całej tabeli do tego to lekka przesada. Hehe, nieco śmieszne, ale właśnie to jest ta jedna z nielicznych sytuacji, kiedy postgresowe SNAPSHOT SERIALIZABLE jest niewystarczające. Musisz więc obronić się w inny sposób przed ewentualnością wstawienia rekordu w p. 2. przez inną transakcję - jakiś constraint by nie pomógł?

0

A takie cus nie skroci sprawy?

insert into tabela (...) select 'a', 'b', 'c', isnull(max(idpolecenia),0)+1, 'e', 'f'
from Tabela where idcudaka = ...
0

isnull(max(idpolecenia),0)+1

To nie jest ładne i nadal może powodować problem z dostępem równoległym wielu transakcji (nawet jeśli użyte w jednym zapytaniu). Tzn. albo obronisz się przez wstawienie unique constraint dla idpolecenia - wtedy musisz przygotować się na sporadyczne wywalenie niektórych transakcji (trzeba ponowić), albo użyjesz sekwencji (tj. next_val) do generowania kolejnych id. Wtedy id niekoniecznie będą po kolei, mogą mieć dziury, ale za to zawsze masz zagwarantowane, że insert wejdzie i nic się nie powtórzy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1