Disclaimer: I have only novice knowledge of and experience with databases.
I'm following a Laravel course on Laracasts, and in the database video, the instructor sets the ID column to a type of SERIAL. This is different to how I've seen this done in all other database tutorials, where they will usually check the A_I (auto-increment) checkbox, and this automatically makes the column primary, and leaves the type to be something like INT.
Hovering over the SERIAL type in PHPMyAdmin tells me that it's an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, but is there ever a particular reason to prefer it over the settings that checking the A_I checkbox sets up? Does either way offer any advantages or disadvantages?
I did find this for PostgreSQL, indicating SERIAL is old and outdated, but I couldn't find an equivalent for MySQL and I'm unsure if the same applies to it.
I'm sure MySQL's SERIAL type was implemented to make it easy for folks who were accustomed to PostgreSQL to have one set of CREATE TABLE statements that would work on both brands of database, and do more or less the same thing.
In an old version of the MySQL manual, it was stated that SERIAL is a compatibility feature (without naming the brand it was intended to be compatible with). The language about compatibility was removed (see https://bugs.mysql.com/bug.php?id=7978).
Now that even PostgreSQL has changed its recommended practice and they use IDENTITY columns instead of SERIAL, the MySQL feature is really unnecessary.
There is no advantage to using SERIAL in MySQL. On the contrary, if you do use it in a CREATE TABLE statement, you will see that the syntax isn't saved. It is just an alias for the BIGINT UNSIGNED AUTO_INCREMENT UNIQUE, as documented.
I find that it's actually wasteful to do this, because I typically declare the auto-increment column as a PRIMARY KEY anyway, and this makes the UNIQUE redundant. So you end up with two unique indexes for no reason.
mysql> create table mytable (id serial primary key);
mysql> show create table mytable\G
*************************** 1. row ***************************
Table: mytable
Create Table: CREATE TABLE `mytable` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`) -- this one is superfluous
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
P.S. This question is almost but not quite a duplicate of What is the difference between SERIAL and AUTO_INCREMENT in mysql
We have loaded several tables (hundreds of millions of rows each) but the following query requires the entire table to be rewritten (the type is exactly the same apart from the AUTO_INCREMENT):
ALTER TABLE sales MODIFY id BIGINT(20) NOT NULL AUTO_INCREMENT;
Is this just a huge oversight by MySQL or does it fundamentally change the format the data on disk?
Changing the AUTO_INCREMENT characteristic of a column cannot be done as an online DDL change. Even when I try to request it explicitly:
mysql> alter table sales modify column id bigint not null auto_increment,
ALGORITHM=INPLACE;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported.
Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
This case of changing the column definition seems to count as a change to the column type (based on the error message).
https://dev.mysql.com/doc/refman/5.6/en/innodb-create-index-overview.html#innodb-online-ddl-summary-grid says:
Change column data type... Only supports ALGORITHM=COPY
In MySQL 5.7, changing the type of a column is still required to rebuild the table, except in one case: increasing VARCHAR length is allowed as an INPLACE change.
You aren't the only one to think that it should be allowed to change the AUTO_INCREMENT property without doing a table restructure: https://bugs.mysql.com/bug.php?id=72109
I am using MariaDB 10.1.9. Short version: What I really want to know for certain is if I can modify an indexed auto_increment field on an innodb table from int to bigint without locking the table?
Long version: Is there a detailed explanation of which ALTER TABLE operations require which lock level? The documentation just says "Depending on the required operation and the used storage engine, different lock strategies can be used for ALTER TABLE.". It doesn't provide a link to any details and each operation on the ALTER TABLE page does not specify it's required level.
From experimentation, I know ADD COLUMN does not require a lock. MODIFY COLUMN allows reads, but can it be manually set to allow writes? The MariaDB documentation says you can set the lock level, but if you don't set it restrictive enough, it will give an error - but it doesn't say what that error is. The current table column definition looks like
`Id` int(10) NOT NULL AUTO_INCREMENT
KEY `Id` (`Id`)
When I try
ALTER TABLE MyTable MODIFY MyField bigint AUTO_INCREMENT LOCK=NONE;
I just get a generic SQL syntax error. Even if I specify DEFAULT, I get an error, so I'm not sure how to use the LOCK - which I would expect the proper error to tell me when I have chosen an improper lock level.
The syntax...
alter_specification [, alter_specification] ...
... requires a comma
ALTER TABLE MyTable
MODIFY COLUMN MyField BIGINT AUTO_INCREMENT, -- comma here
LOCK=NONE;
I'm guessing the error was not all that "generic" -- it should have said something about the right syntax to use near 'LOCK... which is your hint not that the quoted term is the beginning of the error, but rather that that the parser/lexer expected something other than the quoted value to occur at that position (because it was looking for the comma).
If the column you are altering is the primary key, a lock seems inevitable -- because the entire table should need rebuilding, including all the indexes, since the primary key "rides free" in all indexes, as it is what's used after a non-covering index lookup to actually find the rows matched by the index.
I am using MySQL 5.1.56, MyISAM. My table looks like this:
CREATE TABLE IF NOT EXISTS `my_table` (
`number` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`money` int(11) NOT NULL,
PRIMARY KEY (`number`,`name`)
) ENGINE=MyISAM;
It contains these two rows:
INSERT INTO `my_table` (`number`, `name`, `money`) VALUES
(1, 'S. Name', 150), (2, 'Another Name', 284);
Now I am trying to insert another row:
INSERT INTO `my_table` (`number`, `name`, `money`) VALUES
(2, 'S. Name', 240);
And MySQL just won't insert it while telling me this:
#1062 - Duplicate entry '2-S. Name' for key 'PRIMARY'
I really don't understand it. The primary key is on the first two columns (both of them), so the row I am trying to insert HAS a unique primary key, doesn't it?
I tried to repair the table, I tried to optimize the table, all to no avail. Also please note that I cannot change from MyISAM to InnoDB.
Am I missing something or is this a bug of MySQL or MyISAM? Thanks.
To summarize and point out where I think is the problem (even though there shouldn't be):
Table has primary key on two columns. I am trying to insert a row with a new combination of values in these two columns, but value in column one is already in some row and value in column two is already in another row. But they are not anywhere combined, so I believe this is supposed to work and I am very confused to see that it doesn't.
Your code and schema are OK. You probably trying on previous version of table.
http://sqlfiddle.com/#!2/9dc64/1/0
Your table even has no UNIQUE, so that error is impossible on that table.
Backup data from that table, drop it and re-create.
Maybe you tried to run that CREATE TABLE IF NOT EXIST. It was not created, you have old version, but there was no error because of IF NOT EXIST.
You may run SQL like this to see current table structure:
DESCRIBE my_table;
Edit - added later:
Try to run this:
DROP TABLE `my_table`; --make backup - it deletes table
CREATE TABLE `my_table` (
`number` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`money` int(11) NOT NULL,
PRIMARY KEY (`number`,`name`),
UNIQUE (`number`, `name`) --added unique on 2 rows
) ENGINE=MyISAM;
I know this wasn't the problem in this case, but I had a similar issue of "Duplicate Entry" when creating a composite primary key:
ALTER TABLE table ADD PRIMARY KEY(fieldA,fieldB);
The error was something like:
#1062 Duplicate entry 'valueA-valueB' for key 'PRIMARY'
So I searched:
select * from table where fieldA='valueA' and fieldB='valueB'
And the output showed just 1 row, no duplicate!
After some time I found out that if you have NULL values in these field you receive these errors. In the end the error message was kind of misleading me.
I had a similar issue, but in my case it turned out that I used case insensitive collation - utf8_general_ci.
Thus, when I tried to insert two strings which were different in a case-sensitive comparison, but the same in the case-insensitive one, MySQL fired the error and I couldn't understand what a problem, because I used a case-sensitive search.
The solution is to change the collation of a table, e.g. I used utf8_bin which is case-sensitive (or utf8_general_cs should be appropriate one too).
In case this helps anyone besides the OP, I had a similar problem using InnoDB.
For me, what was really going on was a foreign key constraint failure. I was referencing a foreign key that did not exist.
In other words, the error was completely off. The primary key was fine, and inserting the foreign key first fixed the problem. No idea why MySQL got this wrong suddenly.
Less common cases, but keep in mind that according to DOC https://dev.mysql.com/doc/refman/5.6/en/innodb-online-ddl-limitations.html
When running an online ALTER TABLE operation, the thread that runs the ALTER TABLE operation will apply an “online log” of DML operations that were run concurrently on the same table from other connection threads. When the DML operations are applied, it is possible to encounter a duplicate key entry error (ERROR 1062 (23000): Duplicate entry), even if the duplicate entry is only temporary and would be reverted by a later entry in the “online log”. This is similar to the idea of a foreign key constraint check in InnoDB in which constraints must hold during a transaction.
In my case the error was caused by the outdated schema, one column was originally varchar(50) but the dump I was trying to import was created from a modified version of the schema that has varchar(70) for that column (and some of the entries of that field where using more than 50 chars).
During the import some keys were truncated and the truncated version was not unique anymore. Took a while to figure that out, I was like "but this supposedly duplicated key doesn't even exist!".
Try with auto increment:
CREATE TABLE IF NOT EXISTS `my_table` (
`number` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`money` int(11) NOT NULL,
PRIMARY KEY (`number`,`name`)
) ENGINE=MyISAM;
Your code is work well on this demo:
http://sqlfiddle.com/#!8/87e10/1/0
I think you are doing second query (insert...) twice. Try
select * from my_table
before insert new row and you will get that your data already exist or not.
i have just tried, and if you have data and table recreation wouldnt work, just alter table to InnoDB and try again, it would fix the problem
In case anyone else finds this thread with my problem -- I was using an "integer" column type in MySQL. The row I was attempting to insert had a primary key with a value larger than allowed by integer. Switching to "bigint" fixed the problem.
As per your code your "number" and "Name" are primarykey and you are inserting S.NAME in both row so it will make a conflict. we are using primarykey for accessing complete data. here you cant access the data using the primarykey 'name'.
im a beginner and i think it might be the error.
In my case the error was very misleading. The problem was that PHPMyAdmin uses "ALTER TABLE" when you click on the "make unique" button instead of "ALTER IGNORE TABLE", so I had to do it manually, like in:
ALTER TABLE mytbl ADD UNIQUE (columnName);
This problem is often created when adding a column or using an existing column as a primary key. It is not created due to a primary key existing that was never actually created or due to damage to the table.
What the error actually denotes is that a pending key value is blank.
The solution is to populate the column with unique values and then try to create the primary key again. There can be no blank, null or duplicate values, or this misleading error will appear.
For me a noop on table has been enough (was already InnoDB):
ALTER TABLE $tbl ENGINE=InnoDB;
tl;dr: my view showed my table was empty but the view excluded existing rows.
I had the same problem but mine was because I was inserting the same test rows I had used before. When I checked to see if my table was empty, I used a view that excluded different tenants so the search came back empty. When I checked the actual table, the previous records were still there.
Once I had deleted the existing records, the insert worked. Only half a day of frustration lost to this one...
Had this error, when adding a composite primary key that is ADD PRIMARY KEY (column1, column2, ...) The value of all the columns in that row must not be duplicated.
For Example:
You do ADD PRIMARY KEY (name, country, number)
name
country
number
collin
Uk
5
collin
Uk
5
This will throw an error #1062 - Duplicate entry 'collin-UK-5' for key 'PRIMARY' because the columns combined have duplicate
So if you see this format of error just check and ensure that the columns you want to add a composite primary key to combined don't have duplicates.
Another reason you may be getting this error is because the same restriction exists in another related table, and they Keyname on the related table has the exact same name. I've had this happen once and it was quite difficult to identify.
i.e. if you have a trigger that inserts data to a different table (the "related" table) with the same restriction and same Keyname, MySQL will not include the name of the table throwing the error, only the Keyname.
As looking on your error #1062 - Duplicate entry '2-S. Name' for key 'PRIMARY' it is saying that you use primary key in your number field that's why it is showing duplicate Error on Number Field.
So Remove this primary Key then it inset duplicate also.
I have a table that essentially looks like this:
CREATE TABLE myTable (
id INT auto_increment,
field1 TINYINT,
field2 CHAR(2),
field3 INT,
theDate DATE,
otherStuff VARCHAR(20)
PRIMARY KEY (id)
UNIQUE KEY (field1, field2, field3)
)
I'd like to partition the table based on the month and year of theDate, however the manual is telling me I'm not allowed:
All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have. In other words, every unique key on the table must use every column in the table's partitioning expression
What are my options here? Can I still partition the table?
I wrote a blog post about this issue here Scaling Rails with MySQL table partitioning (rails uses integer PKs). The same technique should work in your case, except, unfortunately you have to drop the [field1, field2, field3] unique key.
Dropping a unique key was a problem I dealt with too (though not mentioned in the post). I worked around it by implemented an existence check before creating the record, realizing that we'd still get occasional dupes due to the race condition. In practice, that didn't turn out to be a problem. However, the increased query throughput required scaling up the innodb buffer size 'cause the i/o's we're brutal.
No, not in the current form.
You could remove the primary key and instead just make "id" a normal index. The secondary unique index would still be a problem and you would need to remove this or change the partitioning scheme to involve theDate column.
If you are partitioning based on the year and month of a datetime column, have you thought about having a table for each year-month combo and then using a merge table? I know this doesn't directly answer your question, but thought it may help...