defining new trigger sql error - mysql

My goal in general is like that:
I have a a table with many translations - each translation have a rating - the average of all ratings from the user.
each translation have a unique Id, and in the second table I am saving for each user that ranked a translation the rating he\she gave (userId, translationId, rating)
now everytime a user rank a new translation or change his old rate I want to update the average rating of this translation
I have the following tables:
Create Table if not exists Translation
(TranslationID int (12) NOT NULL UNIQUE AUTO_INCREMENT,
UserID int (10) NOT NULL,
ImageID int (10) NOT NULL,
ChainID int (2) NOT NULL,
Translation text,
TranslationRating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
NumOfRatings int (10) Default 0,
CONSTRAINT translations PRIMARY KEY (UserID,ImageID, ChainID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (ImageID) REFERENCES Images(ImageID) ON DELETE CASCADE)
Create Table if not exists TranslationsRating
(UserID int (10) NOT NULL ,
TranslationID int (3) NOT NULL,
Rating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
CONSTRAINT known_lang PRIMARY KEY (UserID,TranslationID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (TranslationID) REFERENCES Translation(TranslationID) ON DELETE CASCAD
this means that everytime a new row is inserted into 'TranslationsRating' or I update the rating column in this table I want to take the translationId of the row that was just changed and in the 'translation' table update this translationId rating (find all rating for this Id in 'TranslationsRating' and calc the average)
I'm trying to define the following trigger:
CREATE TRIGGER UPDATE_TRANS_RATING
AFTER UPDATE ON TRANSLATIONSRATING
FOR EACH ROW
BEGIN
UPDATE TRANSLATION SET TRANSLATIONRATING = (SELECT AVG(RATING) FROM TRANSLATIONSRATING
WHERE TRANSLATIONSRATING.TRANSLATIONID = RATINGNEW.ID)
END;
and I'm getting the following error message (I'm using phpMyAdmin):
MySQL said: #1303 - Can't create a TRIGGER from within another stored routine
my question is what is this error, and if my trigger is written in a good way that will achive my goal

Related

Derived Attribute of average of another table

Is there a way to create a column in a table that derives its values from the average of the values of a column of another table.
I'd like to have the rating column in the table Series have the averages of the opinion column of the table Status where the name are the same.
This is the current database.
CREATE TABLE User
(UName VARCHAR(30),
Password VARCHAR(30) NOT NULL,
Score INT,
PRIMARY KEY(UName));```
CREATE TABLE Status
(UName VARCHAR(30),
SName VARCHAR(50),
Opinion INT,
CONSTRAINT OpinionCk CHECK (Opinion BETWEEN 0 AND 100),
PRIMARY KEY(UName, Sname),
FOREIGN KEY(UName) REFERENCES User(UName) ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (SName) REFERENCES Serie(SName) ON UPDATE CASCADE ON DELETE CASCADE);
/* here comes the part where i have the problem:*/
CREATE TABLE Series
(SName VARCHAR(50),
Rating REAL AS (
(SELECT AVG(Opinion)
FROM Status
WHERE
Status.SName = Series.SName)
),
Genre VARCHAR(50),
Episodecount INT,
PRIMARY KEY(SName));
Is there a better way to create the table Series? Maybe as a view...?

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).

How does one create a trigger which when a data set is entered for a new week, a calculation is performed on the previous week's data set in MySQL?

Lets say I have 2 tables:
DROP TABLE IF EXISTS `datasetCalculation`;
DROP TABLE IF EXISTS `dataset`;
CREATE TABLE IF NOT EXISTS `dataset`(
`datasetID` INT NOT NULL AUTO_INCREMENT,
`datasetWeekOf` DATE, #date indicates the beginning of a week
`dataInsertedByID` INT NOT NULL,
`datasetItem1` INT,
`datasetItem2` INT,
`datasetItem3` INT,
PRIMARY KEY (`datasetID`, `datasetWeekOf`)
)Engine = InnoDB;
CREATE TABLE IF NOT EXISTS `datasetCalculation`(
`datasetID` INT NOT NULL,
`datasetWeekOf` DATE,
`datasetItemSum` INT,
PRIMARY KEY (`datasetID`, `datasetWeekOf`),
CONSTRAINT `datasetID_FK`
FOREIGN KEY (`datasetID`)
REFERENCES `dataset` (`datasetID`)
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT `datasetWeekOf_FK`
FOREIGN KEY (`datasetID`)
REFERENCES `dataset` (`datasetID`)
ON UPDATE CASCADE
ON DELETE CASCADE
) Engine = InnoDB;
What I'd like to do is when dataset is updated with the next week's information (it is updated once a week), automatically insert the relevant information into datasetCalculation. The equivalent would be to calculate in some language (let's say php) the sum of datasetItem(1-3), then inserting that into datasetCalculation.datasetItemSum with the other relevant information. Instead I'd like this to be done automatically by the database.

Trigger in MYSQL that delete

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.

Nesting of groups or elements

I'm fairly new in Mysql, but I have problem that I cannot solve. I will give you an example to demonstrate it. Please note that I know that (for current example) there are other simpler and more efficient ways to solve it... but just take it as an example of the required procedure.
First the data: The data would be the name of a Person.
CREATE TABLE person(
id INT,
name VARCHAR(100)
) TYPE=innodb;
Second: Group Creation... So this is fairly simple... and could easily done using a table 'group' with a foreignkey to person. These groups could be arbitrary, containing any number of persons, duplicated... or not... (that is simple!!)
Third: MY REAL PROBLEM--- I also would like to have Groups that have other Groups as elements (instead of persons). This is where a really get stuck, because I know how to create a groups of persons, a group of groups (having a self-referencing foreign key)... but I don't know how to create a group that MAY HAVE persons AND Groups.
I appreciate any suggestion to solve this issue.
Thank you very much for your comments.
Regards
ACombo
I'd go with firstly setting up the myGroup and person tables.
Secondly, I'd set up a myGroupGroup table with columns myGroupId, parentMyGroupId. This will allow you to relate group rows to child group rows i.e. "this group has these groups within it". If a group has no rows in this table then it has no child groups within it.
Thirdly, I'd set up a personGroup table with columns personId, myGroupId. This will allow you to relate person rows to a given group. If a group has no rows in this table then it has no persons within it.
CREATE TABLE person(
id INT UNSIGNED PRIMARY KEY,
name VARCHAR(100)
) ENGINE=innodb;
CREATE TABLE myGroup(
id INT UNSIGNED PRIMARY KEY,
groupName VARCHAR(100)
) ENGINE=innodb;
-- Holds groups within groups
CREATE TABLE myGroupGroup(
id INT UNSIGNED PRIMARY KEY,
myGroupId INT UNSIGNED,
parentMyGroupId INT UNSIGNED DEFAULT NULL,
CONSTRAINT `fk_myGroupGroup_group1` FOREIGN KEY (`parentMyGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_myGroupGroup_group2` FOREIGN KEY (`myGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=innodb;
-- Holds persons within a group
CREATE TABLE personGroup(
id INT,
personId int UNSIGNED NOT NULL,
myGroupId int UNSIGNED NOT NULL,
CONSTRAINT `fk_personGroup_group1` FOREIGN KEY (`myGroupId`) REFERENCES `myGroup` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `fk_personGroup_person1` FOREIGN KEY (`personId`) REFERENCES `person` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=innodb;
I've tweaked your SQL a bit:
1) Replaced TYPE with ENGINE
2) Replaced table name group with myGroup (GROUP is a reserved word)
Good luck!
Alternative:
CREATE TABLE Entity
( EntityId INT --- this id could be AUTO_INCREMENT
, PRIMARY KEY (EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Person
( PersonId INT --- but not this id
, PersonName VARCHAR(100)
, PRIMARY KEY (PersonId)
, FOREIGN KEY (PersonId)
REFERENCES Entity(EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Grouping
( GroupingId INT --- and neither this id
, GroupingName VARCHAR(100)
, PRIMARY KEY (GroupingId)
, FOREIGN KEY (GroupingId)
REFERENCES Entity(EntityId)
) ENGINE = InnoDB ;
CREATE TABLE Belongs
( EntityId INT
, GroupingID INT
, PRIMARY KEY (EntityId, GroupingId)
, FOREIGN KEY (EntityId)
REFERENCES Entity(EntityId)
, FOREIGN KEY (GroupingID)
REFERENCES Grouping(GroupingId)
) ENGINE = InnoDB ;