1

Temat: Numeracja sekwencji PostgreSQL

Witam,
stworzyłem niewielką bazę danych, której głównym celem jest rezerwacja numerów upoważnień.
Klient do bazy pracuje z pomocą LibreOffice. Zależało mi na tym żeby numer sekwencji skoro jest nadawany automatycznie odpowiadał numerowi upoważnienia. Jednak zauważyłem że czasem powstaje luka w numeracji i nie wiem czym to jest spowodowane i jak to zdiagnozować oraz poprawić błąd. Czy spotkaliście się z takim problemem? Czy to np. więcej niż jeden użytkownik w tym samym czasie wykonuje zapis do bazy i to jest przyczyną?
Dziekuje za każda podpowiedź.
Pozdrawiam

2

Odp: Numeracja sekwencji PostgreSQL

Zerknij na tabele do której zapisujesz upoważnienia, czy nie ma w niej testowania (walidacji) wartości pola poczytaj o CONSTRAINT lub tabela ma dopisany unikatowy index.

Jeśli np masz w tabeli pole  z warunkiem not null to jeśli użytkownik nie uzupełni tego pola i spróbuje dodać rekord do bazy to taka operacja się nie uda, a sekwencja przesunie licznik o 1 więc będziesz miał dziurę w numeracji.

3

Odp: Numeracja sekwencji PostgreSQL

-- Table: kontrola

-- DROP TABLE kontrola;

CREATE TABLE kontrola
(
  nr_upowaznienia serial NOT NULL,
  data_upowaznienia date,
  termin_wazn_upo date,
  nr_sprawy character varying(20) DEFAULT ((('WI.057.'::character varying)::text || (currval('kontrola_nr_upowaznienia_seq'::regclass))::text) || '.2015'::text),
  data_rozp_kontroli date,
  data_zakon_kontroli date,
  id_os_upowazn character varying(10) NOT NULL,
  id_os_kontrol integer,
  id_podm_kontrol integer,
  CONSTRAINT kontrola_pkey PRIMARY KEY (nr_upowaznienia),
  CONSTRAINT kontrola_id_os_kontrol_fkey FOREIGN KEY (id_os_kontrol)
      REFERENCES osoba_kontrol (id_os_kontrol) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT kontrola_id_os_upowazn_fkey FOREIGN KEY (id_os_upowazn)
      REFERENCES osoba_upowazn (nr_legitym) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT kontrola_id_podm_kontrol_fkey FOREIGN KEY (id_podm_kontrol)
      REFERENCES podmiot_kontrol (id_podm_kontrol) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITHOUT OIDS;
ALTER TABLE kontrola OWNER TO em_postgresql;
GRANT ALL ON TABLE kontrola TO em_postgresql;
GRANT SELECT, UPDATE, INSERT ON TABLE kontrola TO public;
.

Nr upoważnienia posiada warunek NOT NULL ale jest to klucz główny i nadaje się automatycznie , więc użytkownik nie wpisuje go. W formularzu do wypełniania danych w Libre Office wyświetlam jedynie jego wartość w polu tekstowym, żeby użytkownik widział jaki numer nadał mu system.

4

Odp: Numeracja sekwencji PostgreSQL

a pole id_os_upowazn czy zawsze będzie miało wartość. Czy istnieje szansa na to, że użytkownik go nie poda. Do tego to varchar (10) wiec jeśli jakimś cudem ktoś poda 11 znakowy ciąg to posgresql też zgłosi błąd.

Masz też trzy klucze obce (FOREIGN KEY), więc jeśli użytkownik coś w nie wprowadzi to postgresql najpierw sprawdzi czy wartości wprowadzane są w tabelach obcych i zgłosi błąd jeśli coś jest nie zgodne.

Ogólnie mówiąc przejrzyj sobie logi na serwerze, a na pewno znajdziesz inserty które dały błąd.

5

Odp: Numeracja sekwencji PostgreSQL

Niestety użytkownik może spróbować dokonać zapisu bez uzupełnienia pola id_os_upowazn , ale nie przekroczy wartości 11 znaków , gdyż wybiera je z listy rozwijanej. Sprawdzę metodą prób i błędów co się stanie jak użytkownik będzie wprowadzać błędne dane do kluczy obcych. Co do sprawdzenia logów serwera to na razie nie wiem jak to zrobić, bo serwer linuksowy na którym działa baza jest zamkniętym rozwiązaniem i ja mam tylko dostęp webowy. Pozwala mi on na uruchamianie usług,przeglądanie raportów itp. i nie mam bezpośredniego dostępu do katalogów. Bazę stworzyłem za pomocą pgAdmina.

6

Odp: Numeracja sekwencji PostgreSQL

jest jeszcze jedno rozwiązanie:
należy zmienić pole  nr_sprawy by nie miało wartości domyślnej
napisać funkcję i trigger after insert, który nada polu  nr_sprawy wartość ((('WI.057.'::character varying)::text || (currval('kontrola_nr_upowaznienia_seq'::regclass))::text) || '.2015'::text).

Wtedy trigger wywoła sekwecje tylko dla rekordów, które udało się wpisać do bazy danych inne (błędne) nie będą zmieniały numeru sekwencji.

7

Odp: Numeracja sekwencji PostgreSQL

Ok poczytam o tym. A gdzie taką funkcję się wkleja tzn. jej kod i jak się uruchamia?

8

Odp: Numeracja sekwencji PostgreSQL

załączam prosty skrypt ale działa do testów i nauki wystarczy

CREATE SEQUENCE kontrola_nr_sprawy_seq START 1 CACHE 1;

select setval ('kontrola_nr_sprawy_seq'::regclass,(select COALESCE(max(nr_upowaznienia),0)+1 from kontrola));

CREATE OR REPLACE FUNCTION f_kontrola() RETURNS trigger AS
$BODY$begin
update kontrola
   set nr_sprawy=format('WI.057.%s.%s',nextval('kontrola_nr_sprawy_seq'::regclass) ,extract ('year' from current_date))
where nr_upowaznienia=new.nr_upowaznienia;
return null;
end;$BODY$
LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;

ALTER TABLE kontrola ALTER COLUMN nr_sprawy DROP DEFAULT;

CREATE TRIGGER kontrola_tr AFTER INSERT ON kontrola FOR EACH ROW EXECUTE PROCEDURE f_kontrola();

9

Odp: Numeracja sekwencji PostgreSQL

ERROR:  syntax error at or near "NOT"
LINE 12: LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;
                                   ^


********** Błąd **********

ERROR: syntax error at or near "NOT"
Stan SQL:42601
Znak:469

co oznacza ten błąd?

10

Odp: Numeracja sekwencji PostgreSQL

którą wersje postgresa masz?
zobacz czy masz dodany język plpgsql - select * from pg_language;
Jeśli nie to otwórz go poleceniem CREATE LANGUAGE plpgsql;

11

Odp: Numeracja sekwencji PostgreSQL

Mam wersję  8.1.3-11. Rozumiem że ten język standardowo nie jest dodany?

Ostatnio edytowany przez PablooD (2015-03-03 16:15:21)

12

Odp: Numeracja sekwencji PostgreSQL

13

Odp: Numeracja sekwencji PostgreSQL

Język udało się zainicjować. Teraz pojawia się komunikat że jest błąd składni:

ERROR:  syntax error at or near "NOT"
LINE 15: LANGUAGE plpgsql VOLATILE NOT LEAKPROOF;
                                   ^


********** Błąd **********

ERROR: syntax error at or near "NOT"
Stan SQL:42601
Znak:472

14

Odp: Numeracja sekwencji PostgreSQL

z definicji funkcji usuń "NOT LEAKPROOF"

15

Odp: Numeracja sekwencji PostgreSQL

ok poszło, ten parametr miał na celu nie wyświetlanie błędów przez funkcję?

16

Odp: Numeracja sekwencji PostgreSQL

17

Odp: Numeracja sekwencji PostgreSQL

Ok dzięki za linki. Poczytam.
Ustawiłem wszystko wg Twoich instrukcji ale pojawił się kolejny błąd podczas dodawanie rekordu.
Stan SQL: 23502

ERROR: null value in column "nr_upowaznienia" violates not-null constraint

Klienta do bazy danych mam wykonanego w pakiecie Libre Office. Widocznie po tych zmianach nie wykonuje poprawnie polecenia insert. Wiele rzeczy w tym pakiecie wykonuje się za pomocą kreatora i póki co nie wiem gdzie poprawić ten błąd i szukam rozwiązania w google smile

18

Odp: Numeracja sekwencji PostgreSQL

Kolejny błąd smile

Stan SQL: 42883

ERROR: function format("unknown", bigint, double precision) does not exist
  Wskazówka: No function matches the given name and argument types. You may need to add explicit type casts.
  Gdzie: SQL statement "update kontrola set nr_sprawy=format('WI.057.%s.%s',nextval('kontrola_nr_sprawy_seq'::regclass) ,extract ('year' from current_date)) where nr_upowaznienia= $1 "
PL/pgSQL function "f_kontrola" line 2 at SQL statement

19

Odp: Numeracja sekwencji PostgreSQL

W tym przypadku rozumiem że nie pasuje mu typ parametru.? To chodzi o zwracany parametr czy samą zmienna nr_sprawy? Można to jakoś odgórnie ustawić deklaracji funkcji?

20

Odp: Numeracja sekwencji PostgreSQL

Sprawdz w PgAdminie jaki typ zwraca poniższe polecenie
SELECT 'WI.057.%s.%s',nextval('kontrola_nr_sprawy_seq'::regclass)

Jeśli ten typ jest inny niż text to w funksji format jako pierwszy parametr wpisz:
'WI.057.%s.%s',nextval('kontrola_nr_sprawy_seq'::regclass)::text

poczytaj dokumentacje funkcji format tam wszystko jest napisane

21

Odp: Numeracja sekwencji PostgreSQL

Błędy już się nie pojawiają, ale niestety wygląda na to że ten wyzwalacz nie działa bo nie zapisuje się nic do nr_sprawy , a dodatkowo jeśli użytkownik wpisze numer do kluczy obcych to i tak licznik sekwencji upoważnienia  przeskoczy a to zakładaliśmy na początku że nie będzie miało miejsca.

22

Odp: Numeracja sekwencji PostgreSQL

wyślij mi wszystko co do tej pory zrobiłeś
jak zbudowana jest tabela (polecenie create table), jak zbudowana jest funcja triggera i sam trigger (polecenie create trigger).

popatrzę i zobaczymy co nie działa

23

Odp: Numeracja sekwencji PostgreSQL

24

Odp: Numeracja sekwencji PostgreSQL

Nie mogłem sobie poradzić z funkcją format więc ją usunąłem i wstawiłem to:

CREATE SEQUENCE kontrola_nr_sprawy_seq START 1 CACHE 1;

select setval ('kontrola_nr_sprawy_seq'::regclass,(select COALESCE(max(nr_upowaznienia),0)+1 from kontrola));

CREATE OR REPLACE FUNCTION f_kontrola() RETURNS trigger AS
$BODY$begin
update kontrola
   set nr_sprawy='WI.057.' || nextval('kontrola_nr_sprawy_seq'::regclass)::text ||'.'|| extract ('year' from current_date)::text
where nr_upowaznienia=new.nr_upowaznienia;
return null;
end;$BODY$
LANGUAGE plpgsql VOLATILE;

ALTER TABLE kontrola ALTER COLUMN nr_sprawy DROP DEFAULT;

CREATE TRIGGER kontrola_tr AFTER INSERT ON kontrola FOR EACH ROW EXECUTE PROCEDURE f_kontrola();


Przy poprawnym wprowadzaniu danych wszystko się zapisuje ok, natomiast jeśli spowoduję błąd to próba zapisu przesunie licznik nr_upoważnienia i jeszcze tego nie potrafię przeskoczyć.

Ostatnio edytowany przez PablooD (2015-04-07 12:15:08)

25

Odp: Numeracja sekwencji PostgreSQL

Wszystko jest tak jak powinno być.
Pole nr_upowaznienia zmienia się zgodnie z sekwencją, która jest przyporządkowana do tego pola, ale użytkownik widzi pole nr_sprawy, które jest kontrolowane przez trigger z wykorzystaniem sekwencji kontrola_nr_sprawy_seq. Zauważ że nawet nieudany insert nie powoduje zmiany kolejności numeracji w polu nr_sprawy.

Teraz nie możesz zakładać, że wartość z pola nr_sprawy będzie odpowiadało polu nr_upowaznienia.

Aby to poprawić popraw funkcje tak

CREATE OR REPLACE FUNCTION f_kontrola() RETURNS trigger AS
$BODY$
declare
nr integer;
begin
nr := nextval('kontrola_nr_sprawy_seq'::regclass);
update kontrola
   set nr_sprawy='WI.057.' || nr::text ||'.'|| extract ('year' from current_date)::text
       , nr_upowaznienia=nr
where nr_upowaznienia=new.nr_upowaznienia;
return null;
end;$BODY$
LANGUAGE plpgsql VOLATILE;