What is the difference between these two SQL queries? - mysql

I've created table Address with this SQL query:
CREATE TABLE `address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`Street` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Number` smallint(6) DEFAULT NULL,
`other_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
But there's also this query:
CREATE TABLE `address` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`Street` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`Number` smallint(6) DEFAULT NULL,
`other_id` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
KEY `other_id` (`other_id`),
CONSTRAINT `adress_ibfk_1` FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$
and it seems that booth query create identical tables.
So can anyone explain to me what does this line do:
KEY `other_id` (`other_id`),
and what is the difference between these two lines:
FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
and
CONSTRAINT `adress_ibfk_1` FOREIGN KEY (`other_id`) REFERENCES `other` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
If the difference between last two lines is that latter gives name 'adress_ibfk_1' to foreign key ? If that's true - should I do it ? I mean, why should I name foreign keys ? Will I ever need their names ?
Thanks ! :)

MySQL interprets KEY as an index, so the second query creates an index on the column other_id.
The difference between the two FK declaration is that you manually set the name in the second line. In the first line, MySQL automatically sets a name.
They do need names, but you don't necessarily have to be aware of them. Some more advanced RDBMS use them to be more explicit when a query raises an error.

KEY is a synonym for INDEX, so that is creating an index on the other_id column.
The only difference in the foreign key construction is that the latter constraint version allows you to name the constraint, whereas the former will be given a system generated name.
This name can be seen in the INFORMATION_SCHEMA TABLE_CONSTRAINTS table.

Related

MySQL drop unique key: needed in a foreign key constraint

Hello I`ve a table which look like this
CREATE TABLE `ratings` (
`id` bigint NOT NULL,
`profile_id` bigint NOT NULL,
`stars` enum('1','2','3','4','5') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`survey_id` bigint DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ratings_profile_id_email_unique` (`profile_id`,`email`),
UNIQUE KEY `ratings_token_unique` (`token`),
KEY `survey_id` (`survey_id`),
CONSTRAINT `ratings_ibfk_1` FOREIGN KEY (`survey_id`) REFERENCES `surveys` (`id`),
CONSTRAINT `ratings_profile_id_foreign` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
My goal is to delete the ratings_profile_id_email_unique key. I tried this statement
alter table ratings drop key ratings_profile_id_email_unique;
This produces: Cannot drop index 'ratings_profile_id_email_unique': needed in a foreign key constraint
What is wrong? How can a unique key needed in a fk constraint?
In SQL, in general, a foreign key constraint can refer to either a primary key or a unique key. MySQL extends this to any indexed column(s), but that is not relevant here.
Somewhere in your data model, you have a foreign key reference using these two keys instead of id. You need to fix such references in order to delete the index.
If you don't know where this is, you can use the information_schema tables, such as information_schema.referential_constraints and information_schema.key_column_usage.
For instance, this gets foreign key constraints that reference t:
select *
from information_schema.referential_constraints rc
where rc.referenced_table_name = 't'
(You may want to include the schema in them.) This is probably enough information, but if you need more key_column_usage can be more specific on the keys being used.

Simple Relation between 2 tables

I have a problem here.
I cannot add this to my db because one table is dependent of another and vice-versa.
So I get
Cannot add foreign key constraint
on the first create table that I put
How can I add this 2 tables if they both have constraints??
-- User Roles
CREATE TABLE IF NOT EXISTS `user_roles` (
`user_role_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(45) NOT NULL,
`role` varchar(45) NOT NULL,
PRIMARY KEY (`user_role_id`),
UNIQUE KEY `uni_username_role` (`role`,`username`),
UNIQUE KEY `ix_auth_username` (`username`,`role`),
KEY `fk_username_idx` (`username`),
CONSTRAINT `fk_username` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
-- Users
CREATE TABLE IF NOT EXISTS `users` (
`username` varchar(45) NOT NULL,
`name` varchar(45) DEFAULT NULL,
`hashedPassword` varchar(500) NOT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT '1',
`image` mediumblob,
`team` int(11) DEFAULT NULL,
`userRole` int(11) DEFAULT NULL,
PRIMARY KEY (`username`),
KEY `fkteam_idx` (`team`),
KEY `fkrole_idx` (`userRole`),
CONSTRAINT `fkrole` FOREIGN KEY (`userRole`) REFERENCES `user_roles` (`user_role_id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fkteam` FOREIGN KEY (`team`) REFERENCES `team` (`idteam`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
To do this, you'll need to use deferrable constraint checks, but unfortunately MySQL does not implement this standard SQL feature.
As far as I know, only Oracle and PostgreSQL support this feature (deferrable constraints). These constraints are checked at the end of the transaction, and not on every single row insertion. That would solve your problem.
Therefore, you have two options:
Switch to Oracle or PostgreSQL (unlikely, I guess) or,
Change your table definition to allow one of the foreign key constraints to accept null values.
In the second case, you would:
Insert in the table that allow null in the FK, getting the generated ID.
Insert in the other table using the ID. Then, get the second generated ID.
Update the null in first table using the second ID.
Commit.
That's it.

On Cascade Delete does not seem to be applying in my DB

I don't know what I am doing wrong as I've been looking at previous answers on this site concerning ON CASCADE DELETE.
Basically this is my table:
CREATE TABLE `directorycolumntags` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`directorycolumn_id` INT(11) NOT NULL,
`tag_id` INT(11) NOT NULL,
`description` TEXT,
`created` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`directorycolumn_id`) REFERENCES directorycolumn(id),
CONSTRAINT FOREIGN KEY (`tag_id`) REFERENCES tag(id)
ON DELETE CASCADE
) ENGINE=MYISAM AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
The Foreign key references the id of the tag table:
CREATE TABLE `tag` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(200) DEFAULT NULL,
`description` TEXT,
PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=29 DEFAULT CHARSET=utf8;
Now, If I perform this query to INSERT some data into the directorycolumntags table it works:
INSERT INTO directorycolumntags (directorycolumn_id, tag_id) VALUES (178,32);
However, when I DELETE the entry from the tag table with the id of 32 it does not remove the row from the directorycolumntags table. Can anyone point out where I am going wrong?
It's because your table directorycolumntags is MYISAM, not INNODB. MyISAM doesn't support foreign keys. You can write your foreign key statements, but MySQL silently ignores them.
Try this:
ALTER TABLE `directorycolumntags` ENGINE = 'InnoDB';

Foreign constraint On Delete Cascade not working

I have a custom table created which has a foreign constraint on the core_website table. However, the on delete cascade isn't working.
I did a search and found this relevant thread, which notes that the data types between the two columns have to be the same. Both data types are smallint(5).
I did notice one minor discrepancy in the column definition, which is that in core_website, Allow Null is not set, and Default is not set to zero, whereas in the account table, Allow Null is set and Default is zero. I didn't think changing these would have any effect, but I went ahead and changed them on the account table to match, but that didn't help.
CREATE TABLE `account` (
`account_id` smallint(11) unsigned NOT NULL AUTO_INCREMENT,
`website_id` smallint(5) unsigned DEFAULT '0',
`code` varchar(64) NOT NULL DEFAULT '',
PRIMARY KEY (`account_id`),
UNIQUE KEY `code` (`code`),
KEY `FK_WEBSITE_ID` (`website_id`),
CONSTRAINT `FK_WEBSITE_ID` FOREIGN KEY (`website_id`) REFERENCES `core_website` (`website_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8
try this and let us the result pls.
CREATE TABLE `account` (
`account_id` smallint(11) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY,
`website_id` smallint(5) unsigned DEFAULT '0',
`code` varchar(64) NOT NULL DEFAULT '',
UNIQUE KEY `code` (`code`),
KEY `FK_WEBSITE_ID` (`website_id`),
CONSTRAINT `FK_WEBSITE_ID` FOREIGN KEY (`website_id`) REFERENCES `core_website` (`website_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8
You need add foreign key to core_website table and point it to website_id field in account table. In other words, foreign key should be added to the dependent table and pointed to main table, in this case when you delete row from main table - row from dependent table will be deleted because of FK. In your case you did it "upside down".

MySQL Foreign Key Constraint Confusion

Hey everyone, I have the following 'users' table in MySQL:
CREATE TABLE `users` (
`uid` int(11) NOT NULL auto_increment,
`fname` varchar(50) NOT NULL,
`lname` varchar(50) NOT NULL,
`role` varchar(75) NOT NULL,
`region` tinyint(4) unsigned default NULL,
`username` varchar(25) NOT NULL,
`password` varchar(75) NOT NULL,
`new_pass` varchar(5) default NULL,
PRIMARY KEY (`uid`),
UNIQUE KEY `username` (`username`),
KEY `role` (`role`),
KEY `region` (`region`),
CONSTRAINT `users_ibfk_3` FOREIGN KEY (`role`) REFERENCES `role` (`role`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `users_ibfk_4` FOREIGN KEY (`region`) REFERENCES `region` (`region`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8
I have 'region' set as a foreign key to a region table - region.region'
Notice, that users.region is declared as NULL. I was under the impression that in MySQL, a foreign key contstraint is enforced ONLY if the key is set as NOT NULL.
However, when I try to insert a user with a NULL region in my PHP application, I get the following error:
ERROR: Cannot add or update a child row: a foreign key constraint fails (`reslife4/users`, CONSTRAINT `users_ibfk_4` FOREIGN KEY (`region`) REFERENCES `region` (`region`) ON DELETE CASCADE ON UPDATE CASCADE)
BUT, if I were to add this user outside of my PHP application, for example in phpMyAdmin, it would allow me to.
Does anyone know what's going on?
Your application puts a non-NULL value into region.
Enable the query log and see what exactly your PHP tries to insert into the table.