在 SQL 中插入时更新子索引

Update sub-index when inserting in SQL

我有一个 table 简化后的样子:

group   index    value
1       1        text 1
1       2        text 2
1       3        text 3
2       1        text 4
2       2        text 5
2       3        text 6

Group 是外键,也用于对 table 中的项目进行分组。

索引是用于对组内的项目进行排序的内部索引。

文本只是一个值。

然后如果我执行插入或 运行 执行插入的存储过程

INSERT INTO Table VALUES (1, 2, 'new text')

我想更新第 1 组项目的索引,因此 table 如下所示:

group   index    value
1       1        text 1
1       2        new text (inserted)
1       3        text 2   (index updated)
1       4        text 3   (index updated)
2       1        text 4
2       2        text 5
2       3        text 6

(运行 在 MS SQL-Server 2008 上)

在这个答案中,我假设第一列名称是 grpidx,如 groupindex是SQL.

中的保留字

您可以使用 MAX(idx)+1 公式使用下一个可用的 idx 值,如下所示:

INSERT INTO t1(grp, idx, value)
SELECT 1, IFNULL(MAX(idx),0)+1, 'new text'
FROM   t1
WHERE  grp = 1;

但是这样,大约同时插入的两条记录可能会得到相同的 idx 值。为避免这种情况,您可以在插入记录时锁定 table。你可以通过用 table lock/unlock 语句包装上面的语句来做到这一点:

LOCK TABLES t1;
...
UNLOCK TABLES;

但是,此方法不能在过程中使用。那里的解决方案涉及创建交易和 SELECT ... FOR UPDATE。请注意,您需要 InnoDB Storage 为此:

CREATE PROCEDURE ins_val(IN pgrp int, IN pvalue varchar(200)) 
BEGIN
    DECLARE newidx INT;
    START TRANSACTION;

        SELECT IFNULL(MAX(idx),0)+1
        INTO   newidx
        FROM   t1
        WHERE  grp = pgrp;
        FOR UPDATE;

        INSERT INTO t1(grp, idx, value)
        VALUES (pgrp, newidx, pvalue);

    COMMIT;
END;

请注意,如果您稍后删除记录,这些将在 idx 编号中留下空隙,上述方法将无法再次填充这些空隙。另一方面,如果删除具有最高 idx 值的记录,下一个插入的记录将重新使用该 idx 值。

这是一个您可以使用的存储过程。采用 3 个参数,grp、idx 和值:

CREATE PROCEDURE ReIndex
@grp int,
@idx int,
@value nvarchar(30)
AS
IF NOT EXISTS(SELECT 1 FROM [tbl] WHERE grp = @grp and idx =@idx)
INSERT INTO tbl VALUES (@grp, @idx, @value)
else
update tbl
set idx = idx+1
where
grp =@grp and
idx >= @idx

INSERT INTO tbl VALUES (@grp, @idx, @value)

用法:

exec reindex 1, 2, 'new text'

sqlfiddle: http://sqlfiddle.com/#!3/3323d/11