I am writing an app that has a kanban-style card view, similar to Trello or Jira .
I am trying to write a Postgres trigger + procedure so that, on insert, update or delete, position values are updated to reflect the new ordering.
I am a novice with postgres (and particularly with triggers/procedures) so I am a bit stuck on how to achieve this.
I have the following tables:
create table lists (
id INT GENERATED BY DEFAULT AS IDENTITY UNIQUE NOT NULL,
name text,
PRIMARY KEY (id)
);
create table cards (
id INT GENERATED BY DEFAULT AS IDENTITY UNIQUE NOT NULL,
listId INT NOT NULL,
content text,
position INT,
PRIMARY KEY (id),
FOREIGN KEY (listId) REFERENCES lists(id)
);
When a Card
is DELETE
ed, INSERT
ed or UPDATE
ed with a given position
, all the other Card
s belonging to the same List
must have their position
updated to reflect the updated ordering.
ie given the below data:
-- cards
| id | listId | content | position |
|----|--------|---------|----------|
| 1 | 1 | A | 1 |
| 2 | 1 | B | 2 |
| 3 | 1 | C | 3 |
If I were to perform the following operation:
UPDATE cards SET position = 2 WHERE id = 3;
The final data should update like so:
-- cards
| id | listId | content | position |
|----|--------|---------|----------|
| 1 | 1 | A | 1 |
| 3 | 1 | C | 2 |
| 2 | 1 | B | 3 |
I think I can accomplish this with a DB trigger and a procedure. The trigger will fire on INSERT
, UPDATE
, DELETE
, but I am not sure how the procedure should be written.
CREATE OR REPLACE PROCEDURE update_order()
LANGUAGE plpgsql
AS $$
DECLARE
BEGIN
-- how do I update the position field without triggering infinite loop?
COMMIT
END $$;
CREATE TRIGGER update_order
AFTER INSERT OR UPDATE OR DELETE
ON "cards"
FOR EACH ROW WHERE listId = NEW.listId
EXECUTE PROCEDURE update_order()
I think that triggers are not suitable for you due to the fact that this will cause an infinite loop. My suggestion is to create a regular function that needs to be called after every modification of the cards
table. The function will update the position
column from the cards
table, sorting rows by column position
and modified
(you need to add).
CREATE OR REPLACE FUNCTION update_order() RETURNS void LANGUAGE plpgsql AS $$
BEGIN
with ordered_cards AS
(select *, row_number() over() from (select * from cards ORDER BY position, modified DESC) t)
update cards set position = ordered_cards.row_number from ordered_cards where cards.id = ordered_cards.id;
END
$$;
select update_order();
Demo in DBfiddle
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.