Trigger in MYSQL that delete - mysql

I have posted this code in another threat, but this question is slightly different. I have to make a trigger. The question sounds like this:
"Create a trigger that removes the season if unused whenever
information about when and who produces a product is deleted (i.e.,
whenever a record is removed from the 'Produces' table, check if there
are other records about product being produced for the same season, if
not, remove also the corresponding record from the season table)"
My MYSQL code:
the MYSQL code is here:
CREATE TABLE IF NOT EXISTS Dvds(
Serial integer NOT NULL,
Name varchar(50),
Year integer,
Genre varchar(50),
Price integer,
PRIMARY KEY (Serial));
CREATE TABLE IF NOT EXISTS Shops(
Id integer NOT NULL,
Name varchar(50),
Address varchar(50),
PRIMARY KEY (Id));
CREATE TABLE IF NOT EXISTS Customers(
CNo integer NOT NULL,
AccNo integer,
Time varchar(50),
PRIMARY KEY (CNo));
CREATE TABLE IF NOT EXISTS ContactPersons(
Id integer NOT NULL,
Name varchar(50),
Phone integer,
PRIMARY KEY (Id));
CREATE TABLE IF NOT EXISTS Seasons(
StartDate date NOT NULL,
EndDate date NOT NULL,
PRIMARY KEY (StartDate,EndDate));
CREATE TABLE IF NOT EXISTS WebShops(
Id integer NOT NULL,
Url varchar(50),
FOREIGN KEY (Id) REFERENCES Shops (Id),
PRIMARY KEY (Id));
CREATE TABLE IF NOT EXISTS Producer(
Id integer NOT NULL,
Address varchar(50),
Name varchar(50),
PRIMARY KEY (Id));
CREATE TABLE IF NOT EXISTS Sold(
Id integer NOT NULL,
CNo integer NOT NULL,
Serial integer NOT NULL,
FOREIGN KEY (Id) REFERENCES Shops (Id),
FOREIGN KEY (CNo) REFERENCES Customers (CNo),
FOREIGN KEY (Serial) REFERENCES Dvds (Serial),
PRIMARY KEY (Id,CNo,Serial));
CREATE TABLE IF NOT EXISTS Has(
Id integer NOT NULL,
Serial integer NOT NULL,
FOREIGN KEY (Id) REFERENCES Shops (Id),
FOREIGN KEY (Serial) REFERENCES Dvds (Serial),
PRIMARY KEY (Id,Serial));
CREATE TABLE IF NOT EXISTS Has2(
Serial integer NOT NULL,
Producer_Id integer NOT NULL,
StartDate date NOT NULL,
EndDate date NOT NULL,
ContactPersons_Id integer NOT NULL,
FOREIGN KEY (Serial) REFERENCES Dvds (Serial),
FOREIGN KEY ( Producer_Id) REFERENCES Producer (Id),
FOREIGN KEY (StartDate) REFERENCES Seasons (StartDate),
FOREIGN KEY (EndDate) REFERENCES Seasons (EndDate),
FOREIGN KEY (ContactPersons_Id) REFERENCES ContactPersons (Id),
PRIMARY KEY (Serial,Producer_Id,StartDate,EndDate,ContactPersons_Id));
The trigger:
CREATE TRIGGER `Seasons_before_delete`
AFTER DELETE ON `Seasons`
FOR EACH ROW
BEGIN
DELETE FROM seasonstart
WHERE seasonstart.???????
DELETE FROM seasonend
WHERE seasonend.??????
END
but I really don't know. My teacher told me that I could use IF , ELSEIF, GOTOEND? But am i on the right track? I'm really blank right now what to do, so hope someone have a suggestion, what I could do to solve this?

In a trigger you have 2 virtual tables.
NEW and OLD.
Obviously in a create trigger there is no old and in a delete trigger there is no new.
So if you want to use the data of the table where the change happened (the table the trigger is attached to) you use those two tables.
Because this is a delete trigger you'll need to use the old table.
So your trigger will look something like this:
CREATE TRIGGER `Seasons_before_delete` AFTER DELETE ON `Seasons`
FOR EACH ROW
BEGIN
DELETE FROM seasonstart
WHERE seasonstart.seasonID = old.ID
DELETE FROM seasonend
WHERE seasonend.seasonID = old.ID
END
Note that it makes little sense to call a AFTER DELETE trigger "something_something_BEFORE" :-).
Further note that I have no idea why you need an IF in this trigger, the where in the delete statement already takes care of that.

Related

MySQL Error Code 1215: “Cannot add foreign key constraint”

I keep getting this error when attempting to create a table with SQL.
I have these two tables:
I'm using PHPMyAdmin and it won't allow me to use M_id as a foreign key which references Employee Table primary key E_id.
Anyone able to see what's wrong with my code?
Thanks!
Foreign key definitions have to exactly match the primary key columns to which they refer. In this case, you defined Department.M_id to a be a nullable integer column, while EMPLOYEE.E_id is integer not nullable. Try making M_id not nullable:
CREATE TABLE Department (
D_name VARCHAR(100) NOT NULL,
D_id INT NOT NULL,
M_id INT NOT NULL DEFAULT 0000,
...
FOREIGN KEY (M_id) REFERENCES EMPLOYEE(E_id)
ON DELETE SET DEFAULT ON UPDATE CASCADE
)
Your code has multiple errors:
varchar() length is too long.
You have a forward reference for a foreign key constraint.
SET DEFAULT doesn't really work.
You want something like this:
CREATE TABLE employees (
employee_id int not null primary key,
Job_type VARCHAR(100),
Ssn INT NOT NULL,
Salary DECIMAL NOT NULL,
Address VARCHAR(500) NOT NULL,
First_name VARCHAR(50) NOT NULL,
M_initial CHAR(1),
Last_name VARCHAR(50) NOT NULL,
E_end_date DATE,
E_start_date DATE NOT NULL,
department_id INT NOT NULL,
Super_id INT,
FOREIGN KEY (Super_id) REFERENCES employees(employee_id) ON DELETE SET NULL ON UPDATE CASCADE,
UNIQUE (Ssn)
);
CREATE TABLE departments (
department_id int primary key,
D_name VARCHAR(100) NOT NULL,
D_id INT NOT NULL,
M_id INT DEFAULT 0000,
Manager_start_date DATE NOT NULL,
Manager_end_date DATE,
Report VARCHAR(8000),
Num_of_employees INT NOT NULL,
FOREIGN KEY (M_id) REFERENCES employees(employee_id) ON DELETE SET NULL ON UPDATE CASCADE,
UNIQUE (D_name)
);
ALTER TABLE employees ADD CONSTRAINT FOREIGN KEY (department_id) REFERENCES departments(department_id)
ON DELETE CASCADE ON UPDATE CASCADE;
I also changed a few other things:
The table names are plural.
The primary keys are the singular form followed by "_id".
Foreign keys and primary keys have the same name.
The primary key is the first column in the table.
Here is a db<>fiddle showing that this works.
I will not question your design, though it looks problematic.
However - You cannot reference a table which doesn't exist yet (REFERENCES Department(D_id)). You should either remove the FOREIGN KEY constraints from the CREATE statements and add them afterwards in ALTER TABLE statements.
Example:
CREATE TABLE EMPLOYEE (...);
CREATE TABLE Department (...);
ALTER TABLE EMPLOYEE
ADD FOREIGN KEY (D_id)
REFERENCES Department(D_id)
ON DELETE CASCADE
ON UPDATE CASCADE
;
Demo
Or temporarily disable foreign key checks:
SET FOREIGN_KEY_CHECKS = 0;
CREATE TABLE EMPLOYEE (...);
CREATE TABLE Department (...);
SET FOREIGN_KEY_CHECKS = 1;
Demo
You can also not use ON DELETE SET DEFAULT. InnoDB doesn't support it. You need to change it to ON DELETE SET NULL. If you want that behavior, you will need to implement it either in your application code or in a trigger.
I would also use TEXT as data type instead of VARCHAR(30000).

error 1215: database design with foreign key

I am trying to create three tables such as associate, manager and attendance. The attendance table should be having employee and manager details from the other two table which should enable marking the attendance. I created this SQL script. I'm not sure where I am making mistake.
CREATE TABLE associate (
id INT NOT NULL,
idmanager INT NOT NULL,
emp_id DATE NOT NULL,
emp_name VARCHAR(25) NOT NULL,
FOREIGN KEY (id) REFERENCES attendance (associate_id) ON DELETE CASCADE,
FOREIGN KEY (idmanager) REFERENCES attendance (manager_idmanager) ON DELETE CASCADE,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE manager (
id INT NOT NULL,
mgr_usr_id VARCHAR(15) NOT NULL,
mgr_name VARCHAR(25) NOT null,
KEY (id),
KEY (mgr_usr_id),
FOREIGN KEY (id) REFERENCES associate (idmanager) ON DELETE CASCADE,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INT NOT NULL,
manager_idmanager INT NOT NULL,
associate_id INT NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno)
) ENGINE=INNODB;
Screenshot
It's an issue of ordering. For example, the first statement executed is
CREATE TABLE associate (
which references attendance. However, the attendance table has not yet been created. Switch the order so that any tables that reference other tables come last.
Alternatively, don't put the FOREIGN KEY constraints in the CREATE statements, but them at the end of your script with ALTER TABLE statements. Consider:
CREATE TABLE associate (
id INT NOT NULL,
idmanager INT NOT NULL,
emp_id DATE NOT NULL,
emp_name VARCHAR(25) NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INT NOT NULL,
manager_idmanager INT NOT NULL,
associate_id INT NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno)
) ENGINE=INNODB;
ALTER TABLE associate ADD FOREIGN KEY (id) REFERENCES associate(id) ON DELETE CASCADE;
Edit
The above is just syntax. To model the requested problem consider orthogonality of information. You might also see/hear "normalization." The basic concept is this: have only one copy of your information. The schema should have a single point of authority for all data. For example, if a user has a birthdate, make sure you don't have an ancillary column that also stores their birthday; it's superfluous information and can lead to data errors.
In this case, what is the relationship? What must come first for the other to exist? Can an attendance be had without a manager? How about a manager without attendance? The former makes no sense. In this case then, I would actually use a third table, to form a hierarchy.
Then, consider that maybe roles change in a company. It would not behoove the DB architect to hard code roles as tables. Consider:
CREATE TABLE employee (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(25) NOT NULL,
PRIMARY KEY (id)
) ENGINE=INNODB;
CREATE TABLE role (
id INTEGER NOT NULL AUTO_INCREMENT,
name VARCHAR(30) NOT NULL,
description VARCHAR(254) NOT NULL,
PRIMARY KEY( id ),
UNIQUE( name )
) ENGINE=INNODB;
INSERT INTO role (name, description) VALUES
('associate', 'An associate is a ...'),
('manager', 'A manager follows ...');
CREATE TABLE employee_role (
employee_id INTEGER NOT NULL,
role_id INTEGER NOT NULL,
PRIMARY KEY (employee_id, role_id),
FOREIGN KEY (idemployee_id) REFERENCES employee_id (id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES role (id) ON DELETE CASCADE
) ENGINE=INNODB;
CREATE TABLE attendance (
sno INTEGER NOT NULL,
employee_id INTEGER NOT NULL,
date_stamp DATETIME,
state BIT NOT NULL,
PRIMARY KEY (sno),
FOREIGN KEY (idemployee_id) REFERENCES employee_id (id) ON DELETE CASCADE
) ENGINE=INNODB;
From this schema, the attendance needs only one foreign key because everyone is an employee. Employee's can have multiple roles, and they can change. Further, role definitions can change without needing to resort to costly DDL statements (data definition layer changes, like ALTER TABLE), and can be modified with simple DML (data manipulation layer changes, like UPDATE TABLE). The former involves rewriting all entries in the tables, and changing schemas, while the latter involves changing individual entries.

"Cannot add foregin key constraint"

DROP TABLE IF EXISTS CARD_ACCOUNT;
Create Table CARD_ACCOUNT(
acct_no Char(16),
exp_date date,
card_type ENUM('Debit','Credit') NOT NULL,
cust_ID integer NOT NULL
);
DROP TABLE IF EXISTS DEBIT_CARD;
Create Table DEBIT_CARD(
acct_no Char(16),
exp_date date,
bank_no CHAR(9) NOT NULL,
Constraint debit_card_pk primary key(acct_no,exp_date),
Constraint debit_card_fk foreign key(acct_no,exp_date) References card_account(Acct_no,exp_date)
ON UPDATE CASCADE
ON DELETE CASCADE
);
When I try to run this statement I get a "Cannot add foregin key constraint" error in Mysql on the Debit_Card table, why do I get this error the script I am learning from has everything writen the same exact way as I have.
card_account(Acct_no,exp_date) must be Primary Key if you want reference to it in Foreign Key.
and why you don't make it into 1 table?
Create Table CARD_ACCOUNT(
acct_no Char(16),
exp_date date,
bank_no CHAR(9) NOT NULL,
card_type ENUM('Debit','Credit') NOT NULL,
cust_ID integer NOT NULL,
Constraint CARD_ACCOUNT_PK primary key(acct_no,exp_date)
);
i think it serve the same purpose. you already have card_type to know if its debit or credit card so why make separate table for that?
Use the below code, I have just added one primary key constraint in the first table, it will allow you to create the foreign key. But, as "Tim Biegeleisen" commented there is database design problem, you should think again about your database design.
DROP TABLE IF EXISTS CARD_ACCOUNT;
Create Table CARD_ACCOUNT(
acct_no Char(16),
exp_date date,
card_type ENUM('Debit','Credit') NOT NULL,
cust_ID integer NOT NULL,
Constraint debit_card_pk primary key(acct_no,exp_date)
);
DROP TABLE IF EXISTS DEBIT_CARD;
Create Table DEBIT_CARD(
acct_no Char(16),
exp_date date,
bank_no CHAR(9) NOT NULL,
Constraint debit_card_pk primary key(acct_no,exp_date),
Constraint debit_card_fk foreign key(acct_no,exp_date) References card_account(Acct_no,exp_date)
ON UPDATE CASCADE
ON DELETE CASCADE
);

Child table doesn't get deleted

I created two tables in mysql,
customer
house table with houseID being foreign key in my customer table.
Create customer table(
id int not null primary key auto_increment,
name varchar not null,
houseId int not null,
telephoneNo, int not null,
CONSTRAINT FOREIGN KEY (houseId) REFERENCES house(id) ON DELETE CASCADE);
CREATE house table(id int not null primary key auto_increment,
houseNo int not null,
address varchar not null);
However, when I delete customer with a specific houseId, the row in house table doesn't get deleted though I put on delete cascade in the customer table. Any idea why?
Your foreign key is on the wrong table. The way you got it set up is that if you delete a house, the corresponding cutomer will be cascaded.
You will want to put a customerId foreign key in the house table and have ON DELETE CASCADE foreign key trigger from side.
With a foreign key the ON DELETE is asking: what if the foreign key I am referencing is deleted (cascade, set null, do nothing)? not what to do when this row get's deleted.

mysql foreign key reference from a composite key

I am creating an application that will handle and record when a student gets advised by a faculty member at a university and I need an effective way to structure the tables. My problem is coming from a lack of referential integrity, caused by the inability to create a foreign key that will reference a STUDENT on only part of a composite key in ADVISE_HIST which is (STUDENT_ID,DATE_ADVISED)
here are some of the tables
create table STUDENT(
LNAME varchar(50),
FNAME varchar(50),
ID char(9) primary key,
ASSIGNED_ADVISOR_EMAIL varchar(70),
foreign key (ASSIGNED_ADVISOR_EMAIL) references DEP_FACULTY(EMAIL) ON DELETE SET NULL,
IS_ADVISED tinyint(1),
);
create table DEP_FACULTY(
LNAME varchar(50),
FNAME varchar(50),
EMAIL varchar(70) primary key
);
create table ADVISE_HIST(
STUDENT_ID char(9),
/*foreign key (STUDENT_ID) references STUDENT(ID),*/
ACTUAL_ADVISOR_EMAIL char(70) NOT NULL,
foreign key (ACTUAL_ADVISOR_EMAIL) references DEP_FACULTY(EMAIL),
DATE_ADVISED date,
primary key REF_ADVISE_HIST (STUDENT_ID, DATE_ADVISED),
);
My question is, is there a way around not being able to create this key or is there a better structure that I'm not thinking of?
MySQL has a lot of restrictions on foreign keys. Among the ones that might be getting in your way . . .
Both tables have to use the INNODB engine.
"In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. "
This code works in my version (5.1.62).
create table DEP_FACULTY(
LNAME varchar(50),
FNAME varchar(50),
EMAIL varchar(70) primary key
) ENGINE = INNODB;
insert into DEP_FACULTY values ('Gregor', 'Brandich', 'gbrandich#thisdomain.com');
create table STUDENT(
LNAME varchar(50),
FNAME varchar(50),
ID char(9) primary key,
ASSIGNED_ADVISOR_EMAIL varchar(70),
foreign key (ASSIGNED_ADVISOR_EMAIL) references DEP_FACULTY(EMAIL) ON DELETE SET NULL,
IS_ADVISED tinyint(1)
) ENGINE = INNODB;
insert into STUDENT values ('Charmaine', 'DePeletier', 'cmd', 'gbrandich#thisdomain.com', 1);
create table ADVISE_HIST(
STUDENT_ID char(9),
foreign key (STUDENT_ID) references STUDENT(ID),
ACTUAL_ADVISOR_EMAIL char(70) NOT NULL,
foreign key (ACTUAL_ADVISOR_EMAIL) references DEP_FACULTY(EMAIL),
DATE_ADVISED date,
primary key REF_ADVISE_HIST (STUDENT_ID, DATE_ADVISED)
) ENGINE = INNODB;
insert into ADVISE_HIST values ('cmd', 'gbrandich#thisdomain.com', CURRENT_DATE);
insert into ADVISE_HIST values ('ctd', 'gbrandich#thisdomain.com', CURRENT_DATE);
Of those last two inserts, the first works. The second should throw a foreign key constraint error.