Best way to relate foreign key to parent - mysql

I don't dabble much in SQL design at all, so this might be a trivial question.
I have a players table:
CREATE TABLE players(
p_id INT NOT NULL PRIMARY KEY,
p_name VARCHAR(150) NOT NULL
)
I have a results table:
CREATE TABLE results(
f_id INT NOT NULL PRIMARY KEY,
f_datetime DATETIME NOT NULL,
p1_id INT NULL,
p2_id INT NULL,
FOREIGN KEY (p1_id) REFERENCES players(p_id) ON DELETE SET NULL ON UPDATE SET NULL,
FOREIGN KEY (p2_id) REFERENCES players(p_id) ON DELETE SET NULL ON UPDATE SET NULL
)
When I add an INSERT into the results table, I am adding the p1_id and p2_id. For this to work, I need to already have these id's defined in the players table, with the accompanying string name for this id. Programmatically, what should I do with my data before adding to the results table?
Check if p_id exists (from my p1_id and p2_id values), if not, INSERT them with the accompanying string.
Add my data into the results table as a normal insert
Or is there a more conventional way to do these things? Maybe some SQL quirk i'm not aware of?

Related

Can't create table 'student.#sql-f40_3' (errno: 150)

Table 1
create table personal(
id int not null auto_increment unique,
name char(20) not null,
age int not null,
city varchar(20) not null default 'Delhi'
);
insert into personal(name,age,city) values
('anubhav',22,'delhi'),
('rohit',24,'agra');
Table 2
create table applications(
app_id int(5) not null auto_increment unique,
city varchar(10) not null default 'Delhi'
);
insert into applications(city) values
('kolkata'),
('mumbai'),
('mumbai'),
('delhi'),
('agra'),
('agra');
Then i apply foreign key here with the help of Alter command-
alter table personal add foreign key(city) references applications(app_id)
but i am getting an error: ERROR 1005 (HY000): Can't create table 'student.#sql-f40_3' (errno: 150)
MySQL specifies:
Conditions and Restrictions
1.Corresponding columns in the foreign key
and the referenced key must have similar data types. The size and sign
of fixed precision types such as INTEGER and DECIMAL must be the same.
The length of string types need not be the same. For nonbinary
(character) string columns, the character set and collation must be
the same.
2.MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the
referencing table, there must be an index where the foreign key
columns are listed as the first columns in the same order. Such an
index is created on the referencing table automatically if it does not
exist. This index might be silently dropped later if you create
another index that can be used to enforce the foreign key constraint.
index_name, if given, is used as described previously.
The data type must be the same.
You could do:
alter table personal add foreign key(city) references applications(city)
But, the columns on both tables should be indexed.
See here
you desing in not normalized
your personal table should only reference the id.
City name in the applications should be unique, so i added it in the create table, there is no need for two or more delhis in a table(see normalisation)
If you really want to use in personal the city name, you must like i already made refernece the coty name of appcations or define a KEY for that column.
Further the datatyoes of the columns must always be the saem in both table for the foreign key
create table personal(
id int not null auto_increment unique,
name char(20) not null,
age int not null,
city int not null default 0
);
create table applications(
app_id int not null auto_increment primary key,
city varchar(10) not null unique default 'Delhi'
);
alter table personal add foreign key(city) references applications(app_id)
You have small bugs such as not putting null in the insert for the autoincrement and if it is primary key you should not put not null.
Table personal
create table personal(
id int auto_increment primary key,
name char(20) not null,
age int not null,
city varchar(20) not null default 'Delhi'
);
insert into personal values (null,'anubhav',22,'delhi'),
(null,'rohit',24,'agra');
Table applications
create table applications(
app_id int(5) auto_increment primary key,
city varchar(10) not null default 'Delhi'
);
insert into applications values(null,'kolkata'),
(null,'mumbai'),
(null,'mumbai'),
(null,'delhi'),
(null,'agra'),
(null,'agra');
Alter table
alter table personal add foreign key(city) references applications(app_id)

MySQL issue.. creating and referencing tables at once

I was trying to create multiple tables (some of them referncing the other tables) at once.
I think I matched data types and set primary/foreign keys correctly. But I can only see an error
of 'You cannot add foreign key constraint'. I thought the referenced tables might be created on the first before other tables refernce it, so I reversed the order and the result was the same.
Lastly I tried creating and executing only the referenced tables first(item_type), then referencing tables(item) later.. and... it worked!
However, I wonder if those codes can be executed at once.
Here is code below..
(just two tables are shown to make it simple..)
CREATE TABLE item (
i_id SMALLINT unsigned NOT NULL AUTO_INCREMENT,
i_name VARCHAR(30) NOT NULL,
t_id SMALLINT unsigned NOT NULL,
PRIMARY KEY (i_id),
FOREIGN KEY (t_id) REFERENCES item_type(t_id)
) ENGINE=INNODB;
CREATE TABLE item_type (
t_id SMALLINT unsigned NOT NULL AUTO_INCREMENT,
t_name VARCHAR(20) NOT NULL,
PRIMARY KEY(t_id)
);
You can't define a foreign key to a table that doesn't exist, so doing the CREATE TABLE operations in the order above is not going to work. If you create the item_type table first, then the item table with the foreign key to item_type, it should work.
Database engines execute sql code in batches, so one statement that crate table is one batch, but in you example, first batch references second batch which is not executed yet, so change order of batches and it will be working.
CREATE TABLE item_type (
t_id SMALLINT unsigned NOT NULL AUTO_INCREMENT,
t_name VARCHAR(20) NOT NULL,
PRIMARY KEY(t_id)
);
CREATE TABLE item (
i_id SMALLINT unsigned NOT NULL AUTO_INCREMENT,
i_name VARCHAR(30) NOT NULL,
t_id SMALLINT unsigned NOT NULL,
PRIMARY KEY (i_id),
FOREIGN KEY (t_id) REFERENCES item_type(t_id)
) ENGINE=INNODB;

Assigning whole table to some other table

Lets assume I have the following table
create table Article
(
ART_ID bigint not null auto_increment,
ART_NAME varchar(25) not null,
ART_COST decimal(8,2) not null,
ART_DESC text,
primary key(ART_ID)
);
and also this table
create table Fruits
(
FRUITS_ID bigint not null auto_increment,
FRUITS_TYPE varchar(15),
FRUITS_FROZEN timestamp DEFAULT CURRENT_TIMESTAMP,
primary key(FRUITS_ID )
);
I want the Fruits table to have all the fields of the table Article. How can I implement this? Should I reference it by some relation or is there another trick?
I think what you need here is to add an ARTICLE_ID field to Fruits, and then reference it to Articles.ART_ID via a FOREIGN KEY constraint to ensure data consistency.
Note that this means that for each fruit, to have some "article" fields set, a corresponding record in Articles must exist. If you don't want article fields to be mandatory for a fruit, you can make the ARTICLE_ID field nullable. This still allows a foreign key to be defined, but it will only enforce a reference if the value stored in ARTICLE_ID is not NULL.

Design database table to check id in another table before allowing insert

I've got what I'm sure is a really simple database question, but I don't even know what to google, so hopefully someone can help me here.
I'm trying to create 2 tables that are interconnected. For example, lets say I have an employee table with employee name and employee id, then I'm creating another table, employee_bonus, with employee id and bonus amount. What I want is for the employee_bonus table to automatically check with the employee table every time a row is inserted to make sure that the employee id exists in the employee table and reject the insert if not. The thing is, there could be multiple bonuses for a single employee, so I just want it to check that it exists, not make it one to one. Does that make sense? Is that possible? How would I do that and WHAT is that called?
Also, I'm doing this in MySql.
From wikipedia: Foreign Key
In the context of relational databases, a foreign key is a referential constraint between two tables.
http://en.wikipedia.org/wiki/Foreign_key
The following is a basic example of what you are looking for:
CREATE TABLE employees (
employee_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
family_name VARCHAR(100) NOT NULL,
first_name VARCHAR(100) NOT NULL,
birth_date DATETIME NULL DEFAULT NULL,
PRIMARY KEY(employee_id)
) ENGINE=INNODB;
CREATE TABLE employee_bonus (
bonus_id INT UNSIGNED NOT NULL AUTO_INCREMENT,
employee_id INT UNSIGNED NOT NULL,
bonus_value DECIMAL(10,2) DEFAULT 0.00,
PRIMARY KEY(bonus_id),
KEY fk_employee_id (employee_id),
CONSTRAINT fk_employee_constraint FOREIGN KEY fk_employee_id(employee_id)
REFERENCES employees(employee_id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB;
Since it's not a 1-to-1 relationship give the employee_bonus table its own primary key and establish a foreign key relationship between the employee table's id column and the employee_id in the employee_bonus table.
If you want to avoid an error on insertion when attempting to add a missing employee, try this:
insert into employee_bonus
select ?, ?, ? -- put your insert values in here
from employee
where employee_id = ?; -- put the employee_id in here
This will insert one row if the employee exists and will do nothing if it doesn't.

Self relationship in MySQL

I am trying to add a self relation in an existing Innodb table here is table structure
Table person
person_id int (10) primary key not null auto increment,
parent_id int (10) NULL default null,
name varchar(30)
When I use this command
ALTER TABLE `person` ADD FOREIGN KEY ( `parent_id` ) REFERENCES `person` (`person_id`) ON DELETE RESTRICT ON UPDATE RESTRICT ;
I get the error data type mismatch. I think this could be due to null values in parent_id. Is there any way to skip this check?
Thanks
person_id and parent_id need to be the exact same data type. For example, if person_id is INT UNSIGNED and parent_id is INT, then you can't create the foreign key.
Run this command and compare the data types of the two columns:
SHOW CREATE TABLE `person`\G