Is there a way to link two fields in a table so that one auto-increments, but resets to zero when the other field changes? For example, I have the following table in MySQL:
CREATE TABLE searches(
searchID INT UNSIGNED NOT NUL,
userID INT UNSIGNED NOT NULL,
searchParams VARCHAR(100) DEFAULT NULL,
creationDate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX(userID, searchID)
)ENGINE MyISAM;
The same user can create several searches, so what I want is to have searchID start at 1 whenever a new userID is entered, and increment automatically if a record to be inserted has a userID for which there are previous entries already. Can this be achieved somehow at table definition time? If not, can it be achieved with a single insert statement? Thanks in advance.
Is there a way to link two fields in a table so that one
auto-increments, but resets to zero when the other field changes?
NO, there is none; unless you build a trigger and make this change happen. Though I don't see how this would be helpful considering that one is a AUTO_INCREMENT column. You will unnecessary reseed it again and again.
Related
I am new to MySQL and databases overall. Is it possible two create a table where a column is a sum of two other columns from two other tables.
For instance if I have database `Books :
CREATE TABLE `books` (
`book_id` int(100) NOT NULL,
`book_name` varchar(20) NOT NULL,
`book_author` varchar(20) NOT NULL,
`book_co-authors` varchar(20) NOT NULL,
`book_edition` tinyint(4) NOT NULL,
`book_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`book_amount` int(100) NOT NULL COMMENT 'Amount of book copies in both University libraries'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
How can make column book_amount be a sum of the two book_amount columns from library1 and library2 tables where book_id = book_id?
Library1 :
CREATE TABLE `library1` (
`book_id` int(11) NOT NULL,
`book_amount` int(11) NOT NULL,
`available_amount` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
You can define a column with whatever type you want, so long as it's valid, and then populate it as you will with data from other tables. This is generally called "denormalizing" as under ideal circumstances you'll want that data stored in other tables and computed on demand so there's never a chance of your saved value and the source data falling out of sync.
You can also define a VIEW which is like a saved query that behaves as if it's a table. This can do all sorts of things, like dynamically query other tables, and presents the result as a column. A "materialized view" is something some databases support where the view is automatically updated and saved based on some implicit triggers. A non-materialized view is slower, but in your case the speed difference might not be a big deal.
So you have options in how you represent this.
One thing to note is that you should use INT as a default "integer" field, not wonky things like INT(100). The number for integer fields specifies how many significant digits you're expecting, and as INT can only store at most 11 this is wildly out of line.
Not directly, however there are a few ways to achieve what you're after.
Either create a psuedo column in your select clause which adds the other two columns
select *, columna+columnb AS `addition` from books
Don't forget to swap out columna and columnb to the name of the columns, and addition to the name you'd like the psuedo column to have.
Alternatively, you could use a view to auto add the psuedo field in the same way. However, views do not have indexes, so performing lookups in them and joining them can get rather slow very easily.
You could also use triggers to set the values upon insert and update, or simply calculate the value within the language that inserts into the DB.
Following query will work if library1 and library2 table has similar schema as table books:
Insert into books
select l1.book_id,
l1.book_name,
l1.book_authors,
l1.book_co_authors,
l1.book_edition,
l1.book_creation,
(l1.book_amount + l2.book_amount)
from library1 l1
inner join library2 l2
on l1.book_id = l2.book_id
group by l1.book_id
;
i need autoincrement. for start like abc_1,abc_2. like this format? below shown code is for auto increment. but i need format like abc_ is constatanct then auto increment, format like abc_1,abc_2..
CODE
sql = "CREATE TABLE MY_TABLE
(
table_id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(table_id),
table_1 varchar(45),
table_2 varchar(45),
table_3 varchar(999),
table_4 varchar(45)
)"
You have 2 options - both include keeping the autoincrement field exactly as it is.
1st Option is to add a short char type field, which simply stores your Alpha part. When you want to retrieve the whole key, then you can SELECT (alpha_part + table_id) as ID. As you can see this generates smaller storage, but requires more work for each select statement.
2nd option is to add a longer column that gets populated by an insert trigger normally. It is simply storing the concatenation on creation and then you don't have to concatenate it when you want to select it. This option also allows you to create an index or clustered index easier.
CREATE TABLE MY_TABLE (
table_id int NOT NULL AUTO_INCREMENT, PRIMARY KEY(table_id),
alpha_part varchar(10) NOT NULL, -- This
display_id varchar(40) NOT NULL, -- OR This (not both)
table_1 varchar(45),
table_2 varchar(45),
table_3 varchar(999),
table_4 varchar(45) )
"Database Id" and "Insurance Policy Id" are two separate entities - they may contain the "same" number, but don't mix up what the database needs to perform effectively, with what your business application needs to generate IDs for customers. Business rules and database Id are separate entities. You can "seed" a policy Id from a database generated one, but if something changes the policy id (yes this happens) your database suddenly needs to be refactored and you don't want that to happen.
You could add another column to derive this value, then have a trigger that automatically updates this column to add the derived value whenever a row is inserted.
However, it is not clear why this would be needed. It is likely better to just store the number and derive the form abc_123 where that value needs to be used.
It was an interesting thing. so I googled custom auto increment structure and found some links. Most of the people are saying that its better to use trigger before insertion and I think it can be on possible solution for your problem. Look at the following link.
http://www.experts-exchange.com/Database/MySQL/Q_27602627.html
I've got a mysql database with a table (InnoDB) of Games:
gamerooms
id: bigint(20) unsigned not null auto_increment
PRIMARY KEY (`id`)
I'd like to start generating a UUID value for each row which I can share publicly, something like:
gamerooms
id | id_public |
--------------------
1 | abcde
2 | ghijk
3 | lmnop
...
select * from gamerooms where id_public = ...
How do I add this new column, also keeping in mind that there are already records in the table? I'm confused because the column should be marked NOT NULL, but after adding the column, all records that already exist would have empty values.. Do I have to provide a default value?:
ALTER TABLE `gamerooms` ADD COLUMN `id_public` varchar(36) DEFAULT something AFTER `id`
I want to put an index on id_public of course after it's created, so not sure if null values after the column is first created will mess anything up.
Also, I can use varchar(36) with mysqls UUID() output, right?
Thank you
Your ALTER statement is correct:
ALTER TABLE `gamerooms`
ADD COLUMN `id_public` varchar(36) NOT NULL DEFAULT 'something' AFTER `id`
According to my MySQL Pocket Reference, if you don't provide a default value for a column that is defined as NOT NULL:
MySQL picks a value based on the type of the field
In this case, I'm guessing the default would be empty string. Once your column has been added, simply create a new index for the column, and rebuild the index using a null alteration instruction like so:
CREATE INDEX myIndex ON gamerooms(id_public);
ALTER TABLE gamerooms ENGINE = InnoDB;
You may be able to create the index at the same time you do the insert. My MySQL-fu isn't strong enough to know how to do that.
Should the existing records have a value once you create this new column? If yes, you could do this in multiple steps. First, create the new column without constraint or index and then back populate it with the UUID for all existing records. Once everything is populated, add the not null constraint and your indexes.
As a UUID is a 128-bit number, you don't need a varchar column to store it. a char(16) column would just be ok for saving a UUID binary data.
ALTER TABLE `gamerooms` ADD COLUMN `id_public` char(16) NOT NULL DEFAULT '' AFTER `id`
I have a table "Bestelling" with 4 columns: "Id" (PK), "KlantId", "Datum", "BestellingsTypeId", now I want to make the column Id auto_increment, however, when I try to do that, I get this error:
ERROR 1062: ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '1' for key 'PRIMARY'
SQL Statement:
ALTER TABLE `aafest`.`aafest_bestelling` CHANGE COLUMN `Id` `Id` INT(11) NOT NULL AUTO_INCREMENT
ERROR: Error when running failback script. Details follow.
ERROR 1046: No database selected
SQL Statement:
CREATE TABLE `aafest_bestelling` (
`Id` int(11) NOT NULL,
`KlantId` int(11) DEFAULT NULL,
`Datum` date DEFAULT NULL,
`BestellingstypeId` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
Anyone got an idea?
This will happen if the table contains an existing record with an id of 0 (or negative). Updating all existing records to use positive values will allow auto_increment to be set on that column.
Edit: Some people asked how that 0 got in there. For clarification, the MySQL Reference Manual states that "For numeric types, the default is 0, with the exception that for integer or floating-point types declared with the AUTO_INCREMENT attribute, the default is the next value in the sequence." So, if you performed an insert on a table without providing a value for the numeric column before the auto_increment was enabled, then the default 0 would be used during the insert. More details may be found at https://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html.
I also had this issue when trying to convert a column to auto_increment where one row had a value of 0. An alternative to changing the 0 value temporarily is via setting:
SET SESSION sql_mode='NO_AUTO_VALUE_ON_ZERO';
for the session.
This allowed the column to be altered to auto_increment with the zero id in place.
The zero isn't ideal - and I also wouldn't recommend it being used in an auto_increment column. Unfortunately it's part of an inherited data set so I'm stuck with it for now.
Best to clear the setting (and any others) afterwards with:
SET SESSION sql_mode='';
although it will be cleared when the current client session clsoes.
Full details on the 'NO_AUTO_VALUE_ON_ZERO' setting here.
This happens when MySQL can not determine a proper auto_increment value. In your case, MySQL choose 1 as next auto_increment value, however there is already row with that value in the table.
One way to resolve the issue is to choose a proper auto_increment value yourself:
ALTER TABLE ... CHANGE COLUMN `Id` `Id` INT(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT = 123456;
(Note the AUTO_INCREMENT=123456 at the end.)
The easiest way that I have found to solve this issue is to first set the table's AUTO INCREMENT value before altering the column. Just make sure that you set the auto increment value higher than the largest value currently in that column:
ALTER TABLE `aafest`.`aafest_bestelling`
AUTO_INCREMENT = 100,
CHANGE COLUMN `Id` `Id` INT(11) NOT NULL AUTO_INCREMENT
I tested this on MySQL 5.7 and it worked great for me.
Edit: Don't know exactly how that would be caused, but I do have a workaround.
First, create a new table like the old one:
CREATE TABLE aafest_bestelling_new LIKE aafest_bestelling;
Then change the column
ALTER TABLE `aafest`.`aafest_bestelling_new`
CHANGE COLUMN `Id` `Id` INT(11) NOT NULL AUTO_INCREMENT
Dump in the new data:
INSERT INTO aafest_bestelling_new
(KlantId, Datum, BestellingTypeId)
SELECT
KlantId, Datum, BestellingTypeId
FROM aafest_bestelling;
Move the tables:
RENAME TABLE
aafest_bestelling TO aafest_bestelling_old,
aafest_bestelling_new TO aafest_bestelling;
Maybe there's some corruption going on, and this would fix that as well.
P.S.: As a dutchman, I'd highly recommend coding in english ;)
I had a similar issue. Issue was the table had a record with ID = 0 similar to what SystemParadox pointed out. I handled my issue by the following steps:
Steps:
Update record id 0 to be x where x = MAX(id)+1
Alter table to set primary key and auto increment setting
Set seed value to be x+1
Change record id x back to 0
Code Example:
UPDATE foo SET id = 100 WHERE id = 0;
ALTER TABLE foo MODIFY COLUMN id INT(11) NOT NULL AUTO_INCREMENT;
ALTER TABLE foo AUTO_INCREMENT = 101;
UPDATE foo SET id = 0 WHERE id = 100;
This happens because your primary key column already has values.
As the error says ...
ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '1' for key 'PRIMARY'
which means that your column already has a primary key value 1 which when you auto_increment that column is reassigned causing duplication and hence this error
the solution to this is to remove the primary constraint and then empty the column. Then alter the table setting the primary key again, this time with auto increment.
This error comes because the any table contains an existing record with an id of 0 (or negative). Update all existing records to use positive values will allow auto_increment to be set on that column.
If this didn't work then export all the data and save it any where in you computer and dont first make foreign key relation then fill data in parent table .
This error will also happen if have a MyISAM table that has a composite AUTO_INCREMENT PRIMARY KEY and are trying to combine the keys
For example
CREATE TABLE test1 (
`id` int(11) NOT NULL,
`ver` int(10) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`,`ver`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO test1 (`id`, `ver`) VALUES (1,NULL),(1,NULL),(1,NULL), (2,NULL),(2,NULL),(2,NULL);
ALTER TABLE test1 DROP PRIMARY KEY, ADD PRIMARY KEY(`ver`);
Not being able to set an existing column to auto_increment also happens if the column you're trying to modify is included in a foreign key relation in another table (although it won't produce the error message referred to in the question).
(I'm adding this answer even though it doesn't relate to the specific error message in the body of the question because this is the first result that shows up on Google when searching for issues relating to not being able to set an existing MySQL column to auto_increment.)
We are running an import of an existing product table into a new table of our own. The import script we've written runs perfectly and inserts the right amount of rows (6000 or so). However, after the import the next auto incremented primary key/id is 1500 entries (or so) above the number of rows in the table.
We can't understand why MySQL is doing this and we'd like it to stop. I've done the usual searches online looking for help but I am drawing a blank - any ideas?
Let's take this simple table for example:
CREATE TABLE `products` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64) NULL DEFAULT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=MyISAM;
And import file that look like:
"id","name"
1,"product 1"
2,"product 2"
5,"product 3"
102,"product 4"
Then you are importing data to both columns, so auto incrementing mechanism does not work.
After importing all rows, autoincrement value for table is set to MAX(id)+1 [103 in this case] to ensure next autoincremented id is unique. If it was equal to number of rows inserted, then next autincrement value would be 5 and would colide with row #3.
If you want to have clean start and last id equal to number of rows you have to either get rid of "id" column from .csv file, or create table without AUTO_INCREMENT for id, import data and run this simple sql:
SET #i=0;
UPDATE `products` SET id=#i:=#i+1 ORDER BY id;
ALTER TABLE `products` CHANGE COLUMN `id` `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT FIRST;
First query sets auxiliary variable, that will be incremented before updating the record.
Second one updates record to have id equal to row number.
Third will change id column to be autoincremented and set proper value for next autoindex.
But before changing any primary keys ensure that they are not used in any other tables as foreign keys!
If you perform this command:
show create table Foo
Then you will see what the AUTO_INCREMENT= is set too.
My guess is that it is not set to start with 0.
You should then create your new table to have the AUTO_INCREMENT set to 0 (or 1, I cannot remember from the top of my head). This should do the trick.