Why aren't references working - mysql

Trying to explain the REFERENCES CONSTRAINT to someone else with a MySQL example, and I can't make the pesky example work! It seems to work if I define it as a FOREIGN KEY, but I've textbooks that say I don't have to do that (making it a column-level referential constraint rather than a table-level one).
The question is, after the UPDATE to dname in the dept table, why doesn't the dname in the emp table change?
-- SQL CODE BEGINS
DROP TABLE IF EXISTS dept;
DROP TABLE IF EXISTS emp;
CREATE TABLE dept (
dname CHAR(10),
dnum numeric(3,0)
) ENGINE=InnoDB;
CREATE TABLE emp (
dname CHAR(10) REFERENCES dept(dname) ON UPDATE CASCADE,
ename CHAR(10)
) ENGINE=InnoDB;
INSERT INTO dept VALUES ("AAA", 111);
INSERT INTO dept VALUES ("BBB", 222);
INSERT INTO emp VALUES ("CCC", "Carol");
INSERT INTO emp VALUES ("AAA", "Alice");
SELECT * from dept;
SELECT * from emp;
UPDATE dept SET dname="XYZ" WHERE dnum=111;
SELECT * from dept;
SELECT * from emp;
-- SQL CODE ENDS
ARGH!

DECLARE dept.dname AS PRIMARY KEY
create a FOREIGN KEY constraint on emp.dname
FULL DDL:
CREATE TABLE dept
(
dname CHAR(10) PRIMARY KEY,
dnum numeric(3,0)
) ENGINE=InnoDB;
CREATE TABLE emp
(
dname CHAR(10) ,
ename CHAR(10),
CONSTRAINT em_FR FOREIGN KEY (dname)
REFERENCES dept(dname) ON UPDATE CASCADE
) ENGINE=InnoDB;
SQLFiddle Demo

excerpted from MySQL 5.5 Reference Manual
<snip>
InnoDB does not recognize or support “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification. InnoDB accepts REFERENCES clauses only when specified as part of a separate FOREIGN KEY specification. For other storage engines, MySQL Server parses and ignores foreign key specifications.
</snip>
http://dev.mysql.com/doc/refman/5.5/en/create-table.html
I think the authors of your two textbooks should have noted that their recommended approach, adding "REFERENCES" clause on the column definition, does NOT create or enforce foreign key constraints.
In order to create a foreign key constraint, you need a unique index on the target column(s). In your case, you nee an index on dept(dname).
ALTER TABLE dept ADD CONSTRAINT dept_UX
UNIQUE KEY (dname) ;
With that in place, you can then create a foreign key constraint:
ALTER TABLE emp ADD CONSTRAINT FK_emp_dept
FOREIGN KEY (dname) REFERENCES dept(dname) ON UPDATE CASCADE ;
(Normally, a foreign key references the PRIMARY KEY of a table. But a UNIQUE KEY is sufficient. Actually, with InnoDB, all that is required is an index, it doesn't have to be unique, but we don't want to go there.)
To declare dname to be the PRIMARY KEY rather than a UNIQUE KEY:
ALTER TABLE dept ADD PRIMARY KEY (dname) ;
When the REFERENCES clause is added to the column definition, I believe that gets ignored by MySQL. (The syntax is accepted, but it doesn't get recorded in the data dictionary. If you're working with MyISAM it doesn't matter, since MyISAM doesn't enforce foreign key constraints.)
To create foreign key constraints as part of the table definition, I put that on a separate line:
CREATE TABLE emp (
dname CHAR(10),
ename CHAR(10),
CONSTRAINT FK_emp_dept FOREIGN KEY (dname) REFERENCES dept(dname)
) ENGINE=InnoDB ;

Related

Foreign Key Constraint On delete cascade not effective

I have created two tables (emp and dept). Emp contains a foreign key (deptid). I am attempting to delete a row from the dept table and am receiving a foreign key constraint error. I then altered the emp table foreign key to add constraint and delete on cascade. The code is copied here
create table dept (
deptid int primary key,
deptname varchar(20),
locid int);
create table emp (
empid int primary key,
frname varchar(15),
lname varchar(20),
hiredate datetime,
deptid int,
foreign key (deptid) references dept(deptid));
alter table emp add constraint fk_deptid foreign key (deptid)
references dept(deptid) on delete cascade;
This is the error message that I receive:
Query Error: Error: ER_ROW_IS_REFERENCED_2: Cannot delete or update a parent row: a foreign key constraint fails (test.emp, CONSTRAINT emp_ibfk_1 FOREIGN KEY (deptid) REFERENCES dept (deptid))
The problem is that you are creating two foreign key constraints for the same column. Avoid doing this, it's confusing.
The first one is created while you create the table and is unnamed. Since you didn't provide a name for it, MySQL automatically names it for you as emp_ibfk_1. This one does not have CASCADE DELETE and prevents deletion of parent keys.
The second one is on a separate SQL statement and you name it fk_deptid. This one has CASCADE DELETE and allows deletion of parent keys.
While enforcing the foreign key constraints MySQL cannot delete the row since the first constraint does not allow it. That's the error you are getting.
This is a confusing situation and I would avoid doing something like this. I would suggest having a single FK constraint for the column; specifically I would remove the first one.
For example:
create table dept (
deptid int primary key,
deptname varchar(20),
locid int);
create table emp (
empid int primary key,
frname varchar(15),
lname varchar(20),
hiredate datetime,
deptid int
-- , foreign key (deptid) references dept(deptid) -- removed
);
alter table emp add constraint fk_deptid foreign key (deptid)
references dept(deptid) on delete cascade;
insert into dept (deptid, deptname, locid)
values (1, 'Math', 123);
insert into emp (empid, frname, lname, hiredate, deptid)
values (10, 'Peter', 'Fonda', null, 1);
delete from dept where deptid = 1; -- works!

How to fix foreign key constraint when trying to references two primary keys from the same table?

Misson:
I'm trying to create two tables in MySQL, the first table has two primary keys (composite). The second table has three, two of which are foreign keys that reference the first tables two primary keys. So now I'm trying to bridge them, which isolates the problem code and can be seen below.
Issue:
MySQL workbench refuses allow me to create a table that references another table's two primary keys. It just gives me the error code: 1215. Cannot add foreign key constraint.
I tried:
Changing the attribute types from datetime to varchar(). Changing the attribute names. Checked spelling 5 times. Referencing only one key works fine, but I need both.
Problem Code (SQL Table):
CREATE TABLE IF NOT EXISTS TestInformation2
(
WorkOrder varchar(15),
Date datetime,
TechnicianID smallint,
Primary key (WorkOrder, Date)
) ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS TestBridge2
(
TestBridgeID integer Primary key,
WorkOrder varchar(15),
Date datetime,
Foreign key (WorkOrder) references TestInformation (WorkOrder),
Foreign key (Date) references TestInformation (Date)
) ENGINE = InnoDB;
Result I want:
Create the table 'TestBridge' which has the two foreign key attributes: WorkOrder and Date
It should be one composite foreign key, not two:
CREATE TABLE `TestBridge2` (
`TestBridgeID` INTEGER NOT NULL,
`WorkOrder` VARCHAR(15),
`Date` DATETIME,
PRIMARY KEY (`TestBridgeID`),
CONSTRAINT FOREIGN KEY (`WorkOrder`, `Date`) REFERENCES `TestInformation2` (`WorkOrder`, `Date`)
)
ENGINE=InnoDB;
One single foreign key has to be created for this like:
CREATE TABLE IF NOT EXISTS TestBridge2
(
TestBridgeID integer Primary key,
WorkOrder varchar(15),
Date datetime,
Foreign key (WorkOrder, Date) references TestInformation2 (WorkOrder, Date)
) ENGINE = InnoDB;

Issue with MySQL, cannot add foreign key constraint

I'm trying to create a table named appointment, though when I try to create it I receive the error:
Cannot add foreign key constraint
My SQL code is as follows:
CREATE TABLE APPOINTMENT(
APNo VARCHAR(5),
PNo VARCHAR(5),
DNo VARCHAR(5),
APDATE DATETIME
);
ALTER TABLE APPOINTMENT
ADD PRIMARY KEY (APNo),
ADD FOREIGN KEY (PNo) REFERENCES PATIENT(PNo),
ADD FOREIGN KEY (DNo) REFERENCES DOCTOR(DNo)
;
You syntax looks ok. You are not showing the DDL for referrenced tables PATIENT and DOCTOR, however it is likely that the error happens because one of MySQL foreign keys requirements is not met.
Quotes from the documentation:
Corresponding columns in the foreign key and the referenced key must have similar data types.
You must ensure that both DOCTOR(DNo) and PATIENT(PNo) are VARCHAR(5).
MySQL requires indexes on foreign keys and referenced keys. [...] Such an index is created on the referencing table automatically if it does not exist.
Ideally, DOCTOR(DNo) and PATIENT(PNo) should be the primary key of their respective tables. Else, an index must exist for each of them (it could be a multi-column index where the referrenced column appears once).
See this db fiddle for a working example:
CREATE TABLE PATIENT(PNo VARCHAR(5) PRIMARY KEY);
CREATE TABLE DOCTOR(DNo VARCHAR(5) PRIMARY KEY);
CREATE TABLE APPOINTMENT(
APNo VARCHAR(5),
PNo VARCHAR(5),
DNo VARCHAR(5),
APDATE DATETIME
);
ALTER TABLE APPOINTMENT
ADD PRIMARY KEY (APNo),
ADD FOREIGN KEY (PNo) REFERENCES PATIENT(PNo),
ADD FOREIGN KEY (DNo) REFERENCES DOCTOR(DNo)
;

MySQL, MariaDB: Cannot create a table - ERROR 1005 (HY000). Something wrong with foreign key

I am new to databases and I keep getting an error when I try to create these tables. Where is a mistake?
I have found loads of questions similar to mine, but they didn't help me to resolve this problem.
CREATE TABLE IF NOT EXISTS course
(
cou_id VARCHAR(3),
course_name VARCHAR(25),
CONSTRAINT pk_course PRIMARY KEY (cou_id, course_name)
);
CREATE TABLE IF NOT EXISTS students_marks
(
stu_id INT,
student_name VARCHAR(25),
course_name VARCHAR(25),
first_mark NUMERIC(2,0),
second_mark NUMERIC(2,0),
third_mark NUMERIC(2,0),
CONSTRAINT pk_studentsmarks PRIMARY KEY (stu_id),
CONSTRAINT fk_studentsmarks_course FOREIGN KEY (course_name) REFERENCES course (course_name)
);
This is from INNODB STATUS.
LATEST FOREIGN KEY ERROR
------------------------
130603 20:17:22 Error in foreign key constraint of table testdb/students_marks:
FOREIGN KEY (course_name) REFERENCES course (course_name)
):
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.
Note that the internal storage type of ENUM and SET changed in
tables created with >= InnoDB-4.1.12, and such columns in old tables
cannot be referenced by such columns in new tables.
See http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
for correct foreign key definition.
Your primary key is set to cou_id and course_name in your course table. To add a foreign key constraint in your students_marks table, you'd have to reference both fields (and include both fields in your table definition):
CREATE TABLE IF NOT EXISTS course
(
cou_id VARCHAR(3),
course_name VARCHAR(25),
CONSTRAINT pk_course PRIMARY KEY (cou_id, course_name)
);
CREATE TABLE IF NOT EXISTS students_marks
(
stu_id INT,
student_name VARCHAR(25),
cou_id VARCHAR(3),
course_name VARCHAR(25),
first_mark NUMERIC(2,0),
second_mark NUMERIC(2,0),
third_mark NUMERIC(2,0),
CONSTRAINT pk_studentsmarks PRIMARY KEY (stu_id),
CONSTRAINT fk_studentsmarks_course FOREIGN KEY (cou_id,course_name) REFERENCES course(cou_id,course_name)
);
SQL Fiddle Demo
You are referencing only one field of a composed primary key!

Creating a table with composite primary key referencing two foreign keys

I'm trying to create a the following table using MySQL:
CREATE TABLE registrations (
eventNumber CHAR(3) UNIQUE NOT NULL
CHECK (EXISTS (SELECT eventNumber FROM events)),
employeeNumber CHAR(5) UNIQUE NOT NULL
CHECK (EXISTS (SELECT employeeNumber FROM employees)),
PRIMARY KEY(eventNumber , employeeNumber ),
FOREIGN KEY (eventNumber) REFERENCES eventNumber (employees)
ON UPDATE RESTRICT
ON DELETE RESTRICT,
FOREIGN KEY (employeeNumber ) REFERENCES employeeNumber(employees)
ON UPDATE RESTRICT
ON DELETE RESTRICT
) ENGINE=InnoDB;
However, I get a can't create table error (1005) when I run the command. What might be going wrong here?
For reference, I got the REFERENCES statement wrong.
It should in fact read:
REFERENCES <table name>(<attribute name>)