如何在创建自引用行时避免使用max(id)

时间:2015-11-28 17:01:04

标签: mysql auto-increment

我有一个MySQL表

id | ref_id

其中ref_id应该等于其中一个可用的id值(包括同一行中的一个)。 id也会自动递增。

在存储过程中,我想在此表中添加一行ref_id = id。我可以通过

来做到这一点
DECLARE prev_id INT;
SELECT MAX(id) INTO prev_id FROM `table`;
INSERT INTO table (ref_id) VALUES (prev_id + 1)

但为此目的使用MAX(id)not recommended。我应该使用LAST_INSERT_ID()代替。但是如果我还没有插入任何其他内容,我怎么能这样做呢?

1 个答案:

答案 0 :(得分:1)

模式

-- drop table selfie;
create table selfie
(   id int auto_increment primary key,
    thing varchar(40) not null,
    ref_id int not null,
    descr varchar(40) not null
);

存储过程

drop procedure if exists spInsertOneSelfRef;

DELIMITER $$
create procedure spInsertOneSelfRef
(   pThing varchar(40),
    pRef int, -- 0 if to self, >0 if not 
    pDescr varchar(40)
)
begin
  insert selfie(thing,ref_id,descr) values (pThing,pRef,pDescr);
    -- Moment A
  IF (pRef=0) then
    -- self-reference request, ditch the zero that was just inserted
    set @theId:= last_insert_id();
    update selfie set ref_id=@theId where id=@theId;
    -- MOMENT B
  END IF;
end
$$
DELIMITER ;

测试

-- truncate table selfie;
call spInsertOneSelfRef('frog',0,'a selfie'); -- 
call spInsertOneSelfRef('cat',1,''); -- 
call spInsertOneSelfRef('mouse',2,''); 
call spInsertOneSelfRef('dog',3,''); -- 
call spInsertOneSelfRef('abcd',0,'a selfie'); -- 

查看结果

select * from  selfie;
+----+-------+--------+----------+
| id | thing | ref_id | descr    |
+----+-------+--------+----------+
|  1 | frog  |      1 | a selfie |
|  2 | cat   |      1 |          |
|  3 | mouse |      2 |          |
|  4 | dog   |      3 |          |
|  5 | abcd  |      5 | a selfie |
+----+-------+--------+----------+

可以通过一些调整将null插入ref_id。并且在存储过程中列出的时刻A和时刻B之间的瞬间处理并发控制。我将这些留给读者,除非你恳求我这样做。

选项B(ref_id架构更改)

drop table selfie;
create table selfie
(   id int auto_increment primary key,
    thing varchar(40) not null,
    ref_id int, -- NULL means I have no parent
    descr varchar(40) not null,
    constraint fk_blahblah foreign key (ref_id) references selfie(id)
);

测试

call spInsertOneSelfRef('abcd',null,'no parent'); -- good
call spInsertOneSelfRef('pqrs',1,''); --  good
call spInsertOneSelfRef('zzz',44,''); -- bad (as expected, FK failure)

视图

+----+-------+--------+-----------+
| id | thing | ref_id | descr     |
+----+-------+--------+-----------+
|  1 | abcd  |   NULL | no parent |
|  2 | pqrs  |      1 |           |
+----+-------+--------+-----------+

哦,我现在有一个父母,没问题,更新ref_id列