Enter the default month and day with a prefixed year mysql - mysql

Hi I have this code and I have been asked for this query: Surname of the actors in alphabetical order, with the titles of the films in which they participated, and their age at
time of participation in film production (conventionally dated 30 June);
I have tried in every way the datediff function but it keeps giving me error, from what I understand does not accept the production year written in that way. How do I set the month and day as a query and then use the datediff? thank you very much for those who will help me, I'm wasting my time for nonsense. Excuse me but I'm still in the beginning
create database cinema;
use cinema;
create table participation(film varchar (3) not null ,actor varchar(5) not null);
create table actor (id_actor varchar(5) not null,name varchar(30), surname varchar(30) not null);
create table film (id_film varchar(3) not null,title varchar(30) not null, kind varchar (30) not null, producer varchar (5) not null, production_year year(4));
create table producer( id_producer varchar (5) not null, name varchar (30) ,surname varchar(30) not null);
alter table producer add primary key (id_producer);
alter table film add primary key (id_film);
alter table participation add primary key (film,actor);
alter table actor add primary key (id_actor);
alter table participation add constraint fk_pfilm foreign key (film) references film(id_film);
alter table participation add constraint fk_pactor foreign key (actor) references actor(id_actor);
alter table film add constraint fk_fproducer foreign key (producer) references producer (id_producer);
insert into producer(id_producer,name,surname) values ("0000A","Steven","Spielberg"),("0000B","Stanley","Kubrick"),("0000C","Ridley","Scott");
insert into actor(id_actor,name,surname) values ("000AA","Sylvester","Stallone"),("000AB","Brad","Pitt"),
("000AC","George","Clooney"),("000AD","Demi","Moore"),("000AE","Bruce","Willis"),
("000AF","Monica","Bellucci");
insert into film(id_film,title,kind,production_year,producer) values ("00A","Jurassic Park","avventura",'2000',"0000A"),("00B","Matrix","fantascienza",'2001',"0000B"),
("00C","Star Wars","fantascienza",'2000',"0000A"),("00D","Indiana Jones","avventura",'2002',"0000B"),("00E","Rambo","avventura",'2002',"0000A"),
("00F","Rocky I","sportivo",'2001',"0000A"),("00G","Rocky II","sportivo",'2004',"0000B");
insert into participation (film,actor) values ("00A","000AA"),("00B","000AB"),("00C","000AC"),("00D","000AD"),("00E","000AA"),
("00F","000AA"),("00G","000AB"),("00A","000AC"),("00B","000AA"),("00C","000AB"),("00D","000AB");
select * from participation;
select * from actor;
select * from film;
select * from producer;
alter table actor add column datebirth date;
update actor set datebirth='1946-07-06' where id_actor="000AA";
update actor set datebirth='1963-12-18' where id_actor="000AB";
update actor set datebirth='1961-05-06' where id_actor="000AC";
update actor set datebirth='1962-11-11' where id_actor="000AD";
update actor set datebirth='1955-03-19' where id_actor="000AE";
update actor set datebirth='1964-09-30' where id_actor="000AF";
create view vista as select * from (actor inner join participation on id_actor=participation.actor);
create view vista2 as select * from (vista inner join film on vista.film=film.id_film);
select surname,title,datediff(datebirth,production_year-06-30) as età from vista2;

Try to replace anno_produzione-06-30 with:
concat(anno_produzione, '-06-30')
The engine can cast ISO date representations to date.
And you shouldn't use double quotes around string literals. Use singles quotes instead, that's their job in SQL.

Related

Get AVG value for each selected row from MySQL table with 500m rows?

I have one table with 500 million records In MySQL 8.x. My regular query to get a certain result set is 200ms, but if I try to get an AVG value the performance drops to 30s+.
Structure:
KW_ID | DATE | SERP | MERCHANT_ID | ARTICLE_ID
-- auto-generated definition
create table merchants_keyword_serps
(
KW_ID mediumint unsigned null,
MERCHANT_ID tinyint unsigned null,
ARTICLE_ID char(10) null,
SERP tinyint unsigned null,
DATE date null,
constraint `unique`
unique (MERCHANT_ID, ARTICLE_ID, KW_ID, DATE),
constraint fk_serps_kwd_t
foreign key (MERCHANT_ID, ARTICLE_ID) references merchants_product_catalog (MERCHANT_ID, ARTICLE_ID)
on delete cascade,
constraint keywords
foreign key (KW_ID) references merchants_keywords (ID)
on delete cascade
);
create index merchants_keyword_serps_SERP_index
on merchants_keyword_serps (SERP);
create index mks_date
on merchants_keyword_serps (DATE);
Goal, get SERP for 20220122 and MERCHANT_ID = 2:
select
mcs.SERP
FROM merchants_keyword_serps mcs
WHERE date = 20220120
AND mcs.MERCHANT_ID = 2;
Now do also get the AVG SERP for all shops in addition:
select
mcs.SERP,
(
SELECT AVG(SERP)
FROM merchants_keyword_serps mcs2
WHERE mcs2.date = 20220120
AND mcs2.KW_ID = mcs.KW_ID
AND mcs2.ARTICLE_ID = mcs.ARTICLE_ID) AS SERP_AVG
from merchants_keyword_serps mcs
WHERE
date = 20220120
AND mcs.MERCHANT_ID = 2;
The expected result would be an additional column with the average SERP value for all shops with the same KW_ID, DATE, ARTICLE_ID.
Is there a way to speed that up with a different approach? The indexes are all set OK I believe since the standard query runs perfectly fast in unter 200ms.
Where does KW_ID come from? Please provide SHOW CREATE TABLE merchants_keyword_serps.
Using 20220120 for a date is asking for trouble. (I don't see any problem yet.)
Add these:
INDEX(merchant_id, date)
INDEX(kw_id, article_id, date, serp)
and Drop these since they will be redundant:
INDEX(merchant_id)
INDEX(kw_id)

MySQL Procedure to insert data to a table that use auto_increment, get the PK auto_increment generated and insert it into a bridgetable?

I´m creating a restApi with PHP over the courses I have studied. When it comes to the database I´m not sure whats the best practise for this problem ->
I have data over the languages each course had, to normalize data I have languages in a separate table and a bridge to connect them.
So one table for Courses, one for Languages and one bridge table to connect them.
CREATE TABLE `Courses`
(`Course_ID` INT(11),
`Education_ID` INT(11),
`CourseName` VARCHAR(100) NOT NULL,
`Points` VARCHAR (5),
`Grade` VARCHAR(3),
PRIMARY KEY (`Course_ID`)
);
CREATE TABLE `Language` (
`Language_ID` INT(11),
`Language` VARCHAR(100) NOT NULL,
`Img_url` VARCHAR (200),
PRIMARY KEY (`Language_ID`)
);
CREATE TABLE `Bridge_language` (
`Course_ID` INT(11) NOT NULL,
`Language_ID` INT(11) NOT NULL,
KEY `PKFK` (`Course_ID`, `Language_ID`)
);
ALTER TABLE Courses MODIFY Course_ID INTEGER AUTO_INCREMENT;
ALTER TABLE Language MODIFY Language_ID INTEGER AUTO_INCREMENT;
When adding a new course, in the SQL I know the id of the languages, (i will have a function in the admin page where you add new languages) then when you create a new course you just click add languages and the id for the language is added.
But what I don't have is the ID for the course which is created with auto_increment. Is there a smart way you with a function/procedure in SQL, can grab the id that auto_increment has generated and use it to add that into the bridge table?
Or do I need to make a query to the database and grab the latest ID and add one and send that into the bridge table?
In MySQL, you can use last_insert_id() to retrieve the auto-generated id of the last insert query that you executed. You don't give much details about your code, but the logic is like:
insert into course (education_id, coursename, points, grade)
values (?, ?, ?, ?);
insert into bridge_language (course_id, language_id)
values (last_insert_id(), ?);

Declare variable MySQL trigger and create table using that variable

I have a event in which I am storing a string in a variable. Now I want to use that variable to create a new table. Everytime my event runs it creates table with the name of "mon". What is I am doing wrong ?
BEGIN
DECLARE onlyweek INT;
DECLARE mon VARCHAR(20);
SET #mon = "rehan";
CREATE TABLE mon(
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
capacity INT NOT NULL
);
END
Because you use mon instead of #mon. And even then it wont work because you need dynamic SQL for that.
But what is even more important:
Don't do that!
Don't create a table on the fly. Table designs should be static. That smells like a big design flaw.
This is a design mistake. For example, you need to make report for the year. In your design you have to join 12 tables and where-s how to join. And this is very slow.
Better design is creating 2 tables - "months" and "reporting_periods" with foreign key to table 'months'. This way when you need year report - you join only 2 tables by ID with "where".
Table 'months' can be filled once a year using same mysql events.
Then use mysql "stored procedure" (and mysql event) for periodic insert into reporting_period with month id. Months` names can include year as "bad way" or have the field 'year' = 'better one'.
CREATE TABLE months(
id int auto_increment,
name varchar(10),
number int not null,
year int not null,
constraint monthes_pk
primary key (id)
);
and reporting_period
CREATE TABLE reporting_period(
id INT auto_increment,
period_id INT NOT NOT,
capacity INT NOT NULL,
constraint `reporting_period_pk`
primary key (id),
constraint `reporting_period__fk`
foreign key (period_id) references months (id)
);
More about DB design: normalization

MySQL - add data into 2 tables and 1 has foreign key

I'm a totally MySQL newcomer. Sr if my question is quite obvious. I got 2 tables
CREATE TABLE tbl_addresses(
PK_ADDRESS_ID int NOT NULL AUTO_INCREMENT,
house_number int NOT NULL,
street varchar(35),
district varchar(35),
city varchar(35),
postcode varchar(8),
PRIMARY KEY (PK_ADDRESS_ID)
);
CREATE TABLE tbl_people(
PK_PERSON_ID int NOT NULL AUTO_INCREMENT,
title varchar(6) NOT NULL, # Master / Mister therefor 6 is max
forename varchar(35) NOT NULL,
surname varchar(35) NOT NULL,
date_of_birth DATE NOT NULL,
contact_number varchar(12) NOT NULL,
FK_ADDRESS_ID int NOT NULL,
PRIMARY KEY (PK_PERSON_ID),
FOREIGN KEY (FK_ADDRESS_ID) REFERENCES tbl_addresses (PK_ADDRESS_ID)
);
and I'm trying to import data into these tables from Java using below syntaxes
INSERT INTO tbl_addresses (house_number,street,district,city,postcode) VALUES ('1','abc','','abc','abc');
INSERT INTO tbl_people (title,forename,surname,date_of_birth,contact_number) VALUES ('Mr','Tri ','Nguyen','1991-1-1','0123456789');
I got an error Field 'FK_ADDRESS_ID'doesn't have a default value and data actually goes into tbl_addresses but not tbl_people. Am I missing anything? Thanks in advance!
This error is being caused by that you labelled the FK_ADDRESS_ID field in the tbl_people table as NOT NULL, yet you are trying to do an INSERT without specifying a value for this column.
So something like this would work without error:
INSERT INTO tbl_people (title, forename, surname, date_of_birth,
contact_number, FK_ADDRESS_ID)
VALUES ('Mr', 'Tri', 'Nguyen', '1991-1-1', '0123456789', 1);
You could also specify a default value for FK_ADDRESS_ID (the error message you got alluded to this). Here is how you could adda default value:
ALTER TABLE tbl_people MODIFY COLUMN FK_ADDRESS_ID int NOT NULL DEFAULT 1
But because FK_ADDRESS_ID is a key into another table, the value should really be based on the primary key in tbl_addresses.
The fact that you are using a foreign key isn't the reason that you are getting this error. Let's take a look at your column definition.
FK_ADDRESS_ID int NOT NULL,
This is not null but does not a default. Now a look at your insert statement
INSERT INTO tbl_people (title,forename,surname,date_of_birth,contact_number)
FK_ADDRESS_ID isn't in your column list but it cannot be null and doesn't have a default so what can mysql do? Produce an error of course.
The best bet is to define that column as nullable.
Let's revisit the foreign key constraint.
FOREIGN KEY (FK_ADDRESS_ID) REFERENCES tbl_addresses (PK_ADDRESS_ID)
What this really says is that if you asign a value to FK_ADDRESS_ID that value should be present in PK_ADDRESS_ID column in tbl_address
as a side note, it's customary to use lower case for table/column names.

Need help with mysql schema design - current schema requires dynamic sql within a trigger

I imagine that I have designed my database badly, but I'm currently stumped by the fact that I need to use dynamic sql in a trigger and that's making mysql unhappy.
The context is that I have created a membership database with several dozen tables, the main one of which is the 'member' table with a unique primary key 'id'. There are a number of other tables which have foreign keys referring to the member.id field.
Because the data has been gathered over many years and with little dupe-control, there is another field in the 'member' table called 'superseded_by', which contains the id of the member who supersedes this one. By default, superseded_by is set to be the member_id. Any one whose superseded_by <> id is deemed to be a dupe.
Now the tricky part... when we identify a dupe, we want to set the superseded_by field to point to the new primary member and update all the tables with foreign keys pointing to the now redundant member id. I have tried to do this using an after update trigger... and then I've tried to be clever by querying the foreign keys from the information_schema and using dynamic sql to update them.
This clearly doesn't work (Error Code: 1336 Dynamic SQL is not allowed in stored function or trigger).
I'm assuming there is a better way to design the schema / handle dupes which I haven't thought of.
Help please...
CODE SNIPPET:
-- ---
-- Table 'member'
-- ---
DROP TABLE IF EXISTS member;
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
superseded_by INTEGER DEFAULT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (mailing_address_id) REFERENCES mailing_address (id),
FOREIGN KEY (superseded_by) REFERENCES member (id)
);
DELIMITER $$
CREATE TRIGGER set_superseded_by_on_insert BEFORE INSERT ON member FOR EACH ROW
BEGIN
SET NEW.superseded_by = NEW.id;
END$$
-- Trigger to update other tables (volunteers, donations, presenters, etc.) when member's superseded_by record is updated
-- Assumes the new superseding person exists (they should also not be superseded by anyone themselves)
CREATE TRIGGER adjust_foreign_member_keys_on_superseded_by_update AFTER UPDATE ON member FOR EACH ROW
BEGIN
DECLARE db, tbl, col VARCHAR(64);
DECLARE fk_update_statement VARCHAR(200);
DECLARE no_more_rows BOOLEAN;
DECLARE fks CURSOR FOR SELECT kcu.TABLE_SCHEMA, kcu.TABLE_NAME, kcu.COLUMN_NAME
FROM information_schema.TABLE_CONSTRAINTS tc
JOIN information_schema.KEY_COLUMN_USAGE kcu ON
tc.table_schema = kcu.table_schema AND tc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type='FOREIGN KEY' AND
kcu.REFERENCED_TABLE_NAME = 'member' AND
kcu.REFERENCED_COLUMN_NAME = 'id';
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
IF NEW.superseded_by <> OLD.superseded_by THEN
OPEN fks;
SET no_more_rows = FALSE;
update_loop: LOOP
FETCH fks INTO db, tbl, col;
IF no_more_rows THEN
LEAVE update_loop;
END IF;
SET #fk_update_statement = CONCAT("UPDATE ", db, ".", tbl, " SET ", col, " = NEW.superseded_by WHERE ", col, " = NEW.id;");
PREPARE stmt FROM #fk_update_statement;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END LOOP;
CLOSE fks;
END IF;
END$$
DELIMITER ;
Why are you trying to maintain duplicates in your main table? Seems like you'd be better off with a member table and a member_history table to track previous changes. You could do it by having a table that stored the field changed, date changed and the old and new values. Or you could just store the previous snapshot of the member table before updating it. For instance:
INSERT INTO member_history SELECT NULL, * FROM member WHERE id = ?
UPDATE member SET [...] WHERE id = ?
The schema for member_history would be nearly identical except that you would store member.id as member_id and have a separate primary key for each history entry. (Note: I'm glossing over the syntax a little, the NULL, * part might not work in which case you may need to explicitly name all the fields. Haven't taken the time to check it).
CREATE TABLE member (
id INTEGER AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (mailing_address_id) REFERENCES mailing_address (id),
);
CREATE TABLE member_history (
id INTEGER AUTO_INCREMENT,
member_id INTEGER NOT NULL,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
date_of_birth DATE DEFAULT NULL,
gender ENUM('M', 'F') DEFAULT NULL,
mailing_address_id INTEGER DEFAULT NULL,
last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
FOREIGN KEY (member_id) REFERENCES member (id),
);
Notice that I removed the superseded_by field in the member table and the foreign key to mailing_address in the member_history table. You shouldn't need the superseded_by any more and keeping the foreign key in the member_history table isn't really necessary unless you're worried about dangling references in your history.
Ok, just a couple of thoughts on this:
superseded_by is referencing id on the same table and is in general equal to the latter - not in those cases where you were able to identify a dupe, though, in which case it would point to another already existing member's id.
Given that we can safely assume that no superseded_by field will ever hurt the foreign key constraint.
I further assume that id and superseded_by fields of dupes that have not been identified yet are equal.
So, if all of the above is true, you may bend the foreign key of the other related tables to reference superseded_by instead of id. This way you could cascade the changes made to the dupe down to the other tables and still have the exact same constraint as before.
What you think? Am I missing something?
Please note that this is an option only if you are using InnoDB rather than MyISAM.
Regards,
aefxx
Trigger and stored function in mysql have limitations that we can not use dynamic sql in both of these. I hope this helps.