How do I refer from another table for SQL? - mysql

Situation is this:
I have a table for staff and another one for course.
In course I will have a column called coordinator which will refer to the staff_id.
This is because some staff are coordinators and some are not, etc etc.
Staff_id is an IDENTITY hence it is auto-incrementing and I have to make sure the in the course table, it won't follow this auto-increment.
I'm just unsure how do I implement the check constraint for this case.

I have to make sure the in the course table, it won't follow this auto-increment.
Do you just mean that you don't want the coordinator field in the course table to auto-increment? It won't unless you tell it to.
For example these two tables would work fine:
CREATE TABLE Staff
(
`staff_id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(64),
PRIMARY KEY (`staff_id`)
)
CREATE TABLE Courses
(
`course_id` INT NOT NULL AUTO_INCREMENT,
`coordinator_id` INT NOT NULL,
`coursename` VARCHAR(64),
PRIMARY KEY (`course_id`),
INDEX `coordid` (`coordinator_id`)
)
Of course, as GarethD says, you can then additionally add constraints to guarantee that the coordinator_id is correctly filled in and the corresponding record exists in staff.

If I'm understanding your requirements properly you can add a foreign key constraint to the table so that it references itself:
ALTER TABLE Staff
ADD CONSTRAINT FK_Staff_Coordinator FOREIGN KEY (Coordinator)
REFERENCES Staff (StaffID)
ADENDUM
I think I had misunderstood your requirements, I missed the part about a course table. So now I am thinking that the course table needs to link back to the staff table, in which case the command would be:
ALTER TABLE Course
ADD CONSTRAINT FK_Course_Coordinator FOREIGN KEY (Coordinator)
REFERENCES Staff (StaffID)
You are of course free to implement your own naming convention for constraints.

Related

MySQL - Error: 150 "Foreign key constraint is incorrectly formed")

Got an odd problem I cant solve after browsing dozens of forum posts, and my local SQL Books.
I've got two tables, and want to add a foreign key to one of them. The foreign key and primary key share the same datatype and charset and yet I cannot add the Foreign Key at all.
addon_account
name
type
comments
id
int(11)
Primary Key
name
varchar(60)
Primary Key
label
varchar(255)
shared
int(11)
addon_account_data
name
type
comments
id
int(11)
Primary Key
account_name
varchar(60)
Primary Key
money
double
owner
varchar()
The query I ran:
ALTER TABLE `addon_account_data` ADD FOREIGN KEY (`account_name`) REFERENCES `addon_account`(`name`) ON DELETE RESTRICT ON UPDATE RESTRICT;
Can't get it to work. Tosses out the same issue the entire time.
You are creating a foreign key on addon_account_data(account_name) that references addon_account(name). You have a composite primary the referred table : addon_account(id, name).
This is not allowed in MySQL, as explained in the documentation:
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.
Possible solutions:
add an additional column in the referring table: addon_account_data(account_id, account_name) and create a composite primary key to the corresponding columns in addon_account
create an index on addon_account(name) (probably the simplest solution)
change the order of the columns in the primary key of the referred table, like: addon_account(name, id) (you might want to first consider the impacts this may have in terms of performance)
I am not exactly a MySQL guy, but:
I believe the problem is that you are referencing only part of the primary key:
Your table addon_account has a composite key PK(id, name).
So, to put your relationship to work, you will need to add 'account_id' as part of the foreign key as well:
ALTER TABLE addon_account_data ADD FOREIGN KEY (account_id, account_name) REFERENCES addon_account(id, name)
This thread deals with something similar.
I hope this helps.
EDITED
I have installed a MySQL server instance on my local machine... (MySQL 8).
I have run the script below, and it worked (giving warnings about integer display being a deprecated feature, so I would recommend ommitting it):
CREATE TABLE addon_account(
id INT(11) NOT NULL,
`name` VARCHAR(60) NOT NULL,
label VARCHAR(255),
shared INT(11),
CONSTRAINT pk_addon_account PRIMARY KEY(id, `name`));
CREATE TABLE addon_account_data (
id INT(11) NOT NULL,
account_name VARCHAR(60) NOT NULL,
account_id INT(11),
money DOUBLE,
`owner` VARCHAR(255),
CONSTRAINT pk_addon_account_data PRIMARY KEY(id, account_name),
CONSTRAINT fk_addon_account_account_data FOREIGN KEY(account_id, account_name)
REFERENCES addon_account(id, `name`));
Could you try it and see if this works for you?
I am not that familiar with MySQL.
make sure that the 2 tables have the same collation
like
COLLATE='utf8_general_ci'

Unique constraint 'owner-owned attribute' through join table

I have the following scenario: A 'phone' child table can serve several parent tables through join tables, as follows:
CREATE TABLE phone (
id BIGINT AUTO_INCREMENT,
number VARCHAR(16) NOT NULL,
type VARCHAR(16) NOT NULL,
PRIMARY KEY(id)
);
CREATE TABLE employee_phone (
id BIGINT AUTO_INCREMENT,
employee BIGINT NOT NULL,
phone BIGINT NOT NULL,
PRIMARY KEY(id),
CONSTRAINT empl_phone_u_phone UNIQUE(phone),
CONSTRAINT empl_phone_fk_employee
FOREIGN KEY(employee)
REFERENCES employee(id) ON DELETE CASCADE,
CONSTRAINT empl_phone_fk_phone
FOREIGN KEY(phone)
REFERENCES phone(id) ON DELETE CASCADE
);
Let Alice and Bob live in the same house and be employees of the same company. HR has two phone numbers registered for Alice whereas they have only one for Bob, the number of the house's landline. Is there a way to enforce at database level that a phone number (number-type) cannot be repeated for the same employee (or supplier, or whatever parent appears later), using this configuration? Or will I have to take care of such restrictions in the application layer? I'd rather not use triggers or table denormalization (as seen in related questions on the site such as this one, which work with IDs, not with other fields), but I'm open to do so if there's no alternative. I'm using MySQL. Thanks for your attention.
If I understand correctly, you just want unique constraints on the junction tables:
alter table employee_phone add constraint unq_employeephone_employee_phone unique (employee, phone);
This will prevent duplicates for a given employee or (with the equivalent constraint) supplier.
If you want all phone numbers to be unique in the phone table, then just put a unique constraint/index on phone:
alter table phone add constraint unq_phone_phone unique (phone);
(you might want to include the type as well).
If you try to add a duplicate phone, the code will return an error.

MySQL Foreign Key Referencing WHERE field=value

I have a table created in MySQL (see the code below). As you see in the code I have a foreign key manager which references the idNo. However I only want to reference to employees with the cat='B'. So I need something like
FOREIGN KEY (manager ) REFERENCES Employee(idNo WHERE cat='B').
Any ideas how I can accomplish this.
idNo SMALLINT AUTO_INCREMENT UNIQUE,
name VARCHAR(25) NOT NULL,
telNo INT(11) NOT NULL,
cat CHAR(1) NOT NULL,
manager SMALLINT,
PRIMARY KEY (idNo ),
FOREIGN KEY (manager ) REFERENCES Employee(idNo) on DELETE CASCADE)ENGINE=INNODB
AUTO_INCREMENT=1000;
Foreign keys do not allow conditions.
If you want to force the condition, you must do it via coding.
It can be done inside your non DB code (Java, PHP, VB,...), or you could create a procedure in MySQL that would be called to perform the insert and that will return an error code if condition is not matched.
If you insert from various codes/application, the procedure is the way to go since it would be centralized.
Create a new UNIQUE KEY in Employee combining idNo and cat.
ALTER TABLE Employee ADD UNIQUE KEY (idNo,cat);
Make a foreign key in the child table that references that new unique key.
ALTER TABLE SomeTable ADD FOREIGN KEY (idNo,cat) REFERENCES Employee(idNo,cat);
Then you just need to make sure cat is constrained to the single value 'B' in the child table. One solution is to create a lookup table containing just the single value 'B'.
CREATE TABLE JustB (cat char(1) PRIMARY KEY);
ALTER TABLE SomeTable ADD FOREIGN KEY(cat) REFERENCES JustB(cat);
Now the only value you can use in the child table is 'B', so naturally it can only reference rows in Employee that have a cat of 'B'.
Another solution would be to use a trigger, but I favor the lookup table.

MYSQL Error # 1005

I have been trying to create a foregin key with nbrseats but I i get the error 1005 all the time.
CAn someone help me!?
create table theater (
name varchar(30) primary key,
nbrseats int not null
) ENGINE=INNODB;
create table reservation (
nbr integer auto_increment,
users_username varchar(30),
cinemashow_showdate date,
movies varchar(30),
nbrseats int not null,
primary key (nbr),
foreign key (nbrseats) references theater(nbrseats),
foreign key (users_username) REFERENCES users(username)
on delete cascade,
foreign key (cinemashow_showdate, movies) references cinemashow(showdate, movie_title)
on delete cascade
) ENGINE=INNODB;
In order to be a FOREIGN KEY in another table, you must have an index created on theater.nbrseats. And in order to be able to reference a specific row reliably, it should therefore be a UNIQUE index. Otherwise, if you have duplicate values, the referencing table won't be able to discern which row it references. Even though InnoDB will allow you to create the relationship on a non-unique index, it is likely not the behavior you are looking for.
See this question for more info on that bit.
create table theater (
name varchar(30) primary key,
nbrseats int not null,
UNIQUE INDEX `idx_nbrseats` (nbrseats)
) ENGINE=INNODB;
The same will be true of the other FOREIGN KEY definitions in your table reservation, though we do not see their referenced tables posted here. The rules are:
The referenced column must be indexed (independently of any other compound indexes on it)
The referencing column must have exactly the same data type.
This kind of calls into question your design, however. If you are attaching a number of seats to a reservation, will the reservation number of seats exactly match the number available in the theater? Also this means that you could not have 2 theaters with the same number of seats.
You may need to reconsider your design here, and perhaps create a FOREIGN KEY that references theater.name instead of theater.nbrseats.

How to manage one to one relationship in mySql?

I've two tables one about Customers and the second one is about their Accounts as 'Customer_Account_Information'. we know that one customer can have only one account, so I'm trying to enforce one to one relationship, but i don't know the procedure/syntax in mySql or mySqlyog.
is there any one who can help me?
You should create a Foreign Key contraint on table Accounts to table Customers using CustomerID.
Have a look at FOREIGN KEY Constraints
Also then make this a Unique Column in table Accounts
Have a look at MySQL foreign keys - how to enforce one-to-one across tables?
You could also use the same CustomerID from table Customers as PRIMARY KEY column in table Accounts as PRIMARY KEY.
A simple implementation
This is not a perfect solution but it is easy to understand with a little bit of experience with mysql and referential integrity.
You need a FOREIGN KEY in customers to refer to customer_account_inforamtion. Since the account_id in customers is the only way to join the tables, no customer can have more than one record in customer_account_information.
In the sample definitions below, I've included a FOREIGN KEY CONSTRAINT which causes the customer to be deleted when their account information is deleted. You may or may not want/need this.
CREATE TABLE customer_account_information (
id int(11) NOT NULL auto_increment,
some_attribute varchar(20) NOT NULL,
another_attribute varchar(30) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE customers (
id int(11) NOT NULL auto_increment,
account_id int(11) NOT NULL,
firstname varchar(30) NOT NULL,
surname varchar(30) NOT NULL,
PRIMARY KEY (id),
INDEX account_id (account_id),
CONSTRAINT account_id FOREIGN KEY (account_id) REFERENCES customer_account_information (id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The account_id in customers is the foreign key which refers to a record in customer_account_information
Alternative implementation
It might be an idea to revisit the design of the two tables. If each customer really can have only one account then perhaps all of the attributes of each can be merged into one table. Yes this business rule may change in the future but it would be a better idea to defer this work until really necessary - don't over engineer the solution today.