Comparing Dates For Multiple Entries - mysql

im creating a small hire car system and i want a stored procedure that takes in a date and checks to see which cars are available then. I've got the compare working but if a car has more than one contract and one of the contracts isn't for the entered date but another is it says the car is available. Below is my procedure so far
delimiter //
create procedure allAvailableVehicles(req varchar(15))
BEGIN
select distinct vehicles.vehicleID as "Vehicle ID", vehicles.Make as "Make", vehicles.Model as "Model" from vehicles
left outer join contracts
on vehicles.vehicleID=contracts.vehicleID
where cast(req as date) not between hiredFrom and hiredUntill
or contractID is unknown
order by vehicles.vehicleID;
end
//
delimiter ;

This is a good opportunity to use not exists:
select v.*
from vehicles v
where not exists (select 1
from contracts c
where c.VehicleId = v.VehicleId and
cast(req as date) between hiredFrom and hiredUntil
);
Note: you should not need to cast req as a date, because it should already be stored as a date in the database (unless req also has a time component).
A better way to write the stored procedure is:
delimiter //
create procedure allAvailableVehicles(p_req date)
begin
select v.*
from vehicles v
where not exists (select 1
from contracts c
where c.VehicleId = v.VehicleId and
p_req between hiredFrom and hiredUntil
);
end //
delimiter ;
Use built-in types for date/times. Also, name your parameters to distinguish them from columns.

Related

Creating a stored procedure with a select count

I am very new to creating procedures, looking for some guidance on my code. I cant figure out how to output the number of students being mentored. I am trying to output the following statement: Create a stored procedure called MentoringCount which will display the professor name and the number of students he/she is mentoring. Sort the output by the professor name.
delimiter //
create procedure MentoringCount()
Begin
SELECT p.ProfessorName from professor p
join lab10.student_professor SP
on (S.studentno = SP.studentno)
where SP.mentored = 1
SELECT COUNT (Mentor)
FROM student_professor
order by p.ProfessorName;
END //
Delimiter ;
call mentoredStudents();
student table:
studentno
studentprogram
phoneno
age
firstname
lastname
professor table:
ProfessorId
ProfessorProgram
PhoneNo
Age
ProfessorName
student_professor table:
student_professor_id
ProfessorId
StudentNo
Mentor
There's no difference between doing this query in a stored procedure and normally.
You just need to join the tables and use COUNT(*) along with GROUP BY. Use LEFT JOIN so you'll get zero counts.
delimiter //
CREATE PROCEDURE MentoringCount()
BEGIN
SELECT p.professorName, IFNULL(COUNT(sp.student_professor_id), 0) AS students
FROM professor AS p
LEFT JOIN student_professor AS sp
ON sp.professorID = p.professorID AND sp.Mentored = 1
GROUP BY p.professorID
ORDER BY p.professorName
END;
//

How to reverse the results of this procedure?

I am tring to create a simple database for a hotel. It is supposed to take care of all bookings. I am tring to make a procedure which will search for not booked rooms in given date. However, as for now my procedure can show room numbers which already have been booked at some point. Only first 5 of 20 rooms were booked so far, and they appear, the other do not.
Can anyone give me any ideas what is wrong or even better, how to make the whole procedure work?
These are the important tables
This is the call:
The results should go all the way up to "NumerPokoju" = 20, but they stop, because they are not in the Bookings table
To clarify the question: I want the procedure to show also the rooms that simple were never booked, not only the ones that have been at least once.
DELIMITER //
CREATE PROCEDURE freeRooms(IN ilosc int, IN poczatek date, IN koniec date)
BEGIN
SELECT Rooms.RoomID AS "Numer pokoju", Rooms.Places AS "Ilosc lozek"
FROM Rooms INNER JOIN Bookings ON Rooms.RoomID = Bookings.RoomID
WHERE ((poczatek < Bookings.ArrDate AND koniec < Bookings.ArrDate) OR ((poczatek > Bookings.DepDate) AND (koniec > Bookings.DepDate)))
AND ilosc <= Rooms.Places;
END //
DELIMITER ;
Use NOT EXISTS instead of the join:
SELECT
r.RoomID AS "Numer pokoju",
r.Places AS "Ilosc lozek"
FROM Rooms r
WHERE
NOT EXISTS (
SELECT 1 FROM Bookings
WHERE
RoomID = r.RoomID
AND (
poczatek BEWEEN ArrDate AND DepDate
OR
koniec BEWEEN ArrDate AND DepDate
)
)
AND
ilosc <= r.Places;
I'm not sure about the last condition: ilosc <= r.Places if and why you need it.

MariaDB/MySQL Function Select into returns more than one row, 3 variables

I am currently studying SQL and we're using MariaDB and Toad for MySQL as our graphic editor. Currently, we have to create a function that returns 3 different variables.
SELECT ourFunction(c.dni), v.CV, cl.nom_color
INTO #var_age, #var_cv, #var_color
FROM vehicle v
INNER JOIN client c
ON c.dni=v.dni
INNER JOIN color cl
ON v.color=cl.cod_color
We need each variable to give us an exact value so we can use it on another function. The problem is currently that we can't get the results we want on the variable.
Client is 1:N to Vehicle
Vehicle is 1:1 to Color
ourFunction calculates the age of the client. This is what it does:
DELIMITER //
CREATE FUNCTION ourFunction(dni varchar(9))
RETURNS tinyint(3)
BEGIN
select TIMESTAMPDIFF (YEAR, birth_date, CURDATE()) AS age
INTO #age
FROM client c
WHERE c.dni=dni;
RETURN #age;
END //
DELIMITER ;

Updating 180k rows via MySQL stored procedure & function is too slow - how to speed up

I have the following stored procedure:
CREATE DEFINER=`ST`#`%` PROCEDURE `CalculateCheapestPriceALL`()
BEGIN
UPDATE
tickets
SET
tickets.Cheapest = GetCheapestTicket(tickets.STPerformerID, tickets.STVenueID, tickets.FeedID);
END
The function GetCheapestTicket is as follows:
CREATE DEFINER=`suprtickets`#`%` FUNCTION `GetCheapestTicket`(performerID INT(11), venueID INT(11), feedID INT(11)) RETURNS decimal(10,2)
BEGIN
DECLARE TicketPrice DECIMAL(10,2);
SET TicketPrice =
IFNULL((
SELECT
MIN(tickets.Price)
FROM
tickets
WHERE
tickets.STPerformerID = performerID
AND
tickets.STVenueID = venueID
AND
tickets.FeedID = feedID
AND
tickets.Price > 0
),0);
RETURN TicketPrice;
END
Running the stored procedure currently takes about 10 minutes, and I'm looking for ways to speed this up.
The following image shows a sample of the data:
The idea behind the stored procedure is to find the cheapest price for the same STPerformerID and STVenueID, and then update this in the Cheapest column. So then I can quickly look up the lowest price for each peformer and venue.
There are about 20k individual Perfomers, and a similar amount of Venues.
Thanks for your help.
Your basic problem is that you are running the query to find the lowest price over again for every row, which is very inefficient.
If you combine the two queries into one query. it will execute significantly faster:
UPDATE tickets AS t1
JOIN (SELECT STPerformerID, STVenueID, STFeedID, MIN(Price) AS cheapest
FROM tickets
WHERE Price > 0
GROUP BY STPerformerID, STVenueID, STFeedID) AS t2
USING (STPerformerID, STVenueID, STFeedID)
SET t1.Price = t2.cheapest
To make it perform well, make sure you have a composite index on (STPerformerID, STVenueID, STFeedID) (or at least some subset of these columns).

Building an table using procedures

i'm trying to create an procedure that returns an table with some information of my database, it lists the number of the HOTEL by how many clients used each type of their credit cards on the hotel
Keeping in mind that there is more than 50 hotels and 3 types of credit cards, i want the procedure to run through the data and list then in the table
DELIMITER //
DROP PROCEDURE IF EXISTS `testing` //
CREATE PROCEDURE `testing`(OUT param1 VARCHAR(40))
BEGIN
DECLARE id_cnpjEstabelecimento VARCHAR(40);
DECLARE id_redeCartão VARCHAR(255);
SELECT (cnpjEstabelecimento)
FROM fpcsmovatlantica201308tst04;
SET id_cnpjEstabelecimento := cnpjEstabelecimento;
SELECT (id_redeCartão)
FROM fpcsmovatlantica201308tst04;
SET id_redeCartão := id_redeCartão;
SELECT count(*)
FROM fpcsmovatlantica201308tst04;
WHERE redeCartão like 'id_redeCartão%';
AND cnpjEstabelecimento like 'id_cnpjEstabelecimento%';
END //
DELIMITER ;
An example of an select
SELECT count(*)
FROM fpcsmovatlantica201308tst04
WHERE redeCartão like 'Cielo%'
AND cnpjEstabelecimento like '02223966000466%'
the cnpjEstabelecimento got several values, more than 100+, so it's inviable to make all the selects
I don't even have to use procedures to make it, the final result was
SELECT cnpjEstabelecimento, redeCartão, count(*)
FROM fpcsmovatlantica201308tst04
WHERE redeCartão like 'Cielo%'
GROUP BY cnpjEstabelecimento,redeCartão like 'Cielo%'
ORDER BY cnpjEstabelecimento ASC;
I'm assuming you have one table, which looks kind of like this:
|hotelId|cardType|etc...
I'd go with:
Select hotelId, cardType, count(*)
from myTable
group by hotelId, cardType
I tested it here with the following SQL:
SELECT country, city, count(*)
from customers
group by country, city
ORDER BY Country;