SQL Foreign Key - mysql

I'm reading a book about e-commerce. In this book I found the folowing SQL code:
CREATE TABLE `orders` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`users_id` INT UNSIGNED NOT NULL,
`transaction_id` VARCHAR(45) NOT NULL,
`payment_status` VARCHAR(45) NOT NULL,
`payment_amount` INT UNSIGNED NOT NULL,
`date_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `date_created` (`date_created` ASC),
INDEX `transaction_id` (`transaction_id` ASC),
CONSTRAINT `fk_orders_users1`
FOREIGN KEY (`id`)
REFERENCES `users` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
The book says that the CONSTRAINT would prevent the insertion of a "users_id" that doesn't match a 'id' in the table 'users'. By reading the code, I believe the book is wrong, because I believe this code would acctualy prevent the insertion of a "id" (in the table "orders") that doesn't match the field "id" (in the table users). I am right?
Sorry for bad english. I'm not american and trying my best...

Corrected code:
CREATE TABLE `orders` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`users_id` INT UNSIGNED NOT NULL,
`transaction_id` VARCHAR(45) NOT NULL,
`payment_status` VARCHAR(45) NOT NULL,
`payment_amount` INT UNSIGNED NOT NULL,
`date_created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
INDEX `date_created` (`date_created` ASC),
INDEX `transaction_id` (`transaction_id` ASC),
CONSTRAINT `fk_orders_users1`
FOREIGN KEY (`users_id`)
REFERENCES `users` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION
) ENGINE = InnoDB DEFAULT CHARSET=utf8;

Related

MySQL UNIQUE KEY and FOREIGN KEY same column not getting created

I have following tables/CREATE sintaxis:
CREATE TABLE `users` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`parentId` int(10) unsigned DEFAULT NULL,
`fullName` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`alias` varchar(35) COLLATE utf8_unicode_ci DEFAULT NULL,
`username` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`password` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
UNIQUE KEY `uk_parentId_fullName_alias` (`parentId`,`fullName`,`alias`),
KEY `fk_users_parentId` (`parentId`),
CONSTRAINT `fk_users_parentId` FOREIGN KEY (`parentId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `userSettings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(11) unsigned NOT NULL,
`settingsArray` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_userId` (`userId`),
KEY `fk_userSettings_userId` (`userId`),
CONSTRAINT `fk_userSettings_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
im trying to create one table with user data and another one with the user settings, when i create the userSettings table it doesnt create the foreign key, is there something wrong with the create sintaxis? It is related with creating two indexes for same column?
Here what i get after creating the userSettings table:
CREATE TABLE `userSettings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(11) unsigned NOT NULL,
`settingsArray` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_userId` (`userId`),
KEY `fk_userSettings_userId` (`userId`)
) ENGINE=MyISAM AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
As you discovered, MyISAM doesn't support foreign keys. Both users and userSettings must be InnoDB.
[I'm] just curious if having a UNIQUE_KEY and FOREIGN_KEY in same column is a good practice
This means the userSettings table can have at most one row for each userId. I guess you need only one row per userId because you store an "array" of settings encoded somehow in your settingsArray TEXT column. This is not a good practice.
You should either store each setting in its own column:
CREATE TABLE `userSettings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(11) unsigned NOT NULL,
`isAdmin` bool NOT NULL,
`timezone` varchar(10) NOT NULL,
`theme` varchar(10) NOT NULL,
...other settings...
PRIMARY KEY (`id`),
UNIQUE KEY `uk_userId` (`userId`),
KEY `fk_userSettings_userId` (`userId`)
)
Or else store multiple rows per userId, with one setting name and value per row.
CREATE TABLE `userSettings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`userId` int(11) unsigned NOT NULL,
`setting` varchar(20) NOT NULL,
`value` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_userId` (`userId`,`setting`),
KEY `fk_userSettings_userId` (`userId`)
)
It's also puzzling why you need an id column for the primary key, if the userId is already NOT NULL and UNIQUE, and that's probably the key you'll use to look up rows anyway. You can make the userId the PRIMARY KEY as well (or userId, setting in the second example), and omit the id column.
Just realized for the table users the ENGINE was InnoDB and for the userSettings table ENGINE was MyISAM, changed that and worked, im just curious if having a UNIQUE_KEY and FOREIGN_KEY in same column is a good practice

mysql ignore index for order by on join

CREATE TABLE `call_session` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`contact_id` bigint(20) unsigned NOT NULL,
`campaign_id` bigint(20) unsigned DEFAULT NULL,
`user_id` bigint(20) unsigned DEFAULT NULL,
`start_time` datetime DEFAULT NULL,
`end_time` datetime DEFAULT NULL,
`type` varchar(16) DEFAULT NULL,
`status` varchar(16) DEFAULT NULL,
`continue_reason_id` bigint(20) unsigned DEFAULT NULL,
`continue_by` bigint(20) unsigned DEFAULT NULL,
`end_reason_id` bigint(20) unsigned DEFAULT NULL,
`comment` varchar(255) DEFAULT '',
`call_count` int(11) NOT NULL DEFAULT '0',
`answered_call_count` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `ix_call_session_contact_id` (`contact_id`),
KEY `ix_call_session_user_id` (`user_id`),
KEY `ix_call_session_campaign_id` (`campaign_id`),
KEY `call_session_continue_by_foreign` (`continue_by`),
KEY `call_session_end_reason_id_foreign` (`end_reason_id`),
KEY `ix_call_session_end_time` (`end_time`),
KEY `ix_call_session_start_time` (`start_time`),
KEY `ix_call_session_continue_reason_id` (`continue_reason_id`),
CONSTRAINT `call_session_campaign_id_foreign` FOREIGN KEY (`campaign_id`) REFERENCES `campaign` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `call_session_continue_by_foreign` FOREIGN KEY (`continue_by`) REFERENCES `user` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `call_session_continue_reason_id_foreign` FOREIGN KEY (`continue_reason_id`) REFERENCES `continue_reason` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `call_session_end_reason_id_foreign` FOREIGN KEY (`end_reason_id`) REFERENCES `end_reason` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT `call_session_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
)
CREATE TABLE `continue_reason` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`project_id` bigint(20) unsigned DEFAULT NULL,
`sort` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `ix_continue_reason_project_id` (`project_id`),
CONSTRAINT `continue_reason_project_id_foreign` FOREIGN KEY (`project_id`) REFERENCES `project` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
)
The call_session table contain more than 500,000 rows.
The continue_reason table contain only one row.
When I join the continue_reason table for the name column, mysql ignore the start_date index so the query takes between 1.8 to 3 seconds.
I can't figure out why.
The problematic query is:
SELECT `call_session`.`id`,
`continue_reason`.`name`
FROM `call_session`
LEFT JOIN `continue_reason` ON `continue_reason`.`id` = `call_session`.`continue_reason_id`
ORDER BY `call_session`.`start_time` DESC LIMIT 1;
Explain result:
Same query without join works great:
SELECT `call_session`.`id`,
(SELECT `name` FROM `continue_reason` WHERE id = `call_session`.`continue_reason_id`) AS `continue_reason.name`
FROM `call_session`
ORDER BY `call_session`.`start_time` DESC LIMIT 1;
Explain results:
I found many similar questions but I don't have any DISTINCT, no GROUP BY, and there is a very clear benefit for using the index.
Any thoughts?
Thanks in advance
P.S. Force index didn't help.
Here is the Optimizer report

MySQL "Foreign key constraint is incorrectly formed"

I have the follwing SQL commands:
CREATE TABLE IF NOT EXISTS `users`
(
`id` INTEGER NOT NULL auto_increment,
`username` VARCHAR(255) NOT NULL UNIQUE,
`password` VARCHAR(255) NOT NULL,
`root` TINYINT(1) DEFAULT 0,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
UNIQUE `username_unique` (`username`),
PRIMARY KEY (`id`)
)
engine=innodb;
CREATE TABLE IF NOT EXISTS `domains`
(
`id` INTEGER NOT NULL auto_increment,
`domain` VARCHAR(255) NOT NULL UNIQUE,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
`userid` INTEGER,
UNIQUE `domain_unique` (`domain`),
PRIMARY KEY (`id`),
FOREIGN KEY (`userid`) REFERENCES `users` (`id`) ON DELETE SET NULL ON
UPDATE CASCADE
)
engine=innodb;
CREATE TABLE IF NOT EXISTS `aliases`
(
`id` INTEGER NOT NULL auto_increment,
`source_username` VARCHAR(255) NOT NULL,
`source_domain` VARCHAR(255) NOT NULL,
`destination_username` VARCHAR(255) NOT NULL,
`destination_domain` VARCHAR(255) NOT NULL,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`source_domain`) REFERENCES `domains` (`domain`)
)
engine=innodb;
CREATE TABLE IF NOT EXISTS `accounts`
(
`id` INTEGER NOT NULL auto_increment,
`username` VARCHAR(255) NOT NULL,
`domain` VARCHAR(255) NOT NULL,
`password` VARCHAR(255) NOT NULL,
`quota` INTEGER NOT NULL DEFAULT 500,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`sendonly` TINYINT(1) NOT NULL DEFAULT 0,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`domain`) REFERENCES `domains` (`domain`)
)
engine=innodb;
if i try to run these i get the message:
"Foreign key constraint is incorrectly formed"
for the tables Alias and Accounts.
Its not possible to use primary keys in alias and accounts
Im using MariaDB 10.2
I hope somebody can tell me what is wrong with these statements.
You need to add a key/index to the domain field of the domains table, in order for it to be used as Foreign Key by another table.
If the table is already created and you want to add an index, use this.
CREATE INDEX domain ON domains(domain);
OR add the index while creating the table -
CREATE TABLE IF NOT EXISTS `domains`
(
`id` INTEGER NOT NULL auto_increment,
`domain` VARCHAR(255) NOT NULL UNIQUE,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
`userid` INTEGER,
UNIQUE `domain_unique` (`domain`),
PRIMARY KEY (`id`),
INDEX domain (domain),
FOREIGN KEY (`userid`) REFERENCES `users` (`id`) ON DELETE SET NULL ON
UPDATE CASCADE
)
engine=innodb;
For further reading (official documentation) regarding Foreign Key Contraint Errors on MariaDB this URL
You define an integer primary key. Use it:
CREATE TABLE IF NOT EXISTS `aliases`
(
`id` INTEGER NOT NULL auto_increment,
`source_username` VARCHAR(255) NOT NULL,
`source_domain_id` INTEGER NOT NULL,
`destination_username` VARCHAR(255) NOT NULL,
`destination_domain` VARCHAR(255) NOT NULL,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`createdat` DATETIME NOT NULL,
`updatedat` DATETIME NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`source_domain_id`) REFERENCES `domains` (`id`)
)
engine=innodb;

Implementing relationships in CakePHP Model

I am new to Cake and am trying to implement the Model layer as best as I can by using the bake script.
The implementation of my DB relationships has me a little worried though.
CREATE TABLE IF NOT EXISTS `model_base_test`.`entrys` (
`id` INT NOT NULL AUTO_INCREMENT,
`entry_year` INT(2) NOT NULL,
`contact_id` INT NOT NULL,
`division_id` INT NOT NULL,
`category_id` INT NOT NULL,
`entry_name` VARCHAR(45) NULL DEFAULT NULL,
`scale` VARCHAR(10) NULL DEFAULT NULL,
`ootb` TINYINT(1) NULL DEFAULT NULL,
`scratch` TINYINT(1) NULL DEFAULT NULL,
`theme` TINYINT(1) NULL DEFAULT NULL,
`score` DECIMAL(4,2) NULL DEFAULT NULL,
`medal_id` INT NULL DEFAULT NULL,
`image_id` INT NULL DEFAULT NULL,
`created` DATETIME NULL DEFAULT NULL,
`modified` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `fk_entries_contacts_idx` (`contact_id` ASC),
INDEX `fk_entries_groups_idx` (`category_id` ASC),
INDEX `fk_entries_medals_idx` (`medal_id` ASC),
UNIQUE INDEX `entry_id_UNIQUE` (`id` ASC),
INDEX `fk_entrys_divisions_idx` (`division_id` ASC),
CONSTRAINT `fk_entries_contacts`
FOREIGN KEY (`contact_id`)
REFERENCES `model_base_test`.`contacts` (`id`)
ON DELETE NO ACTION
ON UPDATE CASCADE,
CONSTRAINT `fk_entries_groups`
FOREIGN KEY (`category_id`)
REFERENCES `model_base_test`.`categorys` (`id`)
ON DELETE NO ACTION
ON UPDATE CASCADE,
CONSTRAINT `fk_entries_medals`
FOREIGN KEY (`medal_id`)
REFERENCES `model_base_test`.`medals` (`id`)
ON DELETE NO ACTION
ON UPDATE CASCADE,
CONSTRAINT `fk_entrys_divisions`
FOREIGN KEY (`division_id`)
REFERENCES `model_base_test`.`divisions` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `model_base_test`.`scores` (
`id` INT NOT NULL AUTO_INCREMENT,
`judge_id` INT NOT NULL,
`entry_id` INT NOT NULL,
`criteria` VARCHAR(15) NULL DEFAULT NULL,
`possible_points` INT NULL DEFAULT NULL,
`entry_possible` TINYINT(1) NULL DEFAULT NULL,
`raw_score` INT NULL DEFAULT NULL,
`score_adjustment` INT NULL DEFAULT NULL,
`weighted_score` DECIMAL(5,2) NULL DEFAULT NULL,
`created` DATETIME NULL DEFAULT NULL,
`modified` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `fk_scores_entries_idx` (`entry_id` ASC),
UNIQUE INDEX `id_UNIQUE` (`id` ASC),
CONSTRAINT `fk_scores_entries1`
FOREIGN KEY (`entry_id`)
REFERENCES `model_base_test`.`entrys` (`id`)
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
With the above tables and constraints as example, how best can I implement with Cake? The above is an optional one-to-many relationship, i.e. there is not necessarily a Score row for the mandatory Entry row.

having trouble with my database using workbench

I am creating a test database to train with and am running into this problem -
"Schema Creation Failed: Can't create table 'db_2_5b129.tbluserassignment' (errno: 150): "
The code for the specific table is -
-- Table tblUserAssignment
CREATE TABLE IF NOT EXISTS `tblUserAssignment` (
`assignment_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` INT NOT NULL,
`supervisor_id` INT NOT NULL,
`position_id` INT NOT NULL,
`department_id` INT NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`date_added` DATE NOT NULL,
`date_modified` DATETIME NOT NULL,
`date_deleted` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`assignment_id`),
INDEX `fk_tblUserAssignment_tblUserPhone1_idx` (`user_id` ASC),
INDEX `fk_tblUserAssignment_tblUserPositions1_idx` (`position_id` ASC),
CONSTRAINT `fk_tblUserAssignment_tblUserPhone1`
FOREIGN KEY (`user_id`)
REFERENCES `tblUserPhone` (`user_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_tblUserAssignment_tblUserPositions1`
FOREIGN KEY (`position_id`)
REFERENCES `tblUserPositions` (`position_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Can someone look it over and point me in the right direction?
problem is in differences between forign fields type
tblUserPositions.position_id INT UNSIGNED NOT NULL AUTO_INCREMEN
and
tblUserAssignment.position_id INT NOT NULL,`
EDIT 1
see this Use Composite Primary Key as Foreign Key
EDIT 2
this one tested & works fine
CREATE TABLE `tbluserphone` (
`contact_information_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(11) NOT NULL,
`phone_number` VARCHAR(20) NOT NULL,
`phone_type_id` INT(11) NOT NULL,
`date_added` DATETIME NOT NULL,
`date_modified` DATETIME NOT NULL,
`date_deleted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`contact_information_id`, `user_id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
CREATE TABLE `tbluserassignment` (
`assignment_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`contact_information_id` INT(10) UNSIGNED NOT NULL,
`user_id` INT(11) NOT NULL,
`supervisor_id` INT(11) NOT NULL,
`position_id` INT(10) UNSIGNED NOT NULL,
`department_id` INT(11) NOT NULL,
`start_date` DATE NOT NULL,
`end_date` DATE NOT NULL,
`date_added` DATE NOT NULL,
`date_modified` DATETIME NOT NULL,
`date_deleted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`assignment_id`),
INDEX `fk_tblUserAssignment_tblUserPhone1_idx` (`user_id`),
INDEX `fk_tblUserAssignment_tblUserPositions1_idx` (`position_id`),
INDEX `contact` (`contact_information_id`),
CONSTRAINT `FK_tbluserassignment_tbluserpositions`
FOREIGN KEY (`position_id`)
REFERENCES `tbluserpositions` (`position_id`) ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT tbluserassignment_fkz1
FOREIGN KEY (contact_information_id, user_id)
REFERENCES tbluserphone (contact_information_id, user_id)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB;
(contact_information_id, user_id) - fields should goes same way, like in primary key difinition