I'm practicing SQL with given results using MySQL Sakila database.
Here's one of the problems I'm struggling with now.
How many films are out on rent?
Correct Result: 183
I'm inner joining inventory,film, and rental tables for this.
In inventory table, I have inventory_id, film_id, store_id, and last_update
In film table, I havefilm_id, title, description, release_year, language_id, original_language_id, rental_duration, rental_rate, length, replacement_cost, rating, special_features, last_update
And for rental table, I have rental_id, rental_date, inventory_id, customer_id, return_date, staff_id, last_update
And here's my SQL statement
SELECT
inv.film_id, COUNT(f.title) as numOfDVDsOnRent
FROM
rental AS r
INNER JOIN
inventory AS inv ON r.inventory_id = inv.inventory_id
inner join film as f on inv.film_id=f.film_id
What I've got for the result so far was rows of total number of DVDs out on rent for each film...Something like this:
So, how can I get the correct result?
Please try the following...
SELECT COUNT( inventory_id ) as numOfDVDsOnRent
FROM rental
WHERE return_date IS NULL;
All the information to determine how many films are out on rent is included in rental. We do not need to refer to the details about each film or about each item of inventory to determine this, so I have dumped the INNER JOINs. Note : Where JOIN is not preceeded by a join type, an INNER JOIN is performed, so you can just type JOIN if you wish.
Thus all we need to do is count all the entries in rental where the entry has not been returned date.
If you have any questions or comments, then please feel free to post a Comment accordingly.
Related
I want to get the customer who mostly borrowed films of category 3 in 2016, July
SELECT c_firstName, c_lastName, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID HAVING rental.c_ID=MAX((SELECT COUNT(rental.c_ID)
FROM customer, copies, rentalprocess, rental, film
WHERE customer.c_ID=rental.c_ID AND rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%" GROUP BY rental.c_ID))
But ir doesn't work because it said that the subquery returns more than one row
What can I do?
Max() is an aggregate function that needs to be in a select statement
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM customer, copies, rentalprocess, rental, film
WHERE
customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)
In this case the sub-select returns multiple rows but then you take the max value of that query
Comment from Mr Linoff is correct, you should use explicity joins:
SELECT
c_firstName
, c_lastName
, rental.c_ID
FROM customer, rental
GROUP BY rental.c_ID
HAVING rental.c_ID=
(
select
MAX(i.iID)
from
(
SELECT
COUNT(rental.c_ID) iID
FROM
customer
inner join rental
on customer.c_ID=rental.c_ID
inner join rentalprocess
on rentalprocess.r_ID=rental.r_ID
inner join copies
on rentalprocess.s_ID=copies.s_ID
inner join film on film.f_ID=copies.f_ID
WHERE
f_category=3
AND r_date LIKE "2016-07%"
GROUP BY rental.c_ID
) i
)
your code should look something like this, join the tables properly in the code.
I dont know wich columns and table would suit best for the solution becuse I dont got your full schema. but this should give faster query. Put more columns in the select if you wish.
select c_firstName | ' ' | c_lastName, count(rental.c_ID) as rentalCustomer
from customer
inner join rental
on join " connect the both tables"
innner join rentalprocess
on "connect rental with rentalprocess"
inner join copies
on " connect rentalprocess with copies"
inner join film
on "connect copies with film"
WHERE customer.c_ID=rental.c_ID AND
rentalprocess.r_ID=rental.r_ID AND
rentalprocess.s_ID=copies.s_ID AND
film.f_ID=copies.f_ID AND
f_category=3 AND r_date LIKE "2016-07%"
group by c_firstName, c_lastName, rental.c_ID
order by rental.c_ID desc;
I am working on a theatre booking system in MySql (My first SQL project). I have three tables:
Production (contains Title, BasicTicketPrice),
Performance (PerformanceDate, PerformanceTime, Title)
Booking (Email of person who booked, PerformanceDate, PerformanceTime, RowNumber).
Each person booked tickets for two or three performances (using their email to book).
I need to to write a query which will display the prices paid for all booked seats and I need to output the RowNumber, Email of person who booked and the Calculated Price.
I understand that I need to join these tables and make the query display a temporary column called Calculated Price but I don't know how to calculate the price.
I tried this:
SELECT DISTINCT b.RowNumber, b.Email, pr.BasicTicketPrice
FROM booking b, production pr performance p
WHERE p.Title=b.PerfDate*b.PerfTime*b.RowNumber;
SELECT CONCAT (PerfDate, PerfTime, RowNumber) AS BookingID FROM booking;
SELECT RowNumber, Email, CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID FROM booking;
SELECT RowNumber, Email, CONCAT((CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID
FROM booking)BasicTicketPrice*BookingID);
SELECT RowNumber, Email, CONCAT(PerfDate, PerfTime, RowNumber) AS BookingID INTEGER
FROM booking;
SELECT RowNumber FROM booking
LEFT JOIN (SELECT Title FROM performance WHERE '2017-11-01 19:00:00' Email IS NULL);
But it didn't work.
Any suggestions? I will be grateful for any ideas.
Assuming:
One row in Bookings per booked seat
Title to be a suitable primary key for Production
PerformanceDate, PerformanceTime to be a suitable primary composite key for Performance
You'll be looking to join the three tables together as per the keys assumed above. It seems you wish to group the bookings together per performance, by the person booking the tickets - if so, you'll need to use an aggregate to show the seat numbers (I've used GROUP_CONCAT to delimit them), as well as to COUNT the tickets purchased and multiply by the ticket cost.
SELECT
b.Email, prod.Title, per.PerformanceDate, per.PerformanceTime,
GROUP_CONCAT(RowNumber) AS BookedSeats,
COUNT(RowNumber) * prod.BasicTicketPrice AS TotalCost
FROM Booking b
INNER JOIN Performance per
ON b.PerformanceDate = per.PerformanceDate
AND b.PerformanceTime = per.PerformanceTime
INNER JOIN Production prod
ON per.Title = prod.Title
GROUP BY
b.Email, prod.Title, per.PerformanceDate, per.PerformanceTime, prod.BasicTicketPrice
ORDER BY prod.Title, per.PerformanceDate, per.PerformanceTime;
Technically, we should include all non-aggregated columns in the GROUP BY, hence prod.BasicTicketPrice is listed as well.
I have three tables: households, voters, door_knocks
Each household can have several voters associated with it. Each household can also have several door knocks associated with it.
I'm trying to pull together all the voters in a household and the date of the last door_knock from the door_knocks table and I'm having trouble figuring out the proper query syntax. Here is my latest attempt:
SELECT households.hh_id, voters.id
FROM households
INNER JOIN voters ON households.hh_id = voters.hh_id
INNER JOIN ( SELECT MAX(dk.date), dk.hh_id FROM door_knocks dk GROUP BY dk.date) dks
ON dks.hh_id = households.hh_id
WHERE households.street = ?
The above query pulls up one result for each door knock, however. I just want the the date from the last door knock.
So, what it sounds like you're hoping for conceptually is a table that lists the last date of a knock for each houshold.
You'd like to join against that table and combine it with the voters and the households.
what your query does is give you a table of all the dates (group by dk.date) and for each date list all the households.
If you group by hh_id instead, then you will get the max date for each given household.
SELECT households.hh_id, voters.id, dks.max_date
FROM households
INNER JOIN voters ON households.hh_id = voters.hh_id
INNER JOIN ( SELECT MAX(dk.date) as max_date, dk.hh_id FROM door_knocks dk GROUP BY dk.hh_id dks
ON dks.hh_id = households.hh_id
WHERE households.street = ?
I’ve got 5 Tables:
Patients Table 'PAT'
Patient Orders 'ORD'
Patient Comments 'Comm'
Patient Antigens 'Ant'
Patient MRNs 'MRN'
Information in the following four tables:
Pat has all of our patients information
Ord only has orders from the last four years, joined to the Pat table on Patient ID
Comm has all patient comments, joined on the Pat table on Patient ID
Ant has all antigens entered on patients, joined on the Pat table on Patient ID
MRN has all medical record numbers of patients, joined on the Pat table on Patient ID
What I’m trying to do it make sure I have all patients that appear in the Ord, Comm, Ant, and MRN tables and the join it to the Pat table to get information like first name, last name, sex, DOB...
So I’m trying to figure out how best to join these tables together to make sure I don’t include patients that don’t appear in the Ord, Comm, Ant, or MRN tables.
If I join the tables to my main patient table with left outer joins, I'll get all patients regardless if they have an order, comment, antigen, or MRN.
Select * from Pat
Left Outer Join Ord on Pat.X=Ord.X
Left Outer Join Comm on Pat.X=Comm.X
Left Outer Join Ant on Pat.X=Ant.X
Left Outer Join MRN on Pat.X=MRN.X
I've attempted to make a visual diagram of what I'm looking for:
My ideal query would return all Patients except for 4 and 10 because they do not have any orders, antigens, comments, or a MRN.
I was thinking I could perform FULL OUTER JOINS on the ORD, ANT, COMM, and MRN tables and then take those results and and join it to the PAT table.
Select *
FROM P50DATA.AGABFL1 ANT
FULL OUTER JOIN P50DATA.ORDMSTL1 ORD ON ANT.AGACCT=ORD.OPACCT
FULL OUTER JOIN P50DATA.DCMTRNL5 COMM ON ANT.AGACCT=COMM.DCACCT
FULL OUTER JOIN P50DATA.HOSPIDL1 HOS ON ANT.AGACCT=HOS.APACCT
But I don't know how to then take this data set and marry it to the Pat table so I could then get my patient information.
Thoughts?
This doesn't have to be too complicated.
ORD, ANT, COMM, and MRN don't have to join to each other, because you don't need the records in any one of them to match any other one. You just need to know whether they have records for a given patient or not.
There are many ways to construct such a query; here's one:
SELECT *
FROM PAT
WHERE EXISTS (
SELECT 1
FROM ORD
WHERE ORD.X = PAT.X
)
OR EXISTS (
SELECT 1
FROM ANT
WHERE ANT.X = PAT.X
)
OR EXISTS (
SELECT 1
FROM COMM
WHERE COMM.X = PAT.X
)
OR EXISTS (
SELECT 1
FROM MRN
WHERE MRN.X = PAT.X
)
Because you are querying the Patient table without joining it to anything, you don't have to worry about duplicate records, and because you're just checking existence for ORD, ANT, COMM, and MRN, you don't have to worry about exactly how many records each of them has for a given patient.
I have three tables: loans, reservations and books. The books table has an attribute for "noOfCopies", and the total number of loans and reservations for that book can not exceed that figure.
The reservations table has a "timestamp" column which is just the timestamp that the reservation was made. The idea is that when a book is returned, the earliest reservation gets the book next.
Here is what I need help with: I need to create an SQL view that will show all the earliest reservations for each book, but only where that book is available.
Can anyone give me the SQL for this? Thanks in advance.
Here is the SQL I already had: I thought it showed all the reservations where the books were available and was about to move on to figuring out how to show the earliest - but then I got nowhere with earliest and then realised that this doesn't actually work anyway:
CREATE VIEW `view_bookLoans` AS
SELECT count(l.`id`) as loanCount, l.`bookISBN`,b.`noOfCopies` FROM
loans l INNER JOIN books b
ON l.`bookISBN` = b.`ISBN`
GROUP BY l.`bookISBN`;
CREATE VIEW `view_reservationList` AS
SELECT
r.`timestamp`,
b.`title` as `bookTitle`,
r.`readerID`,
bl.`loanCount`
FROM
`reservations` r INNER JOIN `books` b
ON r.`bookISBN` = b.`ISBN`
LEFT JOIN
view_bookLoans bl
ON bl.`bookISBN` = b.`ISBN`
WHERE
(b.`noOfCopies` - bl.`loanCount`) > 0;
With exception to the comments I put in the question about how to exclude reservations already filled, or loans already returned... This SHOULD do it for you.
I would start the list by only looking at those books that people have reserved. Why query and entire list of books where nobody is interested in them... THEN, expand your criteria. The inner query starts directly with the books on the reservations list. That is LEFT JOINED to the loans table (in case there are none remaining on loan). I'm extracting the ealiest time stamp for the reservation per book, and also getting the total count of LOAN book entries grouped by ISBN.
From that result, I immediately re-join to the reservations to match based on the ISBN and timestamp of the earliest to get the WHO wanted it.
Now the finale... JOIN (not a LEFT JOIN) to the books table on both the ISBN AND your qualifier that the number of copies available... less how many are already loaned out is > 0.
You can obviously add an order by clause however you want.
ENSURE that you have an index on the reservations table on (bookISBN, timestamp) for query optimization. Also, the loans table too should have an index on ISBN.
SELECT
B.Title,
R2.readerID,
R2.timeStamp,
Wanted.AlreadyLoandedOut,
B.noOfCopies - Wanted.AlreadyLoanedOut as ShouldBeAvailable
FROM
( select
R.bookISBN,
MIN( R.timeStamp ) EarliestReservation,
COALESCE( COUNT( L.ID ), 0 ) as AlreadyLoanedOut
from
reservations R
LEFT JOIN Loans L
ON R.bookISBN = L.bookISBN
group by
R.bookISBN ) as Wanted
JOIN reservations R2
ON Wanted.bookISBN = R2.bookISBN
AND Wanted.EarliestReservation = R2.timeStamp
JOIN books B
ON Wanted.bookISBN = B.ISBN
AND B.noOfCopies - Wanted.AlreadyLoanedOut > 0