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
There are plenty of questions regarding this error but I can't seem to find any similar scenario to what I have.
My 1st table (users):
My 2nd table (colleges):
I am trying to alter 1st table and add a foreign key that references id of a 2nd table:
ALTER TABLE users
ADD CONSTRAINT FOREIGN KEY (collegelinkId)
REFERENCES databaseName.colleges (id);
Which fails with error (errno: 150 "Foreign key constraint is incorrectly formed").
The only parameter that is different between these two tables is auto_increment. However, I can not add auto_increment to my users table collegelinkId column since its id is already set to auto_increment.
We would expect to see this error if the types of the primary and foreign key did not match exactly. While both appear to be integer with a width of 1, my guess here is that one of the INT columns in the key relationship is unsigned, while the other is signed. A possible fix would be to make both columns unsigned:
ALTER TABLE users MODIFY collegelinkId INT(10) UNSIGNED NOT NULL;
ALTER TABLE college MODIFY id INT(10) UNSIGNED NOT NULL;
Edit:
I was wrong, as evidenced by your latest comments under my answer. Another possibility is that you created your two tables using different database engines. For example, if you created users using InnoDB, but college using MyISAM, you could still get this error. To fix this, change the engine(s) on the tables to the same type.
Note that yet another possibility would be that the two columns had different collations. But, that's really a moot point here, since both columns are numeric, not text.
Since the columns are of the same type, it's worth to check the engine type as #Tim Biegeleisen suggested.
Changing engine type fixed the issue.
ALTER TABLE users
ENGINE=InnoDB;
Verify that the datatypes match (except for PRIMARY KEY).
Verify that both tables are ENGINE=InnoDB.
Even after that, error 150 can still occur. 3 ways around it:
Disable FKs while creating the tables, then re-enable.
CREATE TABLEs without FKs, then ALTER ... ADD ... FKs
Be sure the do the CREATEs in just the right order.
A side note: In INT(2), the (2) is irrelevant. All INTs are 4 bytes.
I'm trying to implement cassandra SE and MariaDB interoperability. In cqlsh, I'm able to create table with composite keys. When I try the same in mariadb, I'm getting error ERROR 1070 (42000): Too many key parts specified; max 1 parts allowed.
Here is my code which I used in cqlsh:
cqlsh:mariadbtest> create table test (test1 int, test2 bigint, test3 varchar, primary key (test1, test2)) with compact STORAGE;
In Mariadb :
MariaDB [test]> set global cassandra_default_thrift_host='localhost';
MariaDB [test]> create table random (test1 int(5), test2 bigint(5), test3 varchar(20), PRIMARY KEY (test1, test2)) engine=cassandra keyspace='historian' thrift_host='localhost' column_family='test';
ERROR 1070 (42000): Too many key parts specified; max 1 parts allowed
When I use single column as my primary key, it works fine with no errors. Please help me on how to solve composite keys issue.
Any help would be appreciated.
This is not supported in the storage engine. According to the docs:
Note: Multi-column primary keys are currently not supported. Support may be added in a future version, depending on whether there is a demand for it.
It is unclear whether you would be able to define a composite partition key (i.e. PRIMARY KEY ((test1, test2))). I'm also not certain that would even suit your needs. It sounds like you should declare your interest if that's what you need.
I created a table named "Payments" and later on realized, that I needed to change the names and datatypes of 2 of its columns. I dropped the table and wanted to create it again - but now I get the error-message: "Can't create table 'dev_datenbank.payment' (errno: 150)"
CREATE TABLE Payment(
payment_id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
payment_gemeindeid INTEGER NOT NULL,
payment_initiator TIMESTAMP,
payment_zyklus INTEGER,
payment_received BOOLEAN DEFAULT false
);
ALTER TABLE Payment ADD FOREIGN KEY(payment_gemeindeid) REFERENCES Gemeinde(gemeinde_id);
I looked at similar problems here, but I haven't found a solution. Most of the times when others encountered this problem, it had to do with tables having different datatypes on the FK columns. But in my case both are INTEGER.
Also the database-type of all columns is 'InnoDB'.
I assume that the foreign key constraint has not correctly been removed from MySQL. I checked in the table KEY_COLUMN_USAGE in the information_schema but I cannot see any remains here.
The other table is created as follows:
CREATE TABLE Gemeinde
(gemeinde_id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
gemeinde_name VARCHAR(50) NOT NULL,
gemeinde_amt INTEGER,
gemeinde_status INTEGER NOT NULL DEFAULT 1,
gemeinde_info VARCHAR(512)
);
Create an index on payment_gemeindeid before using it as a foreign key.
The problems I had, disappered after I updated my XAMPP from an old version (5.0.x) to a newer version (5.5.30). Now I can drop an recreate tables as expected.
Anyhow the hints with indexing my foreign keys was really helpful and I will start doing this from now on. I never paid much attention to this before, since my DBs were rather small. Thanks for your help.
Also reading through following discussion helped me get more understanding to this: Does a foreign key automatically create an index?
I've created a table in MySQL:
CREATE TABLE actions ( A_id int NOT NULL AUTO_INCREMENT,
type ENUM('rate','report','submit','edit','delete') NOT NULL,
Q_id int NOT NULL,
U_id int NOT NULL,
date DATE NOT NULL,
time TIME NOT NULL,
rate tinyint(1),
PRIMARY KEY (A_id),
CONSTRAINT fk_Question FOREIGN KEY (Q_id) REFERENCES questions(P_id),
CONSTRAINT fk_User FOREIGN KEY (U_id) REFERENCES users(P_id));
This created the table I wanted just fine (although a "DESCRIBE actions;" command showed me that the foreign keys were keys of type MUL, and I'm not sure what this means). However, when I try to enter a Q_id or a U_id that does not exist in the questions or users tables, MySQL still allows these values.
What did I do wrong? How can I prevent a table with a foreign key from accepting invalid data?
UPDATE 1
If I add TYPE=InnoDB to the end, I get an error:
ERROR 1005 (HY000): Can't create table './quotes/actions.frm' (errno: 150)
Why might that happen?
UPDATE 2
I'm told that it's important to enforce data integrity with functional foreign keys, but also that InnoDB should not be used with MySQL. What do you recommend?
I would guess that your default storage engine is MyISAM, which ignores foreign key constraints. It silently accepts the declaration of a foreign key, but does not store the constraint or enforce it subsequently.
However, it does implicitly create an index on the columns you declared for the foreign key. In MySQL, "KEY" is a synonym for "INDEX". That's what's being shown in the DESCRIBE output: an index, but not a constraint.
You are able to insert invalid values to the table right now because there is no constraint. To get a constraint that enforces referential integrity, you must use the InnoDB storage engine:
CREATE TABLE actions (
A_id int NOT NULL AUTO_INCREMENT,
...
CONSTRAINT fk_Question FOREIGN KEY (Q_id) REFERENCES questions(P_id),
CONSTRAINT fk_User FOREIGN KEY (U_id) REFERENCES users(P_id)
) ENGINE=InnoDB;
I've always thought it was a big mistake on MySQL's part to silently ignore foreign key constraint declarations. There's no error or warning that the storage engine doesn't support them.
The same is true for CHECK constraints before MySQL 8.0.16. No storage engine used with MySQL supported CHECK constraints, but the SQL parser accepts them with no complaint. In 8.0.16 and later, InnoDB tables do support CHECK constraints but other storage engines still ignore them.
The errno 150 issue occurs when it cannot create the InnoDB table, because it couldn't make sense of the foreign key constraint. You can get some more information with:
SHOW ENGINE INNODB STATUS;
Some requirements for InnoDB foreign keys:
Referenced table must also be InnoDB.
Referenced table must have an index and a primary key.
SQL data types of FK column and referenced PK column must be identical. For example, INT does not match BIGINT or INT UNSIGNED.
You can change the storage engine of a table that has data in it:
ALTER TABLE actions ENGINE=InnoDB;
This effectively copies the entire MyISAM table to an InnoDB table, then once that succeeds it drops the MyISAM table and renames the new InnoDB table to the name of the former MyISAM table. This is called a "table restructure" and it can be time-consuming, depending on how much data is in the table. A table restructure occurs during ALTER TABLE, even in some cases where it may seem unnecessary.
Re your update 2:
I'm told that it's important to enforce data integrity with functional foreign keys, but also that InnoDB should not be used with MySQL. What do you recommend?
Who told you that? It's absolutely false. InnoDB has better performance than MyISAM (though InnoDB needs more attention to tuning the configuration), InnoDB supports atomic changes, transactions, foreign keys, and InnoDB is much more resistant to corrupting data in a crash.
Unless you're running an old, unsupported version of MySQL (5.0 or earlier) you should use InnoDB as your default storage engine choice, and use MyISAM only if you can demonstrate a specific workload that benefits from MyISAM.
Just to save other's of the hours of headache I've been thru - as giraffa touches upon, ensure #FOREIGN_KEY_CHECKS is set to 1.
SELECT ##FOREIGN_KEY_CHECKS
SET FOREIGN_KEY_CHECKS=1
I know this thread was opened long time ago, but I am posting this message for future users who will look for the answer.
I was having the same problem with foreign key in mysql.
The following thing worked for me.
Parent table:
CREATE TABLE NameSubject (
Autonumber INT NOT NULL AUTO_INCREMENT,
NameorSubject nvarchar(255),
PRIMARY KEY (Autonumber)
) ENGINE=InnoDB;
Child Table:
CREATE TABLE Volumes (
Autonumber INT NOT NULL,
Volume INT,
Pages nvarchar(50),
Reel int,
Illustrations bit,
SSMA_TimeStamp timestamp,
Foreign KEY (Autonumber) references NameSubject(Autonumber)
ON update cascade
)engine=innodb;
"ON update cascade" did the magic for me.
I hope this works for others. Best of luck.
For those who still have problems with mysql ignoring foreign keys constraints and for those who the answers above or in any other related question didn't solve teir puzzle, here is what I found to be the issue.
If you declare your foreign keys as such
id INTEGER UNSIGNED REFERENCES A_Table(id)
Then the foreign key seems to be ignored, to enforce the constraint without (apparently) having to use any of the SET commands, use the following declaration.
id INTEGER UNSIGNED,
CONSTRAINT fk_id FOREIGN KEY (id) REFERENCES A_Table(id)
This way solved the problem for me. Not sure why, as many say the first declaration is only a shorthand to the second variant.
I found the following article. I don't have time to test it out, currently, but it may be helpful:
http://forums.mysql.com/read.php?22,19755,43805
The author,Edwin Dando, says:
both tables must be INNODB. The foreign key field must have an index on it. The foeign key field and the field being referenced must be of the same type (I only use integer) and, after hours of pain, they must be UNSIGNED.
the problem is most likely that questions.p_id and users.p_id are not defined as INT NOT NULL. for foreign keys to work, the definition of the columns on both side of the foreign key must match exactly, with the exception of auto_increment and default.
This answer would have saved me a lot of time if I'd seen it first. Try the following three steps, which I've ordered by frequency of newbie mistakes:
(1) Change the table to be InnodDB by appending "ENGINE=InnoDB" to your "CREATE TABLE" statements.
Other engines, which may be the default, do not support foreign key constraints, but neither do they throw an error or warning telling you they're not supported.
(2) Make sure foreign key constraints are in fact being checked by executing "SET foreign_key_checks = 'ON'"
(3) Append "ON UPDATE CASCADE" to your foreign key declaration.
Note: Make sure that cascading is the behavior you want. There are other options...
As noted, your table have to be InnoDB for FK constraints to be enforced.
I've only run into the 'Can't create table' in the case where I'm trying to create a foreign key constraint where my local column is a different type from the foreign column.
I think some of the folks having this problem might be starting out with some of the sample databases provided on the ORACLE website for MYSQL (e.g. sakila DB). Don't forget to "turn the foreign key constraints back on" at the end of your script (e.g. at the beginning of sakila DB script they are turned OFF)
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL';
create your tables here
then don't forget this:
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
Well, my guess is somehow the "Skip creation of FORIEN KEYS" option is checked, it can happen in the "options" section of the "Forward Engineering" process.