MYSQL - foreign key varchar column - mysql

I would like to add localization to my database. I created languages table and I would like to add foreign key to user table:
CREATE TABLE `users` (
`id` int(11) NOT NULL,
`name` varchar(30) NOT NULL,
`email` varchar(100) NOT NULL,
`password` varchar(60) DEFAULT NULL,
`registrationDate` datetime DEFAULT current_timestamp(),
`lastLoginDate` datetime DEFAULT NULL,
`isConfirmed` tinyint(1) NOT NULL DEFAULT 0,
`activationKey` varchar(32) NOT NULL,
`resendEmail` tinyint(1) DEFAULT NULL,
`subscribedNews` tinyint(1) NOT NULL DEFAULT 1,
`activated` tinyint(1) DEFAULT 1,
`lang` varchar(5) NOT NULL DEFAULT 'en'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `email` (`email`);
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
create table languages(
code varchar(5) primary key,
name varchar(255) not null,
dateFormat varchar(255),
dateTimeFormat varchar(255),
currency varchar(255)
);
ALTER TABLE users
ADD lang varchar(5) NOT NULL DEFAULT 'cs';
ALTER TABLE users ADD CONSTRAINT fk_user_lang FOREIGN KEY (lang) REFERENCES languages(code);
I can't add foreign key on lang column:
error code: 150 "Foreign key constraint is incorrectly formed"
Why I can't create varchar foreign key. I would not add int primary key in languages table, because, I would like to get data from database as /api/users/cs instead of /api/users?lang=1.
Thanks

You didn't specify the character set or collation for the languages table.
Whereas users is explicitly utf8, you might be using a MySQL version where the default charset is utf8mb4 or a very old version where the default charset is latin1.
Double-check with:
SHOW CREATE TABLE languages\G
That will display the charset and collation for that table. It must be the same as the charset and collation for the foreign key column in users.

If you change the default character set of the table languages to utf8, which you defined for the table users, then it will work:
ALTER TABLE languages CONVERT TO CHARACTER SET utf8;
See the demo.

Related

Getting cannot find an index in the referenced table error

Cannot find an index in the referenced table where the referenced columns appear as the first columns, or column types in the table and the referenced table do not match for constraint. Note that the internal storage type of ENUM and SET changed in tables created with >= InnoDB-4.1.12, and such columns in old tables cannot be referenced by such columns in new tables.
Above is the full description of error im getting. i checked the indexes of both table and should be fine but it still gives me this error.
Below is the tables structure.
CREATE TABLE `contact_address` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`address_type` int(5) DEFAULT NULL,
`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`postcode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`area` int(5) DEFAULT NULL,
`state` int(5) DEFAULT NULL,
`country` char(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`fax` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`contact_branch_id` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(4) DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
`updated_by` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fk_c_a_area` (`area`),
KEY `fk_c_a_state` (`state`),
KEY `fk_c_a_country` (`country`),
KEY `fk_c_a_contact_branch_id` (`contact_branch_id`),
KEY `fk_c_a_created_by` (`created_by`),
CONSTRAINT `fk_c_a_area` FOREIGN KEY (`area`) REFERENCES `ref_area` (`area_id`),
CONSTRAINT `fk_c_a_contact_branch_id` FOREIGN KEY (`contact_branch_id`) REFERENCES `contact_branch` (`id`),
CONSTRAINT `fk_c_a_created_by` FOREIGN KEY (`created_by`) REFERENCES `user` (`id`),
CONSTRAINT `fk_c_a_state` FOREIGN KEY (`state`) REFERENCES `ref_state` (`state_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `ref_countries` (
`country_code` char(2) NOT NULL,
`country_id` int(11) NOT NULL AUTO_INCREMENT,
`country_name` varchar(80) NOT NULL,
`alpha_3` char(3) DEFAULT NULL,
`calling_code` int(5) NOT NULL,
`continent_name` varchar(30) DEFAULT NULL,
PRIMARY KEY (`country_code`),
KEY `country_id` (`country_id`)
) ENGINE=InnoDB AUTO_INCREMENT=253 DEFAULT CHARSET=utf8mb4;
Im trying to run this and giving me the error.
ALTER TABLE `contact_address`
ADD CONSTRAINT `fk_c_a_countries` FOREIGN KEY (`country`)
REFERENCES `ref_countries` (`country_code`);
The error message you're getting suggests that there's a problem with the foreign key constraint that you're trying to add to the contact_address table. Based on the table definitions you've provided, there are a couple of things that could be causing the issue:
The data type of the country column in the contact_address table is char(2), while the data type of the country_code column in the ref_countries table is char(2) NOT NULL. The NOT NULL constraint on the country_code column may be causing the problem.
Another possibility is that the ref_countries table have not have AUTO_INCREMENT on country_code column, but the contact_address table's country column is referencing that.
You can try the following:
Remove the NOT NULL constraint from the country_code column in the ref_countries table.
Add AUTO_INCREMENT to the country_code column in the ref_countries table.
Also, make sure that there is a matching value in the ref_countries table for each value of the country column in the contact_address table.

Create a relationship between the tables when the table is first created

I use mysql
in my database
I want to create multiple tables with delete and update relationship
as an example
I want to link the profiles table to the users table
Associate the mm_id_user column from the users table with the mm_id_profile column from the profiles table
What I actually tried to do is this example and it didn't work for me
https://stackoverflow.com/a/260453/10206991
https://stackoverflow.com/a/9796950/10206991
The code used to create the users table and it succeeds in creating the table
CREATE TABLE users (
mm_email VARCHAR(255) NOT NULL,
mm_id_user int NOT NULL AUTO_INCREMENT,
mm_name VARCHAR(25) NOT NULL,
mm_password VARCHAR(255) NOT NULL,
mm_code_reset_pass VARCHAR(100) NOT NULL,
mm_code_check_email VARCHAR(100) NOT NULL,
mm_status CHAR(1) NOT NULL DEFAULT '0',
mm_date_create_account TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mm_date_last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mm_is_login CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (mm_id_user, mm_email)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;
The code used to create the profiles table. He failed to create the table
CREATE TABLE profiles (
mm_id_profile VARCHAR(255) NOT NULL,
mm_image_user TEXT NOT NULL,
mm_num_stores_all VARCHAR(4) NOT NULL,
mm_num_stores_exist VARCHAR(4) NOT NULL,
mm_name_public VARCHAR(25) NOT NULL,
mm_email_public VARCHAR(255) NOT NULL,
mm_phone_public VARCHAR(20) NOT NULL,
mm_location_public TEXT NOT NULL,
mm_update_date TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX index_profiles(mm_name_public, mm_email_public),
PRIMARY KEY (mm_id_profile),
FOREIGN KEY (mm_id_profile) REFERENCES users(mm_email) ON DELETE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;
But if you remove the following line from the profiles table, it will be created
But there is definitely no relationship between the two tables
FOREIGN KEY (mm_id_profile) REFERENCES users(mm_email) ON DELETE CASCADE
This is the error message that appears when creating a profiles table
#1005 - Can't create table `mustforu_test`.`profiles` (errno: 150 "Foreign key constraint is incorrectly formed") (Details…)
There's no reason to put both mm_id_user and mm_email in the primary key of users. If you want emails to be unique, it should have its own unique index. Your current primary key would allow duplicate emails with different IDs.
CREATE TABLE users (
mm_email VARCHAR(255) NOT NULL,
mm_id_user int NOT NULL AUTO_INCREMENT,
mm_name VARCHAR(25) NOT NULL,
mm_password VARCHAR(255) NOT NULL,
mm_code_reset_pass VARCHAR(100) NOT NULL,
mm_code_check_email VARCHAR(100) NOT NULL,
mm_status CHAR(1) NOT NULL DEFAULT '0',
mm_date_create_account TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mm_date_last_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mm_is_login CHAR(1) NOT NULL DEFAULT '0',
PRIMARY KEY (mm_id_user),
UNIQUE KEY (mm_email)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;
Giving mm_email its own index will allow the foreign key in profiles to work.

FK constraint is incorrectly formed ERROR

I got the following error message whenever I try to import this sql file to my localhost
(#1005 - Can't create table hostel_management_system.Hostel_Manager (errno: 150 "Foreign key constraint is incorrectly formed"))
Here is the sql:
DROP TABLE IF EXISTS `Hostel_Manager`;
CREATE TABLE `Hostel_Manager` (
`Hostel_man_id` int(10) NOT NULL AUTO_INCREMENT,
`Username` varchar(255) NOT NULL,
`Fname` varchar(255) NOT NULL,
`Lname` varchar(255) NOT NULL,
`Mob_no` varchar(255) NOT NULL,
`Hostel_id` int(10) NOT NULL,
`Pwd` LONGTEXT NOT NULL,
`Isadmin` tinyint(1) DEFAULT '0',
PRIMARY KEY (`Hostel_man_id`),
UNIQUE (`Username`),
KEY `Hostel_id` (`Hostel_id`),
CONSTRAINT `Hostel_Manager_ibfk_1` FOREIGN KEY (`Hostel_id`) REFERENCES `Hostel` (`Hostel_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
LOCK TABLES `Hostel_Manager` WRITE;
UNLOCK TABLES;
Hostel table :
CREATE TABLE `Hostel` (
`Hostel_id` int(10) NOT NULL AUTO_INCREMENT,
`Hostel_name` varchar(255) NOT NULL,
`current_no_of_rooms` varchar(255) DEFAULT NULL,
`No_of_rooms` varchar(255) DEFAULT NULL,
`No_of_students` varchar(255) DEFAULT NULL,
PRIMARY KEY (`Hostel_id`)
)
Why do I get that error and how to fix it?
Both the parent and children column have the same datatype and length, and the parent column is a primary colum, so that's not the issue here.
I suspect that the problem is the charset. Hostel_Manager specifies a default charset, while Hostel does not. If the default charset of your database is something else than latin1, then the foreign is malformed.
I would recommend explictly aligning the charset so it is the same for both tables (either remove both, or declare the same value).
Note that both tables also need to have the same storage engine. InnoDB is the default, so that should not be an issue, but you might want to explictly align that as well (in case the default of your database is MyISAM).

MySQL Error #1215 - Cannot Add Foreign Key Constraint

I have the following problem with a pretty simple MySQL database table creation:
SQL query:
CREATE TABLE IF NOT EXISTS comments(
commentId INT NOT NULL AUTO_INCREMENT,
comment VARCHAR(1024) NOT NULL,
commentdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
profileId INT NOT NULL,
PRIMARY KEY(commentId),
CONSTRAINT fk_ProfilesProfileId FOREIGN KEY(profileId) REFERENCES profiles.profileId ON UPDATE RESTRICT ON DELETE CASCADE
)Engine=InnoDB DEFAULT CHARSET utf8 COLLATE utf8_general_ci
Error:
MySQL said: Documentation
#1215 - Cannot add foreign key constraint
As you can see, the error number is 1215, which would indicate that the problem is about Foreign Key and Primary Key in comments and profiles tables (respectively) being different types. However, I have checked multiple times that they both are INT(11) and signed.
Here are queries for both of them:
'profiles' -table
CREATE TABLE IF NOT EXISTS profiles(
profileId INT NOT NULL AUTO_INCREMENT,
corpname VARCHAR(512) NOT NULL DEFAULT 'VIRHE',
corpserial VARCHAR(16) NOT NULL DEFAULT 'VIRHE',
loginusername VARCHAR(128) NOT NULL,
loginpassword VARCHAR(128) NOT NULL,
profilephone VARCHAR(16),
mapsphone VARCHAR(16),
added TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
done TIMESTAMP DEFAULT NULL,
coderequest TIMESTAMP DEFAULT NULL,
confirmed TIMESTAMP DEFAULT NULL,
PRIMARY KEY(profileId),
INDEX corpnameIndex (corpname),
INDEX corpserialIndex (corpserial)
)Engine=InnoDB DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
'comments' -table
CREATE TABLE IF NOT EXISTS comments(
commentId INT NOT NULL AUTO_INCREMENT,
comment VARCHAR(1024) NOT NULL,
commentdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
profileId INT NOT NULL,
PRIMARY KEY(commentId),
CONSTRAINT fk_ProfilesProfileId FOREIGN KEY(profileId) REFERENCES profiles.profileId ON UPDATE RESTRICT ON DELETE CASCADE
)Engine=InnoDB DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
It is possible that I am dumb, and I'm just missing something. Hopefully it's so.
I replicated your example locally. It seems that the problem is how you declare your constraint for the foreign key.
CREATE TABLE profiles (
profileId int(11) NOT NULL AUTO_INCREMENT,
corpname varchar(512) NOT NULL DEFAULT 'VIRHE',
corpserial varchar(16) NOT NULL DEFAULT 'VIRHE',
loginusername varchar(128) NOT NULL,
loginpassword varchar(128) NOT NULL,
profilephone varchar(16) DEFAULT NULL,
mapsphone varchar(16) DEFAULT NULL,
added timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
done timestamp NULL DEFAULT NULL,
coderequest timestamp NULL DEFAULT NULL,
confirmed timestamp NULL DEFAULT NULL,
PRIMARY KEY (profileId),
KEY corpnameIndex (corpname(255)),
KEY corpserialIndex (corpserial)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS comments(
commentId INT NOT NULL AUTO_INCREMENT,
comment VARCHAR(1024) NOT NULL,
commentdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
profileId INT NOT NULL,
PRIMARY KEY(commentId),
CONSTRAINT fk_ProfilesProfileId FOREIGN KEY(profileId) REFERENCES profiles(profileId) ON UPDATE RESTRICT ON DELETE CASCADE
)Engine=InnoDB DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
with respect to your code:
The syntax for the foreign key after REFERENCES is table(field) rather than table.field
TIMESTAMP DEFAULT NULL should be TIMESTAMP NULL.
Note the partial index corpnameIndex, some considerations follow hereunder.
Some information about indexes the engine you want to use is InnoDB, which specifies that (from here):
By default, an index key for a single-column index can be up to 767
bytes. The same length limit applies to any index key prefix. See
Section 13.1.13, “CREATE INDEX Syntax”. For example, you might hit
this limit with a column prefix index of more than 255 characters on a
TEXT or VARCHAR column, assuming a UTF-8 character set and the maximum
of 3 bytes for each character. When the innodb_large_prefix
configuration option is enabled, this length limit is raised to 3072
bytes, for InnoDB tables that use the DYNAMIC and COMPRESSED row
formats.
The problem in your table is INDEX corpnameIndex (corpname), because this index would be 512*3 = 1536 bytes long.
You have some options here:
Change corpname size to 255 by declaring it as follows corpname VARCHAR(255) NOT NULL DEFAULT 'VIRHE'
Enable innodb_large_prefix on your mysql by running set global innodb_large_prefix = ON;. This will bring the limit to 3072 bytes (1024 chars).
Index only a part of your corpname field by using ADD INDEX (corpname(255))

MySQL 5.5 add foreign key fails with errors [HY000][150] and [HY000][1005]

I have tried adding a foreign key like this...
ALTER TABLE OrderLineItem
ADD CONSTRAINT
FK_OrderLineItem_ShippingType_name FOREIGN KEY
(shippingType)
REFERENCES ShippingType(name);
Or like this in Mysql 5.5...
alter table OrderLineItem add foreign key
FK_OrderLineItem_ShippingType (shippingType) references ShippingType(name);
Every time I see the following error.
[2011-11-18 15:07:04] [HY000][150] Create table
'realtorprint_dev_dev/#sql-7d0_80' with foreign key constraint failed.
There is no index in the referenced table where the referenced columns
appear as the first columns.
[2011-11-18 15:07:04] [HY000][1005] Can't create table
'realtorprint_dev_dev.#sql-7d0_80' (errno: 150)
Both OrderLineItem.shippingType and ShippingType.name have a type of varchar(50) not null. ShippingType.name is the primaryKey of ShippingType.
Here is the result of show create table on ShippingType as well as OrderLineItem...
CREATE TABLE `shippingtype` (
`name` varchar(50) CHARACTER SET latin1 NOT NULL DEFAULT '',
`description` varchar(255) CHARACTER SET latin1 NOT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `orderlineitem` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`description` varchar(255) CHARACTER SET latin1 NOT NULL,
`lineNumber` int(11) NOT NULL,
`quantity` int(11) NOT NULL,
`quantityMultiplier` int(11) NOT NULL,
`unitPrice` decimal(10,2) NOT NULL,
`order_id` bigint(20) NOT NULL,
`productDefinition_id` bigint(20) NOT NULL,
`mlsId` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
`printProviderUnitCost` decimal(10,2) NOT NULL,
`shippingType` varchar(50) NOT NULL,
`address` varchar(255) DEFAULT NULL,
`zipPostal` varchar(255) NOT NULL,
`city` varchar(255) NOT NULL,
`stateProvince` varchar(255) NOT NULL,
`country` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_OrderLineItem_productDefinition_id` (`productDefinition_id`),
KEY `idx_OrderLineItem_order_id` (`order_id`),
CONSTRAINT `FK_OrderLineItem_order_id` FOREIGN KEY (`order_id`) REFERENCES `userorder` (`id`),
CONSTRAINT `FK_OrderLineItem_productDefinition_id` FOREIGN KEY (`productDefinition_id`) REFERENCES `productdefinition` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10029 DEFAULT CHARSET=utf8;
It is possible is that Mysql gives this bad error when the column types do not match exactly - check collation / size etc.
orderLineItem.shippingType has character set utf8, but ShippingType.name has character set latin1. These are not compatible for the purposes of foreign key references.
Data type mismatches or PK not declared properly on referenced based tables.