Use auto increment only when needed - mysql

I have a column in my db "id" int(11) NOT NULL AUTO_INCREMENT, and I want multiple rows in this table with the same id value. So when inserting to the table I'd like to tell whether it should increment or the value remains the sasme. Is there any easy way how to do that?

As MySQL documentation on auto_increment says (highlighting is mine):
No value was specified for the AUTO_INCREMENT column, so MySQL
assigned sequence numbers automatically. You can also explicitly
assign 0 to the column to generate sequence numbers, unless the
NO_AUTO_VALUE_ON_ZERO SQL mode is enabled. If the column is declared
NOT NULL, it is also possible to assign NULL to the column to generate
sequence numbers. When you insert any other value into an
AUTO_INCREMENT column, the column is set to that value and the
sequence is reset so that the next automatically generated value
follows sequentially from the largest column value.
This means, if you determine before the insert the current maximum of the auto_increment field and you explicitly insert that value in the insert statement, then you can have duplicate values in the auto_increment field.
There a couple things that you need to pay attention to:
If you can have parallel inserts into the table, then you may have to lock the table for reading, so another process does not insert a new record triggering the increment of the field.
You cannot use primary / unique index constraint on the auto_increment field.
The alternative is to have a separate table just for the auto_increment and do not use auto_increment in the main table. If you need a new id, then just insert a record into the auto_ncrement table a get the incremented id and use that to insert a record into the main table. Otherwise, just fetch the id value from the main table and use it in the insert.

An auto_increment column makes sure that the values in it are unique ! So, you can't do it this way.
I'd suggest a trigger instead , combining the needed logic.

For MyISAM tables, you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups.
CREATE TABLE animals (
grp ENUM('fish','mammal','bird') NOT NULL,
id MEDIUMINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (grp,id)
) ENGINE=MyISAM;
INSERT INTO animals (grp,name) VALUES
('mammal','dog'),('mammal','cat'),
('bird','penguin'),('fish','lax'),('mammal','whale'),
('bird','ostrich');
SELECT * FROM animals ORDER BY grp,id;
Which returns:
**grep id name**
fish 1 lax
mammal 1 dog
mammal 2 cat
mammal 3 whale
bird 1 penguin
bird 2 ostrich
If the AUTO_INCREMENT column is part of multiple indexes, MySQL generates sequence values using the index that begins with the AUTO_INCREMENT column, if there is one. For example, if the animals table contained indexes PRIMARY KEY (grp, id) and INDEX (id), MySQL would ignore the PRIMARY KEY for generating sequence values. As a result, the table would contain a single sequence, not a sequence per grp value

Related

mysql - insert in two tables using autogenerate key from first insert table without using LAST_INSERT_ID

I need to insert some values into two different tables, this tables need to be linked, let's supposed I have:
table product
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
name TEXT NOT NULL
table ingredients
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY
productID INT NOT NULL
value TEXT NOT NULL
so I need to insert in a commit both tables but table ingredients needs to be linked the productID autogenerated by product table, I DON'T want to use LAST_INSERT_ID because I'm inserting multiples rows at the same time and I may get and id from other row.
You can use LAST_INSERT_ID() since is multi-thread safe. MySQL's docs say:
For LAST_INSERT_ID(), the most recently generated ID is maintained in the server on a per-connection basis. It is not changed by another client.

Store word occurrences in MySQL table

I have a table called words, and in it I'd like to store key/value pairs of words and their occurrences.
I want to make the count column an auto-incrementing column, since I want to keep adding words (from a C++ application) and have the count increment on its own automatically. However, I figured that the table would be searched a lot, so I made word the primary key. I ran into an error, though, saying I cannot set a non-primary key as an auto-incrementing column.
Is there a way to do this properly such that I can insert into the table and have the database handle incrementing and all that?
Create a table to store the words. The word column is the primary key.
CREATE TABLE `words` (
`word` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`count` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`word`)
);
Then insert your words in the table like this:
INSERT INTO `words`(word) VALUES('car') ON DUPLICATE KEY UPDATE `count`=`count`+1;
INSERT INTO `words`(word) VALUES('plane') ON DUPLICATE KEY UPDATE `count`=`count`+1;
INSERT INTO `words`(word) VALUES('car') ON DUPLICATE KEY UPDATE `count`=`count`+1;
If the word doesn't exist in the table, nb defaults to 1 (this is in the table definition).
If the word already exist in the table, the value of nb for this word is increased by 1.
After the 3 inserts above, the table contains:
word | count
car | 2
plane | 1
You may need to adjust:
- the length of the column word
- the character set and collation
Documentation: INSERT ... ON DUPLICATE KEY UPDATE Syntax
You can keep the auto increment column as the primary key, and add an additional index containing the word column only. if you're searching by word, this index will be used

MySQL: Insert multiple rows with same AI value

Let's say this is my table:
CREATE TABLE tab (
id INT AUTO_INCREMENT NOT NULL,
val VARCHAR(9),
KEY(id),
PRIMARY KEY (xx)
);
Would it possible to insert multiple rows at the same time in a way that they would all get the same auto-increment value?
The following works, but increments each new row, regardless of the fact that we are doing a single query.
INSERT INTO tab (id,val) VALUES (LAST_INSERT_ID(),'a'), (LAST_INSERT_ID(),'b');
How could I make sure they all receive the same auto-incremented ID in a single query?
You will need to keep the first AI value in a variable and pass it in the INSERT query for different pairs

mysql manual increment ids?

I have a table with items in it (id, name, etc) and I want some kind of database scheme to be able to have multiple copies of the item while still being able to increment the ids. There will be a field called startdate or date_from_which_this_entry_should_be_used.
I've thought of two ways of implementing this:
Have a table with only ids (primary key, auto-increment) and do joins to a table that has all the item information.
Advantages:
easy to understand
hard for someone that comes after me to get confused
Disadvantages:
requires more debugging and coding since this system is already in use
seems weird to have a table with a single field
Have a single table using a sub-select to get the MAX value (+1) to apply to new items.
Advantages:
single table
only minor code adjustments (but not all that different, maybe)
Disadvantages:
prone to errors (manual increment, can't allow deletions or the MAX value might be off)
Thanks in advance!
You should create a table called item_ids or something to generate id values. It's okay that this has only a single column.
CREATE TABLE item_ids (
item_id INT AUTO_INCREMENT PRIMARY KEY
) ENGINE=InnoDB;
You don't even need to commit any data to it. You just use it to generate id values:
START TRANSACTION;
INSERT INTO item_ids DEFAULT VALUES;
SET #id = LAST_INSERT_ID();
ROLLBACK;
So now you have a concurrency-safe method to create new id's.
Then you make a compound primary key for your items table. You must use MyISAM for this.
CREATE TABLE items (
item_id INT,
seq_id INT AUTO_INCREMENT,
name VARCHAR(20),
etc VARCHAR(20),
PRIMARY KEY (item_id, seq_id)
) ENGINE=MyISAM;
MyISAM supports an auto-increment column in a compound primary key, which will start over at value 1 for each new item_id.* It also uses MAX(item_id)+1 so if you delete the last one, its value will be reallocated. This is unlike other use of AUTO_INCREMENT where a deleted value is not re-used.
Whether you insert a new item, or whether you insert a new copy of an existing item, you use a similar INSERT:
INSERT INTO items (item_id, name, etc) VALUES (#id, 'Stephane', 'etc');
The #id parameter is either a value of an existing item, or else the auto-generated value you got from the item_ids table.
* InnoDB supports auto-increment only as the first column of a primary or unique key, and it does not start over the count for each distinct value of the other column.

Is it possible to have an AUTO_INCREMENT column that permits duplicates?

I have a table that has an AUTO_INCREMENT field. Currently, it is also a PRIMARY KEY.
However, there are situations where I need this AUTO_INCREMENT column to permit duplicates. In other words - two different rows can have the same value inside the AUTO_INCREMENT column. This would mean having an AUTO_INCREMENT field that is not a PRIMARY KEY.
Is this possible?
I'm guessing it's not, since whenever I try to do it, I get this error:
ERROR 1075 (42000) at line 130: Incorrect table definition; there can be only one auto column and it must be defined as a key
I like to have the AUTO_INCREMENT field because it saves me from having to manually store / increment a separate counter elsewhere in my database. I can just insert into the table and grab the value that was inserted. However, if I can't have duplicates, it seems like I'm going to be stuck with using a separate table to track and manually increment this field.
UPDATE: As a quick clarification, I am already familiar with grouping the AUTO_INCREMENT field with another key, as described here. Let's assume for the sake of argument that this solution won't work due to other constraints in the database.
An auto-increment field in MySQL must be part of a key (i.e. an index), but not necessarily part of a primary key or unique key.
CREATE TABLE mytable (
id INT PRIMARY KEY,
otto INT AUTO_INCREMENT,
KEY (otto)
);
-- allow the auto-increment to generate a value
INSERT INTO mytable (id, otto) VALUES (123, DEFAULT);
SELECT * FROM mytable;
> 123, 1
-- specify a duplicate value, overriding the auto-increment mechanism
INSERT INTO mytable (id, otto) VALUES (456, 1);
SELECT * FROM mytable;
> 123, 1
> 456, 1
-- allow the auto-increment to generate another value
INSERT INTO mytable (id, otto) VALUES (789, DEFAULT);
SELECT * FROM mytable;
> 123, 1
> 456, 1
> 789, 2
Sounds like 'subtask' is a table to which 'task' has a FK reference to. That is, if subtasks are reused.
OTOH if a task can have many subtasks, and a subtask can be linked to more than one task then you're looking at many-to-many in a seperate table.
in either case I don't think you want the DB autogenerating these 'linked-IDs'.