Put unique index across more than one table - mysql

I have run into a problem where the easiest solution would be to add a unique index that goes across multiple tables in mysql. Is this possible?
For the purpose of this question I will have three tables; status, tracks and events. The status and tracks tables both have an auto incrementing ID (T_ID or S_ID) in. Information from them is added to the events table with a trigger. The problem is that there could be the same auto incrementing ID in tracks and status, this means that their could be the same ID more than once in events.
tracks;
CREATE TABLE `tracks` (
`ID` int(11) NOT NULL,
`url` varchar(200) COLLATE latin1_general_ci NOT NULL,
`name` varchar(100) COLLATE latin1_general_ci NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`T_ID` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`T_ID`),
UNIQUE KEY `url` (`url`),
UNIQUE KEY `T_ID` (`T_ID`),
KEY `ID` (`ID`),
CONSTRAINT `tracks_ibfk_1` FOREIGN KEY (`ID`) REFERENCES `members` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
status
CREATE TABLE `status` (
`ID` int(11) NOT NULL,
`status` varchar(300) COLLATE latin1_general_ci NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`S_ID` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`S_ID`),
UNIQUE KEY `S_ID` (`S_ID`),
KEY `ID` (`ID`),
CONSTRAINT `status_ibfk_1` FOREIGN KEY (`ID`) REFERENCES `artists` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
events
CREATE TABLE `events` (
`ID` int(11) NOT NULL,
`action` varchar(100) COLLATE latin1_general_ci NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ON UPDATE CURRENT_TIMESTAMP,
`E_ID` int(11) NOT NULL,
KEY `ID` (`ID`),
CONSTRAINT `events_ibfk_1` FOREIGN KEY (`ID`) REFERENCES `members` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci COMMENT='This table shows what the artist has done and is used feed'

Agreed, you cannot have an index across multiple tables.
However, consider changing your schema by adding a "source" column to your event table and making a unique constraint on the combination of the source and the foreign key. This would prevent duplicate keys being inserted from the same source.

Related

MySQL relationship with 2 table

I have two tables:
CREATE TABLE `companies` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`industry_id` int(11) DEFAULT NULL,
... other fields ...
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE
CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
and:
CREATE TABLE `industries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I tried to add a foreign key to the second table:
ALTER TABLE industries ADD FOREIGN KEY (id) REFERENCES companies(industry_id) ON DELETE RESTRICT;
But I got next error:
Cannot add foreign key constraint
How can I add right fkey?
I suppose you've done it wrong. Primary key can't be Foreign Key.
Let's make little changes, which can give you the same value
ALTER TABLE companies ADD FOREIGN KEY (industry_id) REFERENCES industries(id) ON DELETE RESTRICT;

Error 1215: Can't add foreign key constraint (InnoDB)

I'm struggling around to create a foreign key with the following query:
alter table `users` add constraint `users_sales_partner_id_foreign` foreign key (`sales_partner_id`) references `structures` (`sales_partner_id`) on update cascade
InnoDB log says, it can't match this index:
2017-02-27 10:25:47 Error in foreign key constraint of
table website_backend/users: foreign key
(sales_partner_id) references structures (sales_partner_id) on update cascade:
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.
I have already checked typos and data type incompatibility, but everything seems to be alright:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`profile_id` int(10) unsigned NOT NULL,
`sales_partner_id` int(11) NOT NULL,
`email` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(191) COLLATE utf8mb4_unicode_ci NOT NULL,
`state` enum('pending','confirmed','active','deactivated') COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_profile_id_unique` (`profile_id`),
UNIQUE KEY `users_sales_partner_id_unique` (`sales_partner_id`),
UNIQUE KEY `users_email_unique` (`email`),
CONSTRAINT `users_profile_id_foreign` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
CREATE TABLE `structures` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`sales_partner_id` int(11) NOT NULL,
`sales_partner_structure` int(11) DEFAULT NULL,
`active` tinyint(1) NOT NULL,
`blocked` tinyint(1) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
I can't get my problem, does somebody have a clue? Thanks in advance!
Thanks to Paul Spiegel for his reminding that I can only set FKs to the indexed fields. After another review I noticed that my referenced field was not indexed, that solved my problem.

"Foreign key contraint" error message although there are no foreign keys

I am trying to change the engine for my table "adverts". It does not let me and I get the message that "a foreign key contraint fails". But I removed all foreign keys and SHOW CREATE TABLE gives me this:
CREATE TABLE `adverts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_users` int(11) NOT NULL,
`id_categories_adverts` int(11) NOT NULL,
`type` int(11) NOT NULL,
`status` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`headline` varchar(200) NOT NULL,
`description` text NOT NULL,
`show_contact` int(11) NOT NULL,
`stamp_created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`stamp_updated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8
Why can't I change the engine of my table? I am using
ALTER TABLE adverts ENGINE=MyISAM
The problem is that there is at least another table with foreign key to your adverts table. You need to tackle with those foreign key constraints, possibly, by temporarily/permanently removing them.

#1005 - Can't create table 'table_name' (errno: 150)

here is my tables:
DROP TABLE IF EXISTS `tbl_comments`;
CREATE TABLE IF NOT EXISTS `tbl_comments` (
`id` int(11) NOT NULL auto_increment,
`topic_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`text` text NOT NULL,
`create_dt` datetime NOT NULL,
`update_dt` timestamp NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `topic_id_2` (`topic_id`),
KEY `user_id` (`user_id`),
CONSTRAINT `tbl_comments_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tbl_users` (`id`),
CONSTRAINT `tbl_comments_ibfk_1` FOREIGN KEY (`topic_id`) REFERENCES `tbl_topics` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `tbl_users`;
CREATE TABLE IF NOT EXISTS `tbl_users` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL default '',
`password` varchar(128) NOT NULL default '',
`email` varchar(128) NOT NULL default '',
`activkey` varchar(128) NOT NULL default '',
`superuser` int(1) NOT NULL default '0',
`status` int(1) NOT NULL default '0',
`create_at` timestamp NOT NULL default CURRENT_TIMESTAMP,
`lastvisit_at` timestamp NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
UNIQUE KEY `user_username` (`username`),
UNIQUE KEY `user_email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `tbl_topics`;
CREATE TABLE IF NOT EXISTS `tbl_topics` (
`id` int(11) NOT NULL auto_increment,
`group_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`header` varchar(255) NOT NULL,
`text` text NOT NULL,
`create_dt` datetime NOT NULL,
`update_dt` timestamp NULL default CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `group_id` (`group_id`),
CONSTRAINT `tbl_topics_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `tbl_groups` (`id`),
CONSTRAINT `tbl_topics_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `tbl_users` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
now i have the error when i try to import:
#1005 - Can't create table 'kobeco_yii.tbl_comments' (errno: 150) (Details: Percona-XtraDB, Supports transactions, row-level locking, and foreign keys )
You're trying to create tbl_comments before your other tables. tbl_comments requires tables tbl_users and tbl_topics for foreign key constraints.
Try moving the CREATE TABLE for tbl_comments to below the others.
Your first table (table_commets) has constraints to tables that doesn't exist yet. This may be an issue of you are creating them in that order.
Create table_usr and table_topics first.

how to best design the DB in this situation

At a glance, the database schema looks like this:
The schema has to be in 3rd normal form (and I am aware that hotels.average_rating suggests otherwise, try to oversee that, since the database is not fully designed yet). This is for a tourist recommendation system.
The SQL:
SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
CREATE TABLE `activities` (
`activity_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`activity_name` varchar(277) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`activity_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `bookings` (
`from_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`to_date` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`belong_user` int(10) unsigned NOT NULL,
`belong_hotel` int(10) unsigned NOT NULL,
`rating` int(3) unsigned NOT NULL,
KEY `belong_user` (`belong_user`),
KEY `belong_hotel` (`belong_hotel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `countries` (
`cuntry_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`country_name` varchar(20) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`cuntry_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `hotels` (
`hotel_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hotel_name` varchar(128) COLLATE utf8_bin NOT NULL,
`hotel_stars` int(3) NOT NULL,
`hotel_description` text COLLATE utf8_bin NOT NULL,
`average_price` float unsigned NOT NULL,
`average_rating` float unsigned NOT NULL,
`total_rooms` int(10) unsigned NOT NULL,
`free_rooms` int(10) unsigned NOT NULL,
`belong_region` int(10) unsigned NOT NULL,
PRIMARY KEY (`hotel_id`),
KEY `belong_region` (`belong_region`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `hotels_activity_offers` (
`belong_hotel` int(10) unsigned NOT NULL,
`belong_activity` int(10) unsigned NOT NULL,
UNIQUE KEY `belong_hotel_2` (`belong_hotel`,`belong_activity`),
KEY `belong_hotel` (`belong_hotel`),
KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `regions` (
`region_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`belong_country` int(10) unsigned NOT NULL,
`region_name` varchar(255) COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`region_id`),
KEY `belong_country` (`belong_country`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `regions_activity_offers` (
`belong_region` int(10) unsigned NOT NULL,
`belong_activity` int(10) unsigned NOT NULL,
KEY `belong_region` (`belong_region`),
KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `users` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`username` varchar(20) COLLATE utf8_bin NOT NULL,
`password` varchar(40) COLLATE utf8_bin NOT NULL COMMENT 'MD5',
`first_name` varchar(20) COLLATE utf8_bin NOT NULL,
`last_name` varchar(20) COLLATE utf8_bin NOT NULL,
`email` varchar(255) COLLATE utf8_bin NOT NULL,
`is_admin` tinyint(1) NOT NULL,
`is_active` tinyint(1) NOT NULL,
PRIMARY KEY (`user_id`),
KEY `is_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE `users_favourite_activities` (
`belong_user` int(10) unsigned NOT NULL,
`belong_activity` int(10) unsigned NOT NULL,
UNIQUE KEY `belong_user_2` (`belong_user`,`belong_activity`),
KEY `belong_user` (`belong_user`),
KEY `belong_activity` (`belong_activity`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
ALTER TABLE `bookings`
ADD CONSTRAINT `bookings_ibfk_3` FOREIGN KEY (`belong_hotel`) REFERENCES `hotels` (`hotel_id`) ON DELETE CASCADE,
ADD CONSTRAINT `bookings_ibfk_2` FOREIGN KEY (`belong_user`) REFERENCES `users` (`user_id`) ON DELETE CASCADE;
ALTER TABLE `hotels`
ADD CONSTRAINT `hotels_ibfk_1` FOREIGN KEY (`belong_region`) REFERENCES `regions` (`region_id`) ON DELETE CASCADE;
ALTER TABLE `hotels_activity_offers`
ADD CONSTRAINT `hotels_activity_offers_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE,
ADD CONSTRAINT `hotels_activity_offers_ibfk_1` FOREIGN KEY (`belong_hotel`) REFERENCES `hotels` (`hotel_id`) ON DELETE CASCADE;
ALTER TABLE `regions`
ADD CONSTRAINT `regions_ibfk_1` FOREIGN KEY (`belong_country`) REFERENCES `countries` (`cuntry_id`) ON DELETE CASCADE;
ALTER TABLE `regions_activity_offers`
ADD CONSTRAINT `regions_activity_offers_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE,
ADD CONSTRAINT `regions_activity_offers_ibfk_1` FOREIGN KEY (`belong_region`) REFERENCES `regions` (`region_id`) ON DELETE CASCADE;
ALTER TABLE `users_favourite_activities`
ADD CONSTRAINT `users_favourite_activities_ibfk_1` FOREIGN KEY (`belong_user`) REFERENCES `users` (`user_id`) ON DELETE CASCADE,
ADD CONSTRAINT `users_favourite_activities_ibfk_2` FOREIGN KEY (`belong_activity`) REFERENCES `activities` (`activity_id`) ON DELETE CASCADE;
The question is: how to best add a "user activity log" feature which stores the activities a user has taken part to? Note that both regions and hotels can have activities, and I need to be able to tell whether that activity has taken place in a region or in a hotel. Referential integrity should be guaranteed.
Present a query (it should use JOIN shouldn't it?) which lists all users and their activities along with the hotel id or region id. (the one which is not applicable can be NULL if required).
Simple solutions are better - so preferably without stored procedures or anything which digs too much in mysql-specific features.
Your database is not normalized - and the way you've done it looks like a poster-child for why normalization is a good idea.
hotels.average_rating?
WTF?
While it can make sense to denormalize your data - this is not how to do it. Think about what you need to do when a user submits a hotel rating - you need to recalculate the value based on all the ratings submitted. If instead you held a sum_of_ratings (or even retained the current average) and a number of ratings then you could calculate the new values based on the hotel record and the new rating without having to look at the other ratings.