Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

PHP + MYSQL em Duplicate KEY ainda aumentam a INDEX KEY


ok sim, agora eu me lembro deste problema. Certa vez, havia um cara que queria fazer inserções, mas cada inserção tinha que ser em incrementos de 100 se você pudesse imaginar, começando @1000. E tivemos que envolver tudo em um proc armazenado para ter um local de vulnerabilidade. Seu problema surgiu e tirou a numeração dele por 1 ou mais.

Ao envolvê-lo, poderíamos ter um objetivo de fazê-lo, com um bloqueio, e manter o valor auto_inc com ALTER TABLE

A outra abordagem que eu disse a ele foi ter uma tabela incrementadora, bloquear a linha 1, obter o valor nessa linha, usá-lo, atualizar essa tabela inc em 100. desbloquear.

O tempo todo estávamos rindo de problemas de TOC. Acho que ele só gostou de múltiplos de 10, idk

Editar:

Esquema:

-- drop table ocd_nextnums;
create table ocd_nextnums
(   -- id table for nextnum, for the OCD impaired
    tableName varchar(100) not null,
    nextnum int not null
    -- won't bother with indexes, go for it if you want
)engine=INNODB; -- note engine type

insert ocd_nextnums(tableName,nextnum) values('thing',1);
insert ocd_nextnums(tableName,nextnum) values('some_other_table',1);

-- drop table thing;
create table thing
(   id int primary key, -- NOT an auto_increment, but is a PK
    email varchar(100) not null,
    version varchar(20) not null,
    lastupdate datetime not null,
    UNIQUE KEY (email)
)engine=MyIsam;

Procedimento armazenado:

-- drop procedure putInThing;
delimiter $$
create procedure putInThing
(
    email_In varchar(100), version_In varchar(20)
)
BEGIN
    declare toUse int;
    declare theCount int;

    select count(*) into theCount from thing where email=email_In;
    select id into toUse from thing where email=email_In;   -- useful for result set @end
    IF theCount=1 THEN
        -- was there, do UPDATE
        update thing set version=version_In,lastupdate=now() where email=email_In;
    ELSE
        -- new row, do INSERT (please note the FOR UPDATE clause)
        select nextnum into toUse from ocd_nextnums where tableName='thing' FOR UPDATE;
        update ocd_nextnums set nextnum=nextnum+1 where tableName='thing';

        insert thing(id,email,version,lastupdate) values (toUse,email_In,version_In,now());
    end if;
    select toUse;   -- <------- that was your id
END
$$

Teste:

call putInThing('[email protected]','111');
call putInThing('[email protected]','121');
call putInThing('[email protected]','107');
select * from thing;
+----+----------+---------+---------------------+
| id | email    | version | lastupdate          |
+----+----------+---------+---------------------+
|  1 | [email protected] | 111     | 2015-08-14 17:08:10 |
|  2 | [email protected] | 121     | 2015-08-14 17:08:54 |
|  3 | [email protected] | 107     | 2015-08-14 17:08:56 |
+----+----------+---------+---------------------+

call putInThing('[email protected]','101111007'); -- is an update
call putInThing('[email protected]','42'); -- is an update
call putInThing('[email protected]','10007'); -- is an update
call putInThing('[email protected]','1'); -- is an insert

select * from thing;
+----+----------------------+---------+---------------------+
| id | email                | version | lastupdate          |
+----+----------------------+---------+---------------------+
|  1 | [email protected]             | 111     | 2015-08-14 17:08:10 |
|  2 | [email protected]             | 121     | 2015-08-14 17:08:54 |
|  3 | [email protected]             | 10007   | 2015-08-14 17:22:09 |
|  4 | [email protected] | 1       | 2015-08-14 17:22:47 |
+----+----------------------+---------+---------------------+

Da parte do Mysql INNODB do Manual :

Você vai me ver usando isso, provavelmente não. Apenas mostrando. Estou bem com lacunas e dormindo à noite. É por isso que nomeei a primeira tabela como fiz :>