[postgres] update i duplicate key
Arkadiusz 'nare' Kindziuk - 22-06-2007 00:00
[postgres] update i duplicate key
Co należy zrobić aby działało z unikalnym indeksem na vo? Przyszedł mi na myśl tylko trigger który kaskadowo będzie zmieniał po 1 rekordzie, ale to dosyć brzydkie, itp.
CREATE TABLE tbl( id INTEGER PRIMARY KEY, vo INTEGER NOT NULL DEFAULT 0 --UNIQUE );
CREATE OR REPLACE FUNCTION tbl_ins(INTEGER, INTEGER) RETURNS VOID AS $$ DECLARE lid ALIAS FOR $1; lvo ALIAS FOR $2; cnt integer; BEGIN SELECT COUNT(*) INTO cnt FROM tbl WHERE vo=lvo; IF cnt <> 0 THEN UPDATE tbl SET vo = vo + 1 WHERE vo >= lvo ; END IF; INSERT INTO tbl(id,vo) VALUES(lid,lvo); END; $$ LANGUAGE plpgsql;
SELECT tbl_ins(1,1); SELECT tbl_ins(3,2); SELECT tbl_ins(2,2); SELECT tbl_ins(0,1); SELECT * FROM tbl ORDER BY id; id | vo ----+---- 0 | 1 1 | 2 2 | 3 3 | 4 (4 rows)
-- Arkadiusz Kindziuk "Zasady zmieniają się całkowicie. Szachy, nie warcaby. Go, nie szachy. Rozumiesz?" (c) Neil Gaiman, "Władca Górskiej Doliny"
=?UTF-8?B?RmlsaXAgUmVtYmlhxYJrb3dza2k=?= - 22-06-2007 00:00
Arkadiusz 'nare' Kindziuk wrote at 2007-06-21 10:21: > Co należy zrobić aby działało z unikalnym indeksem na vo? > Przyszedł mi na myśl tylko trigger który kaskadowo będzie > zmieniał po 1 rekordzie, ale to dosyć brzydkie, itp. > > CREATE TABLE tbl( > id INTEGER PRIMARY KEY, > vo INTEGER NOT NULL DEFAULT 0 --UNIQUE > ); > > CREATE OR REPLACE FUNCTION tbl_ins(INTEGER, INTEGER) RETURNS VOID AS $$ > DECLARE > lid ALIAS FOR $1; > lvo ALIAS FOR $2; > cnt integer; > BEGIN > SELECT COUNT(*) INTO cnt FROM tbl WHERE vo=lvo; > IF cnt <> 0 THEN > UPDATE tbl > SET vo = vo + 1 > WHERE vo >= lvo > ; > END IF; > INSERT INTO tbl(id,vo) VALUES(lid,lvo); > END; > $$ LANGUAGE plpgsql; > > SELECT tbl_ins(1,1); > SELECT tbl_ins(3,2); > SELECT tbl_ins(2,2); > SELECT tbl_ins(0,1); > SELECT * FROM tbl ORDER BY id; > id | vo > ----+---- > 0 | 1 > 1 | 2 > 2 | 3 > 3 | 4 > (4 rows) >
przy większych zbiorach takie coś zabije wydajność.
co do samego kodu, można tak...
CREATE OR REPLACE FUNCTION tbl_ins(INTEGER, INTEGER) RETURNS VOID AS $$ DECLARE lid ALIAS FOR $1; lvo ALIAS FOR $2; tmpid integer; BEGIN IF EXISTS( SELECT * FROM tbl WHERE vo=lvo) THEN FOR tmpid IN SELECT id FROM tbl WHERE vo >= lvo ORDER BY vo DESC FOR UPDATE LOOP UPDATE tbl SET vo = vo + 1 WHERE id = tmpid; END LOOP; END IF; INSERT INTO tbl(id,vo) VALUES(lid,lvo); END; $$ LANGUAGE plpgsql;
Arkadiusz 'nare' Kindziuk - 22-06-2007 00:00
Dnia Thu, 21 Jun 2007 13:48:57 +0200, Filip Rembiałkowski napisał(a): >> SELECT tbl_ins(1,1); >> SELECT tbl_ins(3,2); >> SELECT tbl_ins(2,2); >> SELECT tbl_ins(0,1); >> SELECT * FROM tbl ORDER BY id; >> id | vo >> ----+---- >> 0 | 1 >> 1 | 2 >> 2 | 3 >> 3 | 4 >> (4 rows) >> > > przy większych zbiorach takie coś zabije wydajność. > Jest o tyle dobrze, że mój realny problem jest w drzewie stopnia <= 30. vo jest niezależne dla dzieci każdego ojca, więc zawsze będę miał małe zbiory.
> co do samego kodu, można tak... > > [...] > FOR tmpid IN > SELECT id FROM tbl WHERE vo >= lvo ORDER BY vo DESC > FOR UPDATE > LOOP > UPDATE tbl > SET vo = vo + 1 > WHERE id = tmpid; > END LOOP; > [...]
:-). Dzięki. Sam jeszcze wpadłem na analogiczny myk z sequence (są dziury w numeracji, ale porządek jest zachowany). Siłą rzeczy update też jest sekwencyjny.
-- Arkadiusz Kindziuk "Zasady zmieniają się całkowicie. Szachy, nie warcaby. Go, nie szachy. Rozumiesz?" (c) Neil Gaiman, "Władca Górskiej Doliny"
zanotowane.pldoc.pisz.plpdf.pisz.pleffulla.pev.pl
|
[PostgreSQL] - jak =?ISO-8859-2?Q?zabezpieczy=E6_interesy_tw?==?ISO-8859-2?Q?=F3rcy_systemu_=3F=3F=3F?=
postgresql - int/int
postgresql Select count(*) czy raczej Select count(ID)
[PostgreSQL] jak =?ISO-8859-2?Q?pobra=E6_warto=B6=E6_zwracan?==?ISO-8859-2?Q?=B1_przez_funkcj=EA=3F?=
[postgresql] kilka =?ISO-8859-2?Q?rekord=F3w_subquery_jako_?==?ISO-8859-2?Q?string?=
[PostgreSQL] Jak =?ISO-8859-2?Q?po=B3=B1czy=E6_funkcje_z_w?==?ISO-8859-2?Q?idokiem?=
Postgres - replikcja master-master
Dopasowanie do "najlepszego" dopasowania :) [ PostgreSQL]
Problemy z =?ISO-8859-2?Q?instalacj=B1_PostgreSQL_na_syste?==?ISO-8859-2?Q?mach_Windows?=
=?ISO-8859-2?Q?[psql]_Polskie_t=B3umaczenie_?= =?ISO-8859-2?Q?licencji_BSD_dla_PostgreSQL=3F?=
zanotowane.pldoc.pisz.plpdf.pisz.pllunadance.htw.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 |
|