Increment an SQL table key in one for stored data - mysql

I'm trying to build an script for a database migration and I have a doubt. I have a table which has lots of registers and an integer type key. This key is auto incremental and now beginning with the '1' index.
The problem is that this index has to be occupied by a default value in the new database. So I want to loop database rows to get each index incremented in one, to leave the first place in blank and insert my value into it. I have tried with this statement:
UPDATE `tapp`, (
SELECT #loop := id_App
FROM
tapp
) o
SET id_App = id_App + 1;
However, is trying to update each index starting from the beginning, so when it tries converting the first one to '2' it finds out the second one is already taken and can't make it.
It's important to make the increase in one, because it's a MyIsam database and I also have to update each foreign key one by one. I'm using MySQL.
Please give me a hand!

The easiest way is twofold: After inserting everything into the target table, you make a 2-pass update.
First, you check what the highest number is in the table, then increment it by one and remember it as topnumber.
Then, you update everything to incremental numbers, starting with topnumber. Finally, you update everything, starting with whatever your initial seed is and increment by one each record.
number data
1 "foo"
3 "bar"
10 "snafu"
topnumber becomes 11
After the first pass, the data looks like this:
number data
11 "foo"
12 "bar"
13 "snafu"
After the second pass (and assuming your initial number is 7), the data looks like this:
number data
7 "foo"
8 "bar"
9 "snafu"
UPDATE
Alternatively, instead of updating the numbers to incremental values, you could add the remembered top number to every initial value at the first pass (and so the above sample table would look like this after the first update:
number data
11 "foo"
13 "bar"
23 "snafu"
), and at the second pass, you would decrement all the numbers by the previously stored top number and increment them by 1, which, for our example, would result in the following:
number data
2 "foo"
4 "bar"
11 "snafu"
Using the names in your code snippet, the entire script might look something like this:
/* remember the top ID */
SET #max_id = (SELECT MAX(ID) FROM tapp);
/* increment by the top ID */
UPDATE tapp SET id_App = id_App + #max_id;
/* decrement by the top ID and increment by 1 */
UPDATE tapp SET id_App = id_App - #max_id + 1;

Related

Best way permute values in a unique constrained column in MySQL in a single instruction (or non-complex instruction)

I have a trouble trying to update some data in sql.
I tried to permutate values in a column with unique constraint in a single query.
For example, I have this rows:
id
name
order
300
first
10
500
second
15
The order column has the unique constraint. Now, I want to update the rows to:
id
name
order
300
first
15
500
second
10
In a single query.
I tried to use some stretegies like:
Start transaction.
Save the first order value into a variable A.
Set to null the first order value.
Save the second order value into a variable B.
Update the second order value using the variable A.
Update the first order value using the variable B.
Commit.
But If I have more than once permutation (for example, 10 permutations) the query it's more complex. For that, I want to know if there is another way to do this more generic (for N permutations) and less complex.

increase the value of only one element in a set

I have a column with sets of numbers like 21,8,0,345,... if I wanted to +1 to only one element in the set, for example element 3, would I be able to do that with a mysql query?
I know I can do this with php code (explode the string to an array then update it) but I'm afraid that with multiple updates simultaneously on the same row the values will be rewritten.
First query will set 21,8,1,345 and the second will rewrite it with 21,9,0,345
Replacing the element in question might also not work because some rows have multiple elements with the same value like 2,40,40,41
MySQL supports "SELECT ... FOR UPDATE" specifically for this situation to make sure the row isn't overwritten while you're processing the the row contents.
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
The above link even gives a very similar example (except for exploding the elements, increasing the one you want, and imploding them back together).
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
The better answer, as Tim suggested, is to store this data in a separate table, especially since you have a variable number of items for each row. I don't know how you currently know that you want to update, say, the 3rd item but I'll assume that's known.
Let's say these numbers are temperature readings from various sensors at a "location" and they gradually go up and down. Your main table is "locations" with with fields:
id (int, auto-increment), location_name (varchar), ...
You're then going to create a new table called "readings" with fields:
id (int, auto-increment), location_id (int), temperature (smallint)
The "id" from the first table is going to match up to the "location_id" of many records in "readings".
When you want to add a new temperature reading to a location (I'm assuming you'll have a $location_id and $new_reading variables in PHP):
INSERT INTO readings (location_id, temperature)
VALUES ( $location_id, $new_reading )
(NOTE: You should be properly sanitizing your inputs, using PDO, or other library, but that's out of scope for this answer or I'm going to be here all night. :-) )
Let's say you want to update the 3rd reading for this location, that would mean the "offset" is 2 and you only want to update 1 record so that's what "LIMIT 2, 1" means below. (I tried and failed to find a way to do this in only 1 query; UPDATE does not seem to support offsets, at least not in my version of MySQL.)
SELECT id FROM readings WHERE location_id = 1 ORDER BY id LIMIT 2, 1;
/* Let's say you stored the above result in $reading_id */
UPDATE readings SET temperature = temperature + 1 WHERE id = $reading_id;

How to block auto_increment to set the next number always as maxnumber + 1

I have a table with auto_incremented field.
The way normally auto increment works is it always start with the max value + 1.
For e.g. if I insert two records, auto increment field takes 1 and 2 as the value initially.
Now when I add a third row by explicitly mentioning the id field value as 100.
After this, If I add a fourth record, auto increment value will be 101, not 3.
My Question :
Is there any way in mysql to enforce auto increment to follow its series? If it encounters a duplicate, it can skip that.
I doubt if this can be done. Imagine this scenario: You insert 5 rows with ids 1 through 5 and delete the rows with ids 2 through 4, and end up with two rows, the one with id 1 and id 5. Now you insert another row. What id would you expect the DB to use now, 2, or 6?
I for one wouldn't want the database to do the former, because my program could rely on some primary keys not being there (think a deleted blog post with a unique id. Would you want someone to see a different blogpost when they hit the URL corresponding to that id versus just showing a 404?)
Coming back to your question, the DB doesn't really know the difference between the following two situations:
The row with id = 100 was inserted like you mention, manually.
There existed 100 rows with ids 1 through 100 and rows 3 through 99 were deleted.
Of course, you might have a use-case for recycling ids, but you'll have to do it yourself. But before doing that, make sure you really want it :)

Mysql Auto Increment For Group Entries

I need to setup a table that will have two auto increment fields. 1 field will be a standard primary key for each record added. The other field will be used to link multiple records together.
Here is an example.
field 1 | field 2
1 1
2 1
3 1
4 2
5 2
6 3
Notice that each value in field 1 has the auto increment. Field 2 has an auto increment that increases slightly differently. records 1,2 and 3 were made at the same time. records 4 and 5 were made at the same time. record 6 was made individually.
Would it be best to read the last entry for field 2 and then increment it by one in my php program? Just looking for the best solution.
You should have two separate tables.
ItemsToBeInserted
id, batch_id, field, field, field
BatchesOfInserts
id, created_time, field, field field
You would then create a batch record, and add the insert id for that batch to all of the items that are going to be part of the batch.
You get bonus points if you add a batch_hash field to the batches table and then check that each batch is unique so that you don't accidentally submit the same batch twice.
If you are looking for a more awful way to do it that only uses one table, you could do something like:
$batch = //Code to run and get 'SELECT MAX(BATCH_ID) + 1 AS NEW_BATCH_ID FROM myTable'
and add that id to all of the inserted records. I wouldn't recommend that though. You will run into trouble down the line.
MySQL only offers one auto-increment column per table. You can't define two, nor does it make sense to do that.
Your question doesn't say what logic you want to use to control the incrementing of the second field you've called auto-increment. Presumably your PHP program will drive that logic.
Don't use PHP to query the largest ID number, then increment it and use it. If you do your system is vulnerable to race conditions. That is, if more than one instance of your PHP program tries that simultaneously, they will occasionally get the same number by mistake.
The Oracle DBMS has an object called a sequence which gives back guaranteed-unique numbers. But you're using MySQL. You can obtain unique numbers with a programming pattern like the following.
First create a table for the sequence. It has an auto-increment field and nothing else.
CREATE TABLE sequence (
sequence_id INT NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`sequence_id`)
)
Then when you need a unique number in your program, issue these three queries one after the other:
INSERT INTO sequence () VALUES ();
DELETE FROM sequence WHERE sequence_id < LAST_INSERT_ID();
SELECT LAST_INSERT_ID() AS sequence;
The third query is guaranteed to return a unique sequence number. This guarantee holds even if you have dozens of different client programs connected to your database. That's the beauty of AUTO_INCREMENT.
The second query (DELETE) keeps the table from getting big and wasting space. We don't care about any rows in the table except for the most recent one.

Change AutoIndex number Mysql

In my table I have auto increment id which is having its number like 1 to 66,440 and next number is 88846790 + increment from here till 88846900.
There is no records in between 66440 to 88846790
I want my next auto increment number to be 66441 but its taking 88846791, can you help me in setting next auto increment to 66441,
alter table tablename AUTO_INCREMENT=664441
should do
You can use ALTER TABLE to change the auto_increment value:
ALTER TABLE my_table AUTO_INCREMENT = 66441;
See the MySQL reference for more details.
Remember to reinsert all rows with an id higher than 88846790
If you don't remove rows with a higher ID than 66441,
the change in autoincrement does nothing.
Example:
ID Value
---- --------
1 C
2 A
4 D
50 A
51 C
If I want to change auto increment to 5 I need to remove or re-insert the 50 and 51 first. Because otherwise the next auto increment is gonna be 52 anyway.
Depending on how much and how important the data is, often the best thing to do is: Nothing
Because those primary ID's have relations to other rows, and maybe even web- urls based opn those IDs. This will all fail, unless you create some sort of script.
I had trouble getting this to work in phpMyAdmin, even inputting the query directly. If you browse the table you want to reset the index of, then click Operations, you should be able to set the AUTO_INCREMENT directly under Table options. Then just click Go and you're all set!
Rebutal to all those recommending ALTER:
You cannot reset the counter to a value less than or equal to the
value that is currently in use. For both InnoDB and MyISAM, if the
value is less than or equal to the maximum value currently in the
AUTO_INCREMENT column, the value is reset to the current maximum
AUTO_INCREMENT column value plus one.
-- https://dev.mysql.com/doc/refman/8.0/en/alter-table.html
(That is from the 8.0 manual, but I believe that it has always applied; I think I discovered it in 4.0 days.)
Better than deleting and re-inserting:
Renumber the higher values:
UPDATE t SET id = id - 88846790 + 66440 + 1 WHERE id >= 88846790;
But then comes the hassle of renumbering references to this id. They can use a similar update:
UPDATE other_table SET t_id = t_id - 88846790 + 66440 + 1 WHERE t_id >= 88846790;