Ik heb het nu redelijk werkend met procedures.
language_get_next_ordinal(): de volgende ordinal in een table. (wellicht enigzins gevaarlijk bij hoge volume inserts, maar dit is niet aan de orde).
language_move(id, x): Verplaats record met id id naar positie x
language_reorder(): Haal gaps uit de tabel. (Bijvoorbeeld na een delete of na een update).
CREATE FUNCTION language_get_next_ordinal() RETURNS integer
AS $$
DECLARE
p_next_ordinal integer;
BEGIN
SELECT count(id)
INTO p_next_ordinal
FROM vdven.language;
RETURN p_next_ordinal;
END;
$$
LANGUAGE plpgsql;
CREATE FUNCTION language_move(f_id integer, f_new_pos integer) RETURNS integer
AS $$
DECLARE
p_rec record;
p_old_pos integer;
p_max_pos integer;
p_done integer := 0;
BEGIN
SELECT ordinal
INTO p_old_pos
FROM vdven.language
WHERE id = f_id;
SELECT COUNT(id)-1
INTO p_max_pos
FROM vdven.language;
IF p_old_pos = f_new_pos THEN
RETURN 0;
END IF;
IF p_max_pos < f_new_pos THEN
RETURN -1;
END IF;
UPDATE vdven.language
SET ordinal = p_max_pos+1
WHERE id = f_id;
IF p_old_pos > f_new_pos THEN
FOR p_rec IN
SELECT id,ordinal
FROM vdven.language
WHERE ordinal >= f_new_pos
AND ordinal < p_old_pos
ORDER BY ordinal DESC
LOOP
UPDATE vdven.language
SET ordinal = ordinal+1
WHERE id = p_rec.id;
p_done := p_done+1;
END LOOP;
ELSEIF p_old_pos < f_new_pos THEN
FOR p_rec IN SELECT id,ordinal FROM vdven.language WHERE ordinal <= f_new_pos AND ordinal > p_old_pos ORDER BY ordinal ASC LOOP
UPDATE vdven.language
SET ordinal = ordinal-1
WHERE id = p_rec.id;
p_done := p_done+1;
END LOOP;
ELSE
RETURN -1;
END IF;
UPDATE vdven.language
SET ordinal = f_new_pos
WHERE id = f_id;
RETURN p_done;
END;
$$
LANGUAGE plpgsql;
CREATE FUNCTION language_reorder() RETURNS integer
AS $$
DECLARE
p_rec record;
p_int integer := 0;
p_done integer := 0;
BEGIN
FOR p_rec IN SELECT id,ordinal FROM vdven.language ORDER BY ordinal ASC LOOP
IF p_int <> p_rec.ordinal THEN
UPDATE vdven.language
SET ordinal = p_int
WHERE id = p_rec.id;
p_done := p_done+1;
END IF;
p_int := p_int+1;
END LOOP;
RETURN p_done;
END;
$$
LANGUAGE plpgsql;
Dit is een realtief complexe oplossing voor een simpel probleem, weet iemand in postgres of sql wellicht een simpelere oplossing?