auto_increment property not working as expected - mysql

I have initialized a database users like this create table users (id not null auto_increment primary key, first_name varchar(256) not null, last_name varchar(256) not null);
However, I can just execute insert into users values (2,'James','Bond'); and no error is thrown. I want to create a table so that the primary key gets auto incremented and one can simply add entries like so: insert into users values ("firstname","lastname"); is this even possible?

When you use the syntax insert into users values ('firstname','lastname'); i.e. you do not specify a list of columns, this implies your VALUES clause will contain values for all columns. This is not related to using auto_increment, it applies to any table.
You can work around this by specifying the columns:
insert into users (firstname, lastname) values ('firstname','lastname');
By omitting id from the list of columns, it should also be omitted from the VALUES clause.
Another form of INSERT syntax supported by MySQL (although it's nonstandard) might be more clear. It also allows you to omit columns you don't want to set in your INSERT statement.
insert into users SET firstname='firstname', lastname='lastname;
If you do include the id column either implicitly or explicitly, you can trigger the auto-increment behavior by using NULL, DEFAULT, or if the sql mode permits it, 0.
If you specify any other value for the id, it overrides the auto-increment.
This is all documented here: https://dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html and related pages linked by that page.

you can name the columns that you want to insert.
But if you have more t columns , you have to define DEFAULT values, so that Mysql knows how to fill the not inserted values
INSERT INTO users (first_name ,last_name ) VALUEs("firstname","lastname");

The fact a column is auto-incrementing doesn't mean you can just ignore it in an insert statement. You could, however, avoid assigning a value to it and letting the auto_increment property handle it by using the default keyword:
insert into users values (default, 'firstname', 'lastname');

Related

Prevent auto increment on duplicated entry?

I have Table called url_info and the structure of the table is:
url_info:
url_id ( auto_increment, primary key )
url ( unique,varchar(500) )
When I insert into table like this:
INSERT INTO url_info(url) VALUES('Tom');
INSERT INTO url_info(url) VALUES('Jerry');
The output is:
1 Tom
2 Jerry
When I insert like this
INSERT INTO url_info(url) VALUES('Tom');
INSERT INTO url_info(url) VALUES('Tom');
INSERT INTO url_info(url) VALUES('Jerry');
The output is
1 Tom
3 Jerry
The auto-increment id is incremented when I try to insert to duplicate entry. I have also tried Insert Ignore
How to prevent it from incrementing when I try to insert a duplicate entry?
It's probably worth creating a stored procedure to insert what you want into the table. But, in the stored procedure check what items you have already in the table. If these match what you're trying to insert, then the query should not even attempt the insert.
Ie. The procedure needs to contain something like this:
IF NOT EXISTS(SELECT TOP 1 url_id FROM url_info WHERE url = 'Tom')
INSERT INTO url_info(url) VALUES('Tom')
So, in your stored procedure, it would look like this (assuming the arguments/variables have been declared)
IF NOT EXISTS(SELECT TOP 1 url_id FROM url_info WHERE url = #newUrl)
INSERT INTO url_info(url) VALUES(#newUrl)
This is expected behaviour in InnoDB. The reason is that they want to let go of the auto_increment lock as fast as possible to improve concurrency. Unfortunately this means they increment the AUTO_INCREMENT value before resolving any constraints, such as UNIQUE.
You can read more about the idea in the manual on AUTO_INCREMENT Handling in InnoDB, but the manual is also unfortunately buggy and doesn't tell why your simple insert will give non-consecutive values.
If this is a real problem for you and you really need consecutive numbers, consider setting the innodb_autoinc_lock_mode option to 0 in your server, but this is not recommended as it will have severe effects on your database (you cannot do any inserts concurrently).
Auto_increment is performed updated by the engine. This is done before hand of checking a value is unique or not. And we can't roll back the operation to get back to former value of auto_increment.
Hence NO to start from where you last read on auto_increment.
And it is not an issue in loosing some intermediate values on auto_increment field.
The MAX value you can store into a SIGNED INT field is 2^31-1 equal to 2,147,483,647. If you read it loud, it sounds 2 billion+.
And I don't think it is small and won't suite your requirement.
CREATE TABLE `url_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=4 ;
When I execute:
INSERT INTO url_info(url) VALUES('Tom');
INSERT INTO url_info(url) VALUES('Tom');
INSERT INTO url_info(url) VALUES('Jerry');
I get:
Make sure you ID column is UNIQUE too.
As the manual says:
A UNIQUE index creates a constraint such that all values in the index
must be distinct. An error occurs if you try to add a new row with a
key value that matches an existing row. This constraint does not apply
to NULL values except for the BDB storage engine. For other engines, a
UNIQUE index permits multiple NULL values for columns that can contain
NULL. If you specify a prefix value for a column in a UNIQUE index,
the column values must be unique within the prefix.

knowing next value from auto increment field mysql java

I want to know the next value of auto increment field
I wanted to test this :
select max(contactid) from contact
and I add 1
but I realized that it can give me an error
for exemple
if I insert one record and I delete it
so if I insert after the field will increase by two
how can I achieve that ?
thank you
There are multiple solutions to this problem:
1. (Preferable) Stop trying to predict auto-increment values
This is the more typical case, and basically is using auto-increment as designed. This assumes that you don't actually need the auto-increment value before you insert. What you can do is:
DROP TABLE IF EXISTS t;
CREATE TABLE t (id INT UNSIGNED NOT NULL auto_increment, x INT NOT NULL, PRIMARY KEY(id));
INSERT INTO t (x) VALUES (100);
SELECT LAST_INSERT_ID();
The call to SELECT LAST_INSERT_ID() will return the ID that was just generated for your INSERT.
2. Set up an ID generation table specifically to generate IDs
You can create a table with just an auto-increment column, like so:
DROP TABLE IF EXISTS id_generator;
CREATE TABLE id_generator (id INT UNSIGNED NOT NULL auto_increment, PRIMARY KEY(id));
You can then generate a new, unique ID with:
INSERT INTO id_generator (id) VALUES (NULL);
SELECT LAST_INSERT_ID();
And use that ID to insert into the table you're actually working with. As long as all generated IDs come from this ID generation table, there will be no conflicts. However there is a cost to generating these IDs, and auto-increment is not very efficient at it.
3. Use an external ID generation scheme
This is more or less similar to solution 2, but doesn't use MySQL at all for the ID generation. You can use something like a UUID/GUID scheme which generates a string, or you could use something like Snowflake to generate integer IDs.
You should use LAST_INSERT_ID like this:
SELECT LAST_INSERT_ID()
It will return the last value of AUTO_INCREMENT ID field.
More details here: http://goo.gl/RkmR5
This will give you the next id value that will be inserted:
SELECT LAST_INSERT_ID() + 1;

MySQL: Generate Autokey but use same for multiple rows

I have a mysql table that stores a mapping from an ID to a set of values:
CREATE TABLE `mapping` (
`ID` bigint(20) unsigned NOT NULL,
`Value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
This table is a list of values and the ID of a row selects the set, this value belongs to.
So the column ID is unique per set, but not unique per row.
I insert data into the table using the following statement:
INSERT INTO `mapping`
SELECT 5, `value` FROM `set1`;
In this example I calculated and set the ID manually to 5.
It would be great if mysql could set this ID automatically. I know the autokey feature, but using it will not work, because all rows inserted with the same insert statement should have the same ID.
So each insert statement should generate a new ID and then use it for all inserted rows.
Is there a way to accomplish this?
I am not convinced to it (I'm not sure whether locking table is good idea, I think it's not), but this might help:
lock tables `mapping` as m write, m as m1 read;
insert into m
select (select max(id) + 1 from m1), `value` from `set1`;
ulock tables;
One option is to have an additional table with an autogenerated key on single rows. Insert (with or without an necessary or appropriate other data) into that table, thus generating the new ID, and then use the generated key to insert into the mapping table.
This moves you to a world where the non-unique id is a foreign key reference to a truly unique key. Much more in keeping with typical relational database thinking.

MySQL Auto-Inc Bug?

In my MySQL table I've created an ID column which I'm hoping to auto-increment in order for it to be the primary key.
I've created my table:
CREATE TABLE `test` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`date_modified` DATETIME NOT NULL ,
UNIQUE (
`name`
)
) TYPE = INNODB;
then Inserted my records:
INSERT INTO `test` ( `id` , `name` , `date_modified` )
VALUES (
NULL , 'TIM', '2011-11-16 12:36:30'
), (
NULL , 'FRED', '2011-11-16 12:36:30'
);
I'm expecting that my ID's for the above are 1 and 2 (respectively). And so far this is true.
However when I do something like this:
insert into test (name) values ('FRED')
on duplicate key update date_modified=now();
then insert a new record, I'm expecting it to be 3, however now I'm shown an ID of 4; skipping the place spot for 3.
Normally this wouldn't be an issue but I'm using millions of records which have thousands of updates every day.. and I don't really want to even have to think about running out of ID's simply because I'm skipping a ton of numbers..
Anyclue to why this is happening?
MySQL version: 5.1.44
Thank you
My guess is that the INSERT itself kicks off the code that generates the next ID number. When the duplicate key is detected, and ON DUPLICATE KEY UPDATE is executed, the ID number is abandoned. (No SQL dbms guarantees that automatic sequences will be without gaps, AFAIK.)
MySQL docs say
In general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
That page also says
If a table contains an AUTO_INCREMENT column and INSERT ... ON
DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID()
function returns the AUTO_INCREMENT value.
which stops far short of describing the internal behavior I guessed at above.
Can't test here; will try later.
Is it possible to change your key to unsigned bigint - 18,446,744,073,709,551,615 is a lot of records - thus delaying the running out of ID's
Found this in mysql manual http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
Use a large enough integer data type for the AUTO_INCREMENT column to hold the
maximum sequence value you will need. When the column reaches the upper limit of
the data type, the next attempt to generate a sequence number fails. For example,
if you use TINYINT, the maximum permissible sequence number is 127.
For TINYINT UNSIGNED, the maximum is 255.
More reading here http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id it could be inferred that the insert to a transactional table is a rollback so the manual says "LAST_INSERT_ID() is not restored to that before the transaction"
What about for a possible solution to use a table to generate the ID's and then insert into your main table as the PK using LAST_INSERT_ID();
From the manual:
Create a table to hold the sequence counter and initialize it:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter and causes the next call to
LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that
value. The mysql_insert_id() C API function can also be used to get the value.
See Section 20.9.3.37, “mysql_insert_id()”.
It's really a bug how you can see here: http://bugs.mysql.com/bug.php?id=26316
But, apparently, they fixed it on 5.1.47 and it was declared as INNODB plugin problem.
A duplicate, but same problem, you can see here too: http://bugs.mysql.com/bug.php?id=53791 referenced to the first page mentioned here in this answer.

INSERT unique value to MYSQL

I am trying to insert a unique value into my table, however I need to know the ID before I create it. I know an AUTO_INCREMENT would have solved this problem, but this field is not AUTO_INCREMENTed.
This is my code...
INSERT INTO networks
(NETWORK_ID, ADMIN_USER_ID, NETWORK_NAME, ADDRESS)
VALUES
((SELECT MAX(NETWORK_ID)+1 FROM networks) , 3, 'Arcafe', 'habarzel 2 TA')
When I run it, I get a warning that I can't use the table in the FROM, I guess because it is pointing to itself. How can I achieve what I need? Can I change a field into an AUTO_INCREMENT field?
Usually you set the field to be an auto increment field when it is defined. To do so afterwards, you can use:
ALTER TABLE networks MODIFY NETWORK_ID int(10) unsigned NOT NULL auto_increment;
To then insert an ew record and for it to automatically get an assigned ID, merely omit the field from the insert, eg.
INSERT INTO networks
(ADMIN_USER_ID, NETWORK_NAME, ADDRESS)
VALUES
(3, 'Arcafe', 'habarzel 2 TA')
You can use separate table for generation unique ids and use this ids
ALTER TABLE networks CHANGE NETWORK_ID NETWORK_ID int auto_increment
Alter Table Manual