I have successfully solved situation regarding swapping rows by value here what still work excellent.
But by using this function I see some lacks of functionality in mean of
This handles the tabbing order by a set of triggers+ associated functions.
brred for a particular brkalk will cause all values between the old and new values to be rotated, either up or down.brred values above the OLD value (for the same brkalk) to be decremented (shifted down)brred values above the NEW value (for the same brkalk) to be incremented (shifted up)To avoid recursively updating forever, one extra bit of information per row is needed: the flipflag (which should only be touched by the triggers, not by the application code. It could be hidden from the application by means of a view)
ALTER TABLE kalksad1 ADD COLUMN flipflag boolean DEFAULT false;
-- This should be an UNIQUE constraint
-- , but that would need to be deferrable.
CREATE INDEX ON kalksad1 (brkalk,brred);
-- Trigger functions for Insert/update/delete
CREATE function rotate_brred()
RETURNS TRIGGER AS $body$
BEGIN
UPDATE kalksad1 fr
SET brred = brred +1
, flipflag = NOT flipflag -- alternating bit protocol ;-)
WHERE NEW.brred < OLD.brred
-- AND OLD.flipflag = NEW.flipflag -- redundant condition
-- AND OLD.brkalk = NEW.brkalk
AND fr.brkalk = NEW.brkalk
AND fr.brred >= NEW.brred
AND fr.brred < OLD.brred
AND fr.kalk_id <> NEW.kalk_id -- exlude the initiating row
;
UPDATE kalksad1 fr
SET brred = brred -1
, flipflag = NOT flipflag
WHERE NEW.brred > OLD.brred
-- AND OLD.flipflag = NEW.flipflag
-- AND OLD.brkalk = NEW.brkalk
AND fr.brkalk = NEW.brkalk
AND fr.brred <= NEW.brred
AND fr.brred > OLD.brred
AND fr.kalk_id <> NEW.kalk_id
;
RETURN NEW;
END;
$body$
language plpgsql;
CREATE function shift_down()
RETURNS TRIGGER AS $body$
BEGIN
UPDATE kalksad1 fr
SET brred = brred -1
, flipflag = NOT flipflag -- alternating bit protocol ;-)
WHERE fr.brred > OLD.brred
AND fr.brkalk = OLD.brkalk
;
RETURN NEW;
END;
$body$
language plpgsql;
CREATE function shift_up()
RETURNS TRIGGER AS $body$
BEGIN
UPDATE kalksad1 fr
SET brred = brred +1
, flipflag = NOT flipflag -- alternating bit protocol ;-)
WHERE fr.brred >= NEW.brred
AND fr.brkalk = NEW.brkalk
;
RETURN NEW;
END;
$body$
language plpgsql;
-- Triggers for Insert/Update/Delete
-- ONLY for the case where brkalk is NOT CHANGED
CREATE TRIGGER shift_brred_u
AFTER UPDATE OF brred ON kalksad1
FOR EACH ROW
WHEN (OLD.flipflag = NEW.flipflag AND OLD.brkalk = NEW.brkalk AND OLD.brred <> NEW.brred)
EXECUTE PROCEDURE rotate_brred()
;
CREATE TRIGGER shift_brred_d
AFTER DELETE ON kalksad1
FOR EACH ROW
EXECUTE PROCEDURE shift_down()
;
CREATE TRIGGER shift_brred_i
BEFORE INSERT ON kalksad1
FOR EACH ROW
EXECUTE PROCEDURE shift_up()
;
-- Test it
UPDATE kalksad1
SET brred = 2
WHERE brkalk = 2
AND brred = 4;
SELECT * FROM kalksad1
ORDER BY brkalk, brred;
RESULT:
UPDATE 1
kalk_id | brkalk | brred | description | flipflag
---------+--------+-------+---------------------------+----------
36 | 1 | 1 | text index 36 doc 1 row 1 | f
37 | 1 | 2 | text index 37 doc 1 row 2 | f
26 | 2 | 1 | text index 26 doc 2 row 1 | f
43 | 2 | 2 | text index 43 doc 2 row 4 | f
30 | 2 | 3 | text index 30 doc 2 row 2 | t
42 | 2 | 4 | text index 42 doc 2 row 3 | t
12 | 2 | 5 | text index 12 doc 2 row 5 | f
46 | 3 | 1 | text index 46 doc 3 row 1 | f
47 | 3 | 2 | text index 47 doc 3 row 2 | f
32 | 4 | 1 | text index 32 doc 4 row 1 | f
38 | 5 | 1 | text index 38 doc 5 row 1 | f
39 | 5 | 2 | text index 39 doc 5 row 2 | f
(12 rows)