Auto Increment Manually - mysql

There is a table with an int field - field_1.
I want to insert a new row.
The field_1 value will be Maximum value from all the entries plus one.
I've tried:
INSERT INTO table (field names, `field_1`)
VALUES (values, '(SELECT MAX(field_1) FROM table)');
I get '0' in the field_1.
I know I can do it in separate queries.
Is there a way to perform this action with one query? I mean one call from php.
I have an auto-increment field 'id' and I want to add 'position' field. I want to be able to make changes in position but the new item will always have highest position

Whatever it is that you are trying to do, it will not work, because it is not guaranteed to be atomic. So two instances of this query executing in parallel are guaranteed to mess each other up at some random point in time, resulting in skipped numbers and duplicate numbers.
The reason why databases offer auto-increment is precisely so as to solve this problem, by guaranteeing atomicity in the generation of these incremented values.
(Finally, 'Auto Increment Manually' is an oxymoron. It is either going to be 'Auto Increment', or it is going to be 'Manual Increment'. Just being a smart ass here.)
EDIT (after OP's edit)
One inefficient way to solve your problem would be to leave the Position field zero or NULL, and then execute UPDATE table SET Position = Id WHERE Position IS NULL. (Assuming Id is the autonumber field in your table.)
An efficient but cumbersome way would be to leave the Position field NULL when you have not modified it, and give it a value only when you decide to modify it. Then, every time you want to read the Position field, use a CASE statement: if the Position field is NULL, then use the value of Id; otherwise, use the value of Position.
EDIT2 (after considering OP's explanation in the comments)
If you only have 30 rows I do not see why you are even trying to keep the order right on the database. Just load all rows in an array, programmatically assign incrementing values to any Position fields that are found to be NULL, and when the order of the rows in your array changes, just fix the Position values and update all 30 rows in the database.

Try this:
INSERT INTO table (some_random_field, field_to_increment)
SELECT 'some_random_value', IF(MAX(field_to_increment) IS NULL, 1, MAX(field_to_increment) + 1)
FROM table;
Or this:
INSERT `table`
SET
some_random_field = 'some_random_value',
field_to_increment = (SELECT IF(MAX(field_to_increment) IS NULL, 1, MAX(field_to_increment) + 1) FROM table t);
P.S. I know it's 4 years late but I was looking for the same answer. :)

ALTER TABLE table_name AUTO_INCREMENT = 1 allows the database to reset the AUTO_INCREMENT to:
MAX(auto_increment_column)+1
It does not reset it to 1.
This prevents any duplication of AUTO_INCREMENT values. Also, since
AUTO_INCREMENT values are either primary/unique, duplication would
never happen anyway. The method to do this is available for a reason.
It will not alter any database records; simply the internal counter so
that it points to the max value available. As stated earlier by
someone, don't try to outsmart the database... just let it handle it.
It handles the resetting of AUTO_INCREMENT very well. See gotphp

Related

auto increment column increments even when there is NO new row insertion

I have created a table which is having a conditional row insertion function,so at times new rows are not inserted into the column. Here the problem is, even when row insertion is failed the auto_inc column increments and thus the values stored in that will be some what like this:
Sl No.
1
2
4
7
8
9
it looks really messy please help.thanks in advance
A sspencer7593 has mentioned
"The behavior of AUTO_INCREMENT is fairly well defined. And it's primarily designed to generate unique values. It's not designed to prevent gaps."
However as MySQL allows you to assign a custom value to AUTO_INCREMENT column a workaround to your scenario would be to assign value of Max(SI_No)+1 while inserting the row. In this case you will ensure that you would add next incremented value only when row is actually inserted.
Typical syntax would look like
INSERT INTO TABLENAME (ID,SOMECOLUMN) VALUES ((SELECT MAX(ID)+1 NEWID FROM TABLENAME) ,someValue);
Note:- it would prevent gaps you are seeing during insertion and last row deletion cases . If you delete row in between you would still see the Gaps but I think this should be OK with you
Can you please add your php code and table structure? I think insert query is being executed even condition fails.
This is expected behavior with INSERT ... SELECT, or when an INSERT statement fails or is rolled back. The innodb_autoinc_lock_mode setting can also influence the behavior. We will also see this when a value is supplied for the AUTO_INCREMENT column, or when rows are deleted.
The behavior of AUTO_INCREMENT is fairly well defined. And it's primarily designed to generate unique values. It's not designed to prevent gaps.
got an answer for this question thanks to # juergen d
this should be the query:
String queryString = "INSERT INTO hcl_candidates(SL_No,candidate,phone,pan,mailid) SELECT MAX(SL_No)+1, ?, ?, ?, ? FROM hcl_candidates";

SQL Trigger for comparing on insert

I'd like to write a trigger that checks top value in column (table consists of 4 double columns and one of them acts as a primary key (value within that field should always be bigger then previous entry)). Now is there a way to compare a top value of id column with new value that should be inserted, and rollback transaction if value of new id is equal or lower then previous top value(by using sql triggers of course).
Thank you in advance.
One and most easy way I found is to check if you get any result. I mean this:
if (SELECT COUNT(*) FROM tbl_name WHERE id = id_you_want_check >= 1) {
rollback;
}
If you know to use triggers in mysql or whatever DBMS you are using (look at the documentation of your DBMS).
PS: As said Colin, next time post your SQL DBMS to easily find an appropiate solution for you. ;)

How mysql AUTO_INCREMENT works?

In mysql AUTO_INCREMENT doc, I didn't find the detail explanation about how it pick new id on insert,
Is it cache a "max number" key, or find the smallest ID which is not in use? any reference to the source code?
EDIT:
I had test it, looks like it will not reuse deleted item's ID, But I'm not sure. I want use id as a timestamp for ordering, so I must 100% certain it is so, that means this logic explanation should has a trusted reference, either in source code or in mysql doc..
It will NOT pick the smallest number not in use. It will always increment one to the last ID it had assigned. This will be a constant time operation. (As opposed to picking the smallest number not in use which would be linear time*).
For example, if you insert 10 rows, then delete the 5th row. The next inserted row will get an ID of 11, and NOT 5.
This operation can quite easily be optimized to be constant time as well (at the time of insertion) by accepting a penalty at the time of deletion. However, that is not what MySQL does.
Yes, that's the way auto_increment works.
The value will be incremented for each new row
The value is unique, duplicates are not possible
If a row is deleted, the auto_increment column of that row will not be re-assigned.
The auto_increment value of the last inserted row can be accessed using the mySQL function LAST_INSERT_ID() but it must be called right after the insert query, in the same database connection.
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html

Will all numbers be 100% unique in a table if to use this simple algorithm?

My goal is to insert a new and unique(unique is very important) number into a MySQL table on the server every time upon an event on a user's machine, using ajax.
So, server's part on user's event is doing this (using php):
Finds a maximum value from the column in the db,
Adds 10 to a maximum value,
this is a new and unique (bigger than a maximum) value, we insert insert into a table.
Will all numbers be unique and go like 1, 11, 21, 31, if it starts from 1? I'm curious if inserting into the Table finishes before it starts performing another queue and coule be like 1, 11, 21, 21, 31, 41?
If it theoretically works like this (ordered by time)
find max value from the column for the first user
find max a value from the column for the second user (it will be the same)
insert a (max+10) for the first user into the same table
insert a (max+10) for the second user into the same table (it will be the same), then the results will be the same, and 1 value could be repeated twice or even more...
So, the question is: will all numbers be 100% unique?
Depending on this I have to choose which algorithm to use for creating unique numbers.
Added:
Is it possible to be sure with this algorythm and without using autoincrements? Autoincrement is used for another column. Holes between numbers are OK. The only requirement is that numbers should be different, but with some "delta" that is more than one. Sorry I didn't notice about that in my question. Thank you.
Unless you have a very specific reason against it, I recommend using AUTO_INCREMENT - it will scale much better and actually leave fewer "holes" in the sequence of numbers than your approach.
And you are correct - your approach will not actually guarantee uniqueness in concurrent environment. One way to make your algorithm work is to have a UNIQUE constraint on your field (if it is not already PRIMARY KEY) and then repeatedly attempt to insert a new value - if it fails just generate a new value and try again and it will eventually succeed.
Use an auto incrementing column in the db
It sounds like you want to use autoincrement.
If you're using auto-increment on a separate column, you can still emulate it with something like the following.
insert into mytable (
column1,
column2,
fake_auto_incr
) select
'value for column1',
'value for column2',
max (fake_auto_incr) + 1
from mytable
Because the insert is a transactional statement, ACID databases will ensure the max+1 trick is always one greater then the current top value.
Keep in mind you'll need a slight adjustment for that to work on an empty table, since the query will return NULL in that case. This should suffice:
insert into mytable (
column1,
column2,
fake_auto_incr
) select
'value for column1',
'value for column2',
coalesce (max (fake_auto_incr), 0) + 1
from mytable
This forces the initial value to 1 on an empty table, otherwise it uses the next available value.

MySQL intelligent default value

I'm adding stuff to a MySQL table, and each item has a position that it shows up in my system like a question number.
I could find out what the largest position is before adding a new question, +1 it, and then add it - but I was wondering if there's a more intelligent way that doesn't require a second query.
Something like INSERT INTO questions (id, position) values (0, MAX(position)).
This field is not the primary key, auto_increment is of no use to this situation.
I cannot use position as the key, because the key relates to many other things, and the position can be changed at any time.
I am a pretty confident MySQL query writer, so please don't offer any suggestions other than the question asked - I know of plenty of alternatives, this is just a syntax question.
I'm sure you get my drift!
Cheers.
Use auto_increment like most other folk do?
This is the intelligent way because it concurrency safe.
Best way would be to change the field properties within MySQL, meaning let MySql do the work without providing input.
TABLE TableName CHANGE position position INT( 11 ) NOT NULL AUTO_INCREMENT
Now when inserting, do not provide any values for this field.
INSERT INTO questions (var1, var2) values (val1,val2)
MySQL will automatically increment the position value. You can set current counter as well as reset if need be. This way you are not running any quarries at all.
something like this should work
INSERT INTO questions (id, position) SELECT 0, MAX(position)+1 FROM questions;
Obviously, you will need to handle the 0 value, as in set it for something appropriate, i just copied that value off your example.
You could also create a stored procedure to use in the query, or even have a trigger which determines the MAX(position), adds one and stores it in your newly created row.
Quite alot of options there, I would go for the above solution though (with a index on position)
There's no way to set a default value to a specific calculation, it seems.