Troubleshooting unmatched foreign keys in mysql tables - mysql

I have two myIsam tables student and fee which were later changed into InnoDB engine and assigned foreign key to section field in fee table which points to section field in student table with UPDATE and DELETE CASCADE. My problem is that the existing section field values does not match with the existing student section values. This happened because before I had changed my engine, I had updated student table section field, and thought that section field values in fee table would also changed when I converted both the tables and assigned foreign keys to section field in both the tables. I am not sure whether synchronization will solve it. I am newbie and have no idea how I would solve this. Please help me.
Fee table:
CREATE TABLE IF NOT EXISTS `fee` (
`f_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`regd` bigint(20) unsigned NOT NULL,
`Class` varchar(20) COLLATE latin1_general_ci NOT NULL,
`Section` varchar(10) COLLATE latin1_general_ci NOT NULL,
`Amount` int(11) NOT NULL,
`Balance` int(11) NOT NULL,
PRIMARY KEY (`f_id`),
KEY `Section` (`Section`),
KEY `Rollno` (`Rollno`),
KEY `regd` (`regd`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
AUTO_INCREMENT=2500;
ALTER TABLE `fee`
ADD CONSTRAINT `fee_ibfk_1` FOREIGN KEY (`Section`)
REFERENCES `student` (`Section`) ON DELETE CASCADE ON UPDATE CASCADE,
ADD CONSTRAINT `fee_ibfk_2` FOREIGN KEY (`Rollno`)
REFERENCES `student` (`Roll_no`) ON DELETE CASCADE ON UPDATE CASCADE;
Student Table:
CREATE TABLE IF NOT EXISTS `student` (
`regd` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE latin1_general_ci NOT NULL,
`Date_of_birth` date NOT NULL,
`Sex` varchar(20) COLLATE latin1_general_ci NOT NULL,
`Roll_no` int(11) DEFAULT NULL,
`Section` varchar(20) COLLATE latin1_general_ci DEFAULT NULL,
PRIMARY KEY (`regd`),
KEY `Section` (`Section`),
KEY `Roll_no` (`Roll_no`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci
AUTO_INCREMENT=2500;

Unless you have some record of which fee should point to which student, I'm afraid you can't do this.
You'll have to recreate the links; either using logs of which UPDATEs you ran, from a backup or manually.

Related

Should I use Inner Join in this case?

I am working on a student attendance mini-project, and I don't know how to proceed for my database. I'm new to SQL and databases in general so this might seem dumb to you.
So, I want to do a database containing the table student, which contains : student_id (primary key) , name (string) and attendance(boolean) (that's the bare minimum, i'll add more afterwards) and I want to register the daily attendance of the students. So I want to have all the students tied to every date of the week.
I created a date table in phpMyadmin but I don't know how to proceed to link them, i've tried an Inner Join and it was successful.
The problem is : If i want to add another line to the student table my table won't update, so is there a way to "automatically" tie all the students to the date table ?
Sorry if this seems confused I've tried my best to summarize it !
Lets have some idea about tables should be there to implement a proper Student Attendance system in place. I have copied create script for some of my tables that used for maintaining Students record per course. I hope following sample Table scripts with relation will help you understanding regarding table structure and also to solve your issue.
Please be noted, That this table structures for your your reference only. You can add/remove tables/columns as per your requirement once you get an overall idea from this post.
CREATE TABLE `staff` (
`id` int(11) NOT NULL,
`type` varchar(200) DEFAULT NULL,
`first_name` varchar(200) DEFAULT NULL,
`last_name` varchar(200) DEFAULT NULL,
`emal` varchar(200) DEFAULT NULL,
`contact` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `batch` (
`id` int(11) NOT NULL,
`department` varchar(200) DEFAULT NULL,
`details` varchar(200) DEFAULT NULL,
`staff_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `batch_staff_idx` (`staff_id`),
CONSTRAINT `batch_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `student` (
`id` int(11) NOT NULL,
`batch_id` int(11) DEFAULT NULL,
`first_name` varchar(200) DEFAULT NULL,
`last_name` varchar(200) DEFAULT NULL,
`email` varchar(200) DEFAULT NULL,
`contact` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `batch_student_idx` (`batch_id`),
CONSTRAINT `batch_student` FOREIGN KEY (`batch_id`) REFERENCES `batch` (`batch_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `course` (
`id` int(11) NOT NULL,
`name` varchar(200) DEFAULT NULL,
`details` varchar(200) DEFAULT NULL,
`staff_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `course_staff_idx` (`staff_id`),
CONSTRAINT `course_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `attendence` (
`course_id` int(11) NOT NULL,
`student_id` int(11) DEFAULT NULL,
`class_date` date DEFAULT NULL,
KEY `att_course_idx` (`course_id`),
KEY `att_student_idx` (`student_id`),
CONSTRAINT `att_course` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `att_student` FOREIGN KEY (`student_id`) REFERENCES `student` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Your required data will finally store into table Attendance. From this table data, you will be able to find list of students absent/present per date and per course. Remember, the attendance table should enrich daily from a automated OR a manual process.

Only allow one unique foreign key for primary

I have 3 tables in mysql, One is a Company table, the other is a license table and the last is a joining table between both primary keys, When a person adds a company id to the license id in the joining table, it allows multiple companies to exist for one license, this cannot happen, so I need to do something that will only allow one company id for one license id
heres the tables
Table license
CREATE TABLE `License` (
`license_id` int(11) NOT NULL AUTO_INCREMENT,
`license_number` varchar(45) NOT NULL,
`start_date` date NOT NULL,
`end_date` date NOT NULL,
`duration` int(11) NOT NULL,
`expiry_date` date NOT NULL,
`product_id` int(11) DEFAULT NULL,
PRIMARY KEY (`license_id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1;
;
Company Table
CREATE TABLE `Company` (
`company_id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`physical_address` varchar(255) DEFAULT NULL,
`postal_address` varchar(255) DEFAULT NULL,
`reseller_id` int(11) DEFAULT NULL,
PRIMARY KEY (`company_id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=latin1;
and Joining table
CREATE TABLE `CompanyLicense` (
`license_id` int(11) NOT NULL,
`company_id` int(11) NOT NULL,
PRIMARY KEY (`license_id`,`company_id`),
KEY `companlicence_company_fk_idx` (`company_id`),
CONSTRAINT `companylicense_company_fk` FOREIGN KEY (`company_id`) REFERENCES `Company` (`company_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `companylicense_license_fk` FOREIGN KEY (`license_id`) REFERENCES `License` (`license_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
So far i have this
INSERT INTO CompanyLicense (license_id, company_id) VALUES
('2','6') on duplicate key update license_id = '2';
doesnt seem to do the job
You need to make company unique in companylicense:
ALTER TABLE companylicense ADD UNIQUE KEY (company)
or better yet, make company a field in license instead of having a link table.

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.

mysql prevent deleting records that is in used

i got 2 tables. product and order_items which contain all the products that were bought.
so how do i create a relationship in mysql whereby if a product exists in order_items, restrict users from deleting it from product table??
thanks
You can do this with Foreign keys with the InnoDB Engine.
ALTER TABLE order_items ADD FOREIGN KEY (`p_id`) REFERENCES `products` (`p_id`);
The ID on products must be a key (it probably already is the primary key).
If you are not using InnoDB, you cannot enforce this with MySQL, but it must be enforced with your application (check whether a record exists in orders first for example).
So with your tables, you run:
ALTER TABLE `order_item` ADD FOREIGN KEY (`bookid`) REFERENCES `book` (`id`);
You're looking for a foreign key. Specifically look at the "Restrict" option.
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
my table structure:
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
`description` text NOT NULL,
`author` varchar(100) NOT NULL,
`publisher` varchar(100) NOT NULL,
`edition` int(11) NOT NULL,
`isbn` varchar(13) NOT NULL,
`category` varchar(11) NOT NULL,
`datesubmitted` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
CREATE TABLE `order_item` (
`orderid` int(11) NOT NULL,
`bookid` int(11) NOT NULL,
KEY `Foreign` (`bookid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Help with my table structure

I'm trying to make an address book. And have made my tables like this:
CREATE TABLE `list_`.`contacts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` tinyint(11) NOT NULL,
`group` varchar(128) NOT NULL,
`first_name` varchar(128) NOT NULL,
`last_name` varchar(128) NOT NULL,
`address` varchar(128) NOT NULL,
`city` varchar(128) NOT NULL,
`state` varchar(2) NOT NULL,
`zip` int(5) NOT NULL,
`phone_number` varchar(16) NOT NULL,
`cell_number` varchar(16) NOT NULL,
`work_number` varchar(16) NOT NULL,
`fax_number` varchar(16) NOT NULL,
`email` varchar(128) NOT NULL,
`company` varchar(55) NOT NULL,
`title` varchar(56) NOT NULL,
`notes` text NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`,`user_id`),
KEY `user_id` (`user_id`),
KEY `group` (`group`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
CREATE TABLE `list_`.`groups` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` tinyint(11) NOT NULL,
`position` int(8) unsigned NOT NULL DEFAULT '0',
`name` varchar(128) NOT NULL,
`date_added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`,`user_id`),
KEY `user_id` (`user_id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8 AUTO_INCREMENT=32 ;
My logic here is that I have all the contacts in the contacts table, from there I have a column called group that I use to filter the contacts into groups.
Then I have a table called groups that I'll use to keep track of what groups where created by a specific user and fill a with these groups so they can move the contacts around.
When a group is deleted I will throw back an error no letting it be deleted if the group contains contacts. I can probably query the contacts to see what group they belong to and if they belong to the group being deleted then I'll move them into a group called Uncategorized or something.
But if they choose to accept and delete ALL contacts within a group then go ahead and delete the group and all child rows that belong to that group.
I am having trouble creating my Foreing Keys in the contacts table. No matter what combination of index and keys I try I still can't make it work.
--
-- Constraints for table `contacts`
--
ALTER TABLE `list_`.`contacts`
ADD CONSTRAINT `contacts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`),
ADD CONSTRAINT `contacts_ibfk_2` FOREIGN KEY (`group`) REFERENCES `groups` (`name`) ON UPDATE CASCADE;
--
-- Constraints for table `groups`
--
ALTER TABLE `list_`.`groups`
ADD CONSTRAINT `group_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`);
Also, can someone help me with the ON DELETE and ON UPDATE. To help me figure out how I can delete all child rows that reference the name column in groups
I do not think you should have MySQL do so much heavy lifting, specifically deleting a group if it is empty. Is there any specific reason to do this, i.e. can the group no longer be used if it is empty? You could probably achieve this with mysql triggers if you really wanted to.
As for preventing the deletion of a group that is simply done by the foriegn key on contacts that you already have on groups. However I highly recommend that you use ids rather than names for keys.
What you are saying seems to conflict, however: you want to prevent deletion of a group that has contacts, but you want all contacts in a group to be deleted when the group is deleted?