Two or more foreign key in the table - mysql

In MySQL I have these 3 tables :
CREATE TABLE IF NOT EXISTS Seasons
(
season_id INT NOT NULL AUTO_INCREMENT,
start_date DATE,
end_date DATE,
club_num INT,
desc TEXT,
PRIMARY KEY(season_id)
);
ALTER TABLE Seasons AUTO_INCREMENT=10000;
CREATE TABLE IF NOT EXISTS Clubs
(
club_id INT NOT NULL AUTO_INCREMENT,
club_name VARCHAR(70),
PRIMARY KEY(club_id)
);
ALTER TABLE Clubs AUTO_INCREMENT=100000;
CREATE TABLE IF NOT EXISTS ClubsCloths
(
season_id INT NOT NULL,
club_id INT NOT NULL,
first_shirt VARCHAR(50),
second_shirt VARCHAR(50),
PRIMARY KEY(season_id,club_id),
FOREIGN KEY (season_id) REFERENCES Seasons(season_id),
FOREIGN KEY (club_id) REFERENCES Clubs(club_id)
);
In the last one I have 2 foreign keys that reference to first and second table. Now I want to know is it wisely to have 2 foreign key in a one table ?
thanks

It is normal. The ClubsCloths table is used to support many-to-many relationship between Seasons and Clubs.

It's perfectly normal to have several foreign keys to different tables (or the same table, doesn't matter).

Related

How to create a table with a composite key made of 2 foreign keys referencing to other tables?

I have three tables A, B and funding:
Table A has a primary key partner_id
Table B has a primary key branch_id
When I try to create table C with the following code:
CREATE TABLE Funding (
partner_id INT,
branch_id INT,
total_fund FLOAT,
PRIMARY KEY (partners_id, branch_id),
FOREIGN KEY (partners_id) REFERENCES A(partner_id) ON delete SET NULL,
FOREIGN KEY (branch_id) REFERENCES B(branch_id) ON delete SET NULL
);
I get error message:
1830: column partner_id cannot be NOT NULL: needed in a foreign key constraint.
How can I solve this problem?
Create a separted ID for PK:
SQL DEMO
CREATE TABLE A (
partner_id INT,
PRIMARY KEY (partner_id)
);
CREATE TABLE B (
branch_id INT,
PRIMARY KEY (branch_id)
);
CREATE TABLE Funding (
id INT PRIMARY KEY AUTO_INCREMENT,
partner_id INT,
branch_id INT,
total_fund FLOAT,
FOREIGN KEY (partner_id) REFERENCES A(partner_id) ON DELETE SET NULL,
FOREIGN KEY (branch_id) REFERENCES B(branch_id) ON DELETE SET NULL
);
You can also add:
ALTER TABLE `Funding` ADD UNIQUE `unique_index`(partner_id, branch_id);
But that can cause problem when multiple partners from same branch are deleted
In CREATE TABLE Funding just add NOT NULL statement to partner_id and branch_id.
CREATE TABLE Funding ( partner_id INT NOT NULL, branch_id INT NOT NULL,...

MySQL create table one to many, what is the best option below?

I have below data and using mysql. Person_name is unique and TelephoneNumbers are unique per person.
Person_name1=TelephoneNumber1, TelephoneNumber2, TelephoneNumber3...
Person_name2=TelephoneNumber4, TelephoneNumber5, TelephoneNumber6...
Option 1. Create 1:Many master and child table.
CREATE TABLE Person (
personName varchar(50) NOT NULL,
id int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (id),
UNIQUE KEY personName (personName)
);
CREATE TABLE Telephone (
telephoneNumber int,
mappingId int,
PRIMARY KEY (telephoneNumber),
foreign key(mappingId) references Person(id)
);
Option 2. Create one table with personName, telephoneNumber as Composite Key.
CREATE TABLE
Person_Telephone (
personName varchar(50) NOT NULL,
telephoneNumber int NOT NULL,
PRIMARY KEY(personName, telephoneNumber)
);
Option 1 is it over complicating creating two tables for just two fields?
Option 2 looks perfect and will there be any issues if Option 2 chosen over Option 1?
The option 2 gives you duplicate persons that you must control in every query.
The best is have the entities separate, it's a classic 1-N relation
Since users can have multiple phone numbers, I think 2 tables would be the best solution.
CREATE TABLE person (
PRIMARY KEY (id) AUTO_INCREMENT,
person_name VARCHAR(45) NOT NULL,
);
CREATE TABLE phone_number (
PRIMARY KEY (id) AUTO_INCREMENT,
phone_number VARCHAR(11) NOT NULL,
FOREIGN KEY (person_id) REFERENCES person(id)
)
Now you can simply JOIN the tables like this:
SELECT
t1.id,
t1.person_name,
t2.phone_number
FROM person t1
LEFT JOIN phone_number t2
ON (t1.id = t2.person_id);

Intersection of Two Tables in SQL

Basically I need to create a new table that uses specific information from two other tables.
For example, I have a table called person with the elements person_id, first_name, last_name, gender, age, and fav_quote. I have a second table called department with the elements dept_id, dept_name, and building. I now need to create and intersection table with the person_id and dept_id elements included. And both must be the primary key (which I assume just means PRIMARY KEY (person_id, dept_id) command in my source).
CREATE TABLE person (
person_id INT(8) NOT NULL auto_increment,
first_name VARCHAR(25) NOT NULL,
last_name VARCHAR(25) NOT NULL,
gender VARCHAR(1),
age INT(8),
fav_quote TEXT,
PRIMARY KEY (person_id)
);
CREATE TABLE department (
dept_id INT(8) NOT NULL auto_increment,
dept_name VARCHAR(25) NOT NULL,
building VARCHAR(25) NOT NULL,
PRIMARY KEY (dept_id)
);
That is the code I have for the initial two tables I'm just not sure how to create an intersection and, having gone back over my notes, I can't find the instructions on how to write it.
You got the primary key part right. I'd add foreign keys to your existing table in order to prevent creating interactions with people or departments that don't exist:
CREATE TABLE person_department
person_id INT(8) NOT NULL,
dept_id INT(8) NOT NULL,
PRIMARY KEY(person_id, dept_id),
FOREIGN KEY(person_id) REFERENCES person(person_id),
FOREIGN KEY(dept_id) REFERENCES department(dept_id)
)
You need a table with 2 fields; person_id and dept_id. The table will have foreign keys to the two tables person and department primary keys’ and a composite primary key of both.
Also, this table is only necessary if there is a one to many relationship of person to department. Otherwise just add dept_id as a foreign key in person.

#1005 - Cant create table... (errno: 150)

I have all the primary keys and drop tables in the correct order.
I basically want stockID to be a foreign key in my refund table.
My schema looks like this...
CREATE TABLE refunds (
refundID SMALLINT AUTO_INCREMENT,
stockID SMALLINT,
refundDate DATE,
FOREIGN KEY (stockID) REFERENCES tblStock(stockID),
PRIMARY KEY (refundID)
);
CREATE TABLE tblStock (
stockID SMALLINT AUTO_INCREMENT,
stockName VARCHAR(60),
StockNumbers SMALLINT
);
When referencing another table for a foreign key reference, that table needs to already exist. And, the column being referenced should be a primary key. Try this:
CREATE TABLE tblStock (
stockID SMALLINT AUTO_INCREMENT PRIMARY KEY,
stockName VARCHAR(60),
StockNumbers SMALLINT
);
CREATE TABLE refunds (
refundID SMALLINT AUTO_INCREMENT,
stockID SMALLINT,
refundDate DATE,
FOREIGN KEY (stockID) REFERENCES tblStock(stockID),
PRIMARY KEY (refundID)
);
FOREIGN KEY (stockID) REFERENCES tblStock(stockID)
Is referencing a table that doesn't yet exist. Create tblStock first.
You are referencing a table that doesn't exist. Create it first.
In addition, you will want to index the key you are referencing. Make sure any value being referenced in your foreign key actually exists.

In MySQL how does one create global/general foreign IDs?

Question:
Is there a way to make the foreign ID point to something more generic than one specific table?
Details:
Often I run into the situation where I have several tables which have nothing to do with each other, but still need a common table (in below examples engine is innodb)
CREATE TABLE IF NOT EXISTS movies
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS books
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS songs
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS news_papers
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS scrolls
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS sumarian_wheat_tablets
(
id INT NOT NULL auto_increment,
name VARCHAR(100) NOT NULL ,
PRIMARY KEY(id)
);
Now I want to keep a record of every time each is viewed like so
CREATE TABLE IF NOT EXISTS movie_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES movies ( id ),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS book_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES books ( id ),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS song_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES songs ( id ),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS news_paper_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES news_papers ( id ),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS scroll_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES scrolls ( id ),
PRIMARY KEY(id)
);
CREATE TABLE IF NOT EXISTS sumarian_wheat_tablet_history
(
id INT NOT NULL auto_increment,
foreign_id INT NOT NULL ,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (foreign_id) REFERENCES sumarian_wheat_tablets ( id ),
PRIMARY KEY(id)
);
Is there a more correct way to handle such situations without making n new tables? I realize that I can make one history table and copy it over with CREATE TABLE...LIKE... but that still requires making n new tables, plus I have to go in and ALTER the foreign_id.
My first thought is just dump the fk reference and have one history table:
CREATE TABLE history(
base_table VARCHAR,
base_table_id INT,
view_date TIMESTAMP DEFAULT now()
);
But I assume you want the fk to maintain the integrity (question: is this really necessary, or can this be worked around?). I guess you could accomplish this by creating a table of "pks in use". For example:
create a table "keys" with columns id (autoincrement) and base_table_name
create a table "movies", where id is both pk and also a fk to "keys.id" (but not an autoincrement column)
add a "before insert" trigger to "movies" which inserts a record into "keys" returning the generated id to be used as the id for the "movie" record
create a history table with a fk to "keys"
create a "delete" trigger on "movies" which also removes the record from "keys" if you want the integrity maintained, or cascading deletes, etc
So the generated "id" is shared across many tables. There is a school of thought that suggests using a primary key unique across all relations within the database (an "enterprise key"), so it is not unprecedented. Instead of using sequences or autogenerated columns, sometimes a GUID or UUID is used.
This replaces extra history tables with triggers on each base table, which might not be a great thing, depending on your environment. I haven't done this myself, just throwing some thoughts out there, so take it for what its worth.
This depends on the record that you're keeping. If you just want to know hits, add one field to each table that is incremented each time your 'hit' criteria is met (ie, there is a read from a webpage). If you want to hold more information:
CREATE TABLE IF NOT EXISTS view_history
(
id INT NOT NULL,
table VARCHAR NOT NULL,
//other relevant stats to a given view, such as ip and so on.
)
The id and table form a composite key as to what table it refers to.
I don't think there is a way to specify more than one table on a single foreign key.
If you define a single history table, you cannot enforce referential integrity using a single foreign key. You could enforce it programmaticaly as explained here
This describes how to do it for other storage engines that do not support FKs, but could be used as a guide to implement what you need. It suggests creating triggers that will enforce same validations a foreign key would.
Other approach:
CREATE TABLE IF NOT EXISTS history
(
id INT NOT NULL auto_increment,
movie_id INT,
book_id INT,
song_id INT,
news_paper_id INT,
view_date TIMESTAMP DEFAULT now(),
FOREIGN KEY (movie_id) REFERENCES movie ( id ),
FOREIGN KEY (book_id) REFERENCES book ( id ),
FOREIGN KEY (song_id) REFERENCES song ( id ),
FOREIGN KEY (news_paper_id) REFERENCES news_paper ( id ),
PRIMARY KEY(id)
);