MySQL query between dates - mysql

I have the following table, where bookings can be made
CREATE TABLE booking (
bookingID INT UNSIGNED NOT NULL AUTO_INCREMENT,
customerID INT,
runID INT,
startDate DATETIME,
endDate DATETIME,
dateBookedOn TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (bookingID),
INDEX idx_start (startDate),
INDEX idx_end (endDate),
FOREIGN KEY (runID) REFERENCES RUn(RunID),
FOREIGN KEY (customerID) REFERENCES customer(CustomerID)
)
Then i have a run table
CREATE TABLE run
(
RunID INT UNSIGNED NOT NULL AUTO_INCREMENT,
RunName VARCHAR(15),
PricePerNight DECIMAL(3,2),
primary key (RunID)
);
I am querying the run table to get all runID's that do not lie between two dates in the booking table, as follows.
SELECT *
FROM run
WHERE Runid NOT IN (SELECT RunID
FROM booking
WHERE CAST(startDate AS DATE) >= '2015-07-19' AND
CAST(endDate AS DATE) <= '2015-07-25');
How would I change the query to select runID's that don't have ANY dates between them, if the dates overlap with query dates they are included in result set.
ie if a new booking had a startDate 2015-07-15 and a endDate 2015-07-21 then it will still show in the queries result set.

Your query does what you want, but might be a bit slow: Avoid NOT IN if you can. This should do the same but is just faster:
SELECT a.*
FROM run a
LEFT JOIN booking b ON a.runID=b.runID
AND startDate>= '2015-07-19' AND endDate<= '2015-07-25'
WHERE b.runID IS NULL;
Also avoid casting your data from your database: If you want/have to cast anything, cast your variables: Casting your variable=1 value cast, casting the data from your database is N values cast, plus that indexes can not be used anymore.

Related

Find people who have the same day of birth

I'm looking for a way to create a query that gives me the list of people who were born on the same day (the data is in two different tables).
All ideas are welcome. ( I use MySQL)
SQL code :
https://pastebin.com/StNggaYg
CREATE TABLE Professeurs(
ID_Professeur Int Auto_increment NOT NULL ,
Nom_Professeur Varchar (50) NOT NULL ,
Prenom_Professeur Varchar (50) NOT NULL ,
Ville_de_naissance_P Varchar (50) NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
Professeur_Principal Bool NOT NULL
,CONSTRAINT Professeurs_PK PRIMARY KEY (ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Classes
#------------------------------------------------------------
CREATE TABLE Classes(
ID_Classes Int Auto_increment NOT NULL ,
Lettre_classe Char (5) NOT NULL ,
ID_Professeur Int NOT NULL
,CONSTRAINT Classes_PK PRIMARY KEY (ID_Classes)
,CONSTRAINT Classes_Professeurs_FK FOREIGN KEY (ID_Professeur) REFERENCES Professeurs(ID_Professeur)
)ENGINE=InnoDB;
#------------------------------------------------------------
# Table: Elèves
#------------------------------------------------------------
CREATE TABLE Eleves(
ID_Eleve Int Auto_increment NOT NULL ,
Nom_eleve Varchar (50) NOT NULL ,
Prenom_eleve Varchar (50) NOT NULL ,
Ville_de_naissance_E Varchar (50) NOT NULL ,
Date_de_naissance_E Date NOT NULL ,
ID_Classes Int NOT NULL
,CONSTRAINT Eleves_PK PRIMARY KEY (ID_Eleve)
,CONSTRAINT Eleves_Classes_FK FOREIGN KEY (ID_Classes) REFERENCES Classes(ID_Classes)
)ENGINE=InnoDB;
The column :
Date_de_naissance_E Date NOT NULL ,
Date_de_naissance_P Date NOT NULL ,
First, you would have to get the results of BOTH tables dates via a UNION to find what dates have more than one instance. Its possible to have two teachers with same date, two students with same date, OR a teacher AND student have same date. Once that is done, then you can join back to the respective original source to grab the names.
To simplify the query from rewriting it twice nested within itself, I will use CTE (common table expression). It allows you to write a query that will be used multiple times allowing simple alias name to be used in a subsequent query.
Below is the CTE via "With AllPeople as". This select is the query used in the second half. Notice I am getting ID, name, birth date and also a type "P" as Professeur and "E" as Eleves for the person type. First time through I am getting a count where a given birthdate occurs more than once. THEN, re-join to the same AllPeople again that had that date found as a common birth date.
with AllPeople as
( select
'P' personType,
p.ID_Professeur personID,
p.Nom_Professeur personName,
Date_Format( p.Date_de_naissance_P, "%M %d" ) commonDate
from
Professeurs p
union all
select
'E' personType,
e.ID_Eleve personID,
e.nom_eleve personName,
Date_Format( e.Date_de_naissance_E, "%M %d" ) commonDate
from
Eleves e
)
select
who.PersonType,
who.PersonID,
who.PersonName,
BornOnSameDay.commonDate
from
(select
commonDate
from
AllPeople
group by
commonDate
having
count(*) > 1 ) BornOnSameDay
JOIN
AllPeople Who
on BornOnSameDay.commonDate = Who.commonDate
order by
BornOnSameDay.commonDate,
who.PersonName
Now, you also provided a class table of which teachers were teaching what class, and if a student was in a particular class. If your intention was to find out which classes has a student with the same birthdate as the professor teaching it, that would be a different query.
Please advise on which you meant. The one I have provided is ANY teacher having a same birthday as ANY other teacher OR student. And likewise could be two students having the same birth date.
You can use the GROUP_CONCAT function:
SELECT date_format(birthdate,"%d %b") AS birthday, GROUP_CONCAT(person_name) AS people
FROM persons
GROUP BY MONTH(birthdate), DATE(birthdate)

How to improve performance on SUM from float values in MySQL?

I am trying to optimize a query (on MySQL 5.7) that takes about 1s to execute on 3M rows. The desired result is a SUM of float values per day within the last 30days:
Query:
SELECT
DATE,
SUM(RIX) as value
FROM
tbl1 v
JOIN tbl2 b ON v.BRAND_ID = b.ID and b.MANUFACTURER_ID = 18670
WHERE
DATE BETWEEN FROM_UNIXTIME(1613663944) AND FROM_UNIXTIME(1616255944)
AND type = 'kwd'
group by v.DATE
Tbl1 (10K rows):
create table tbl1
(
ID mediumint unsigned auto_increment
primary key,
ID_parent mediumint unsigned null,
MANUFACTURER_ID mediumint unsigned not null,
BRAND varchar(255) null,
CREATED date null,
constraint test
unique (MANUFACTURER_ID, BRAND),
);
create index idx2
on tbl1 (ID_parent);
create index idx3
on tbl1 (MANUFACTURER_ID);
create index idx4
on tbl1 (BRAND);
Tbl2 (3M rows:
create table tbl2
(
DATE date not null,
MERCHANT_ID mediumint unsigned not null,
TYPE enum ('cat', 'kwd', 'css') not null,
BRAND_ID mediumint unsigned not null,
RIX float unsigned not null,
primary key (DATE, TYPE, MERCHANT_ID, BRAND_ID)
)
create index idx1
on tbl2 (RIX);
I could not get it to perform faster. Any ideas on how to improve the query time?
primary key (DATE, TYPE, MERCHANT_ID, BRAND_ID)
Try rearranging it to
primary key (TYPE, DATE, MERCHANT_ID, BRAND_ID)
That would make this more efficient:
WHERE type = ...
AND date BETWEEN ...
tbl1 has an index starting with MANUFACTURER_ID; don't add another index on just MANUFACTURER_ID.
(Please qualify each column with the table alias, it is hard to read the query. While you are at it, fix v.BRAND_ID and others!!)

View with derived value column

I'm having some trouble trying to make a view with a calculated average column, for every movie row I need an average rating based on all the ratings for this movie in the rating table.
Movie table:
CREATE TABLE IF NOT EXISTS streaming_db.movie(
id BIGINT NOT NULL auto_increment
,name VARCHAR (100)
,description VARCHAR (1000)
,PRIMARY KEY (id)
) engine = InnoDB;
Rating table:
CREATE TABLE IF NOT EXISTS streaming_db.rating(
id BIGINT NOT NULL auto_increment
,rating_score DECIMAL(4, 2) NOT NULL
,comment VARCHAR (255) NULL
,id_profile BIGINT NOT NULL
,id_movie BIGINT NOT NULL
,PRIMARY KEY (id)
) engine = InnoDB;
Here's what I have so far:
CREATE VIEW streaming_db.midia
AS
SELECT name,
description
FROM streaming_db.movie a
INNER JOIN (SELECT avg(rating_score) AS averageRating from streaming_db.rating where
rating.id_movie = a.id);
It was telling me that a derived table needs its own alias, and I don't know if that really gives me the average per row.
You are attempting a correlated subquery in the FROM clause. Well, this is actually a real thing, called a lateral join.
But that is not your intention. Move the logic to the SELECT:
SELECT m.name, m.description,
(SELECT avg(rating_score)
FROM sistema_streaming_db.rating r
WHERE r.id_movie = m.id
) as averageRating
FROM streaming_db.movie m;
Note that I fixed the table aliases so they are abbreviations for the table names, which makes the query much easier to read.

MySQL BEFORE INSERT TRIGGER is not affecting first record entry

I am trying to calculate the differential column of the score table upon inserting into a MySQL 8.0 database using a before trigger. The calculation uses the coursetee table as well. The trigger works fine on all but the first record in the table, which doesn't get updated. Is there something that I am missing? All relevant code is below.
CREATE TABLE coursetee (
teeID INT UNSIGNED AUTO_INCREMENT,
tee_name VARCHAR(20) NOT NULL,
course_rating DECIMAL(3,1) NOT NULL,
slope_rating INT UNSIGNED NOT NULL,
par INT UNSIGNED,
CONSTRAINT pk_coursetee PRIMARY KEY (teeID),
CREATE TABLE score (
roundID INT UNSIGNED AUTO_INCREMENT,
teeID INT UNSIGNED,
round_score INT UNSIGNED NOT NULL,
round_date DATETIME NOT NULL,
entry_date DATETIME DEFAULT NOW() NOT NULL,
differential DECIMAL(3,1),
CONSTRAINT pk_score PRIMARY KEY (roundID),
CONSTRAINT fk_score_coursetee FOREIGN KEY (teeID) REFERENCES coursetee(teeID));
DELIMITER $$
CREATE TRIGGER calculate_differential
BEFORE INSERT ON score
FOR EACH ROW
BEGIN
SET NEW.differential = (SELECT ROUND((113/ct.slope_rating)*(NEW.round_score-ct.course_rating),1)
FROM score, coursetee as ct
WHERE NEW.teeID = ct.teeID AND differential IS NULL);
END$$
DELIMITER ;
INSERT INTO coursetee
(courseID,tee_name,course_rating,slope_rating,par)
VALUES
(1,'Back',74.7,143,72),
(1,'Middle',72.6,136,72),
(1,'Front',71.3,132,72),
(2,'Back',76.8,155,72),
(2,'Middle',73.9,146,72),
(2,'Front',65.3,125,72);
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(1,2,79,'2019-07-25');
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(2,2,80,'2019-07-25');
INSERT INTO score
(playerID,teeID,round_score,round_date)
VALUES
(1,2,77,'2019-08-06');
The query returns:
image of query not returning calculated record for row 1
CREATE TRIGGER calculate_differential
BEFORE INSERT
ON score
FOR EACH ROW
SET NEW.differential = ( SELECT ROUND((113/ct.slope_rating)*(NEW.round_score-ct.course_rating),1)
FROM coursetee ct
WHERE NEW.teeID = ct.teeID);
fiddle
The problem was in using score table as a source of the subquery. And the hope that differential BEFORE inserting the first record will give anything except NOT FOUND. And testing the field of the record BEFORE INSERT for NULL makes no sense.
My assumption is about the FROM clause of the differential query in the trigger. i'd suggest you to try change the order of the tables -
FROM score, coursetee as ct
to
FROM coursetee as ct, score
Seems like its trying to extract nothing for the first insert...

SQL - result of Stored Procedures

I have two tables and A and B and i have a third table with result of join A and B,i use mariadb database, i want to store result in the third table result_A_B but I have this message when i run "CALL session_cpu_procedure()": ERROR 1136 (21S01): Column count doesn't match value count at row 1
CREATE TABLE result_A_B (
ID INT UNSIGNED NOT NULL AUTO_INCREMENT,
cid nvarchar(100) NOT NULL,
time datetime NOT NULL,
OS nvarchar(100) NOT NULL,
program nvarchar(100) NOT NULL,
nb_OS_by_program FLOAT NOT NULL,
cpu FLOAT,
last_line int NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY (`cid`,`time`,`program`) ) ENGINE=InnoDB;
DELIMITER |
CREATE PROCEDURE session_cpu_procedure()
BEGIN
TRUNCATE result_session_cpu_CPLSVFX201P;
INSERT INTO result_session_cpu_CPLSVFX201P
SELECT DISTINCT C.cid, C.time, C.OS, C.program, COUNT(*) as nb_OS_by_program, O.cpu, C.last_line
FROM session_test C LEFT outer JOIN cpu_test O ON O.sid2 = C.cid and O.time = C.time and C.PROGRAM=O.MODULE
where C.time
GROUP BY C.time, C.OS, C.program, C.last_line;
END |
DELIMITER ;
CALL session_cpu_procedure();
I want to know how to resolve this error: ERROR 1136 (21S01): Column count doesn't match value count at row 1, thanks for any response
You have a table with 8 columns.
Your SELECT... INSERT statement has 7 columns.
This generated the rather self explanatory error.
Option 1:
Since you have a UNIQUE key already, make this the primary key and remove the AUTO_INCREMENT column.
Option 2:
Be explicit in your INSERT SELECT about the columns omitting the auto_increment column:
INSERT INTO result_session_cpu_CPLSVFX201P
(cid, time, OS, program, nb_OS_by_program, CPU, lastline)
SELECT ....