“最佳方式”我不知道。
但是,就像在另一个 RDBMS 中一样,为此添加一列是一个很好的解决方案。
处理该列将隐含一些代码,但在 SQLite 中,您可以使用触发器在数据库中实现此逻辑。
这里有一个示例,使用一个后台表和一个执行魔术的视图:
-- Main table, where data belongs
CREATE TABLE _t(n, o);
-- Table view, which will handle all inserts, updates and deletes
CREATE VIEW t AS SELECT * FROM _t;
-- Triggers:
-- Raise error when inserting invalid index (out of bounds or non integer)
CREATE TRIGGER t_ins_err INSTEAD OF INSERT ON t
WHEN NEW.o<1 OR NEW.o>(SELECT COUNT()+1 FROM _t) OR CAST(NEW.o AS INT) <> NEW.o
BEGIN SELECT RAISE(ABORT, 'Invalid index!'); END;
-- Increments all indexes when new row inserted in middle of table
CREATE TRIGGER t_ins INSTEAD OF INSERT ON t
WHEN NEW.o BETWEEN 1 AND (SELECT COUNT() FROM _t)+1
BEGIN
UPDATE _t SET o=o+1 WHERE o>=NEW.o;
INSERT INTO _t VALUES(NEW.n, NEW.o);
END;
-- Insert row in last when supplied index is NULL
CREATE TRIGGER t_ins_last INSTEAD OF INSERT ON t
WHEN NEW.o IS NULL
BEGIN
INSERT INTO _t VALUES(NEW.n, (SELECT COUNT()+1 FROM _t));
END;
-- Decrements indexes when item is removed
CREATE TRIGGER t_del INSTEAD OF DELETE ON t
BEGIN
DELETE FROM _t WHERE o=OLD.o;
UPDATE _t SET o=o-1 WHERE o>OLD.o;
END;
-- Raise error when updating to invalid index
CREATE TRIGGER t_upd_err INSTEAD OF UPDATE OF o ON t
WHEN NEW.o NOT BETWEEN 1 AND (SELECT COUNT() FROM _t) OR CAST(NEW.o AS INT)<>NEW.o OR NEW.o IS NULL;
BEGIN SELECT RAISE(ABORT, 'Invalid index!'); END;
-- Decrements indexes when item is moved up
CREATE TRIGGER t_upd_up INSTEAD OF UPDATE OF o ON t
WHEN NEW.o BETWEEN OLD.o+1 AND (SELECT COUNT() FROM t)
BEGIN
UPDATE _t SET o=NULL WHERE o=OLD.o;
UPDATE _t SET o=o-1 WHERE o BETWEEN OLD.o AND NEW.o;
UPDATE _t SET o=NEW.o WHERE o IS NULL;
END;
-- Increments indexes when item is moved down
CREATE TRIGGER t_upd_down INSTEAD OF UPDATE OF o ON t
WHEN NEW.o BETWEEN 1 AND OLD.o-1
BEGIN
UPDATE _t SET o=NULL WHERE o=OLD.o;
UPDATE _t SET o=o+1 WHERE o BETWEEN NEW.o AND OLD.o;
UPDATE _t SET o=NEW.o WHERE o IS NULL;
END;
-- Tests:
INSERT INTO t(n) VALUES('a1');
INSERT INTO t(n) VALUES('b1');
INSERT INTO t(n) VALUES('c1');
INSERT INTO t(n) VALUES('d1');
INSERT INTO t VALUES('e1', 5);
INSERT INTO t VALUES('z1', 20);
SELECT * FROM t ORDER BY o;
INSERT INTO t VALUES('b2', 2);
SELECT * FROM t ORDER BY o;
DELETE FROM t WHERE n='b1';
SELECT * FROM t ORDER BY o;
UPDATE t SET o=4 WHERE o=2;
SELECT * FROM t ORDER BY o;
UPDATE t SET o=3 WHERE o=5;
SELECT * FROM t ORDER BY o;