MySQL subquery on multiple tables - mysql

I am trying to retrieve names and address of all guests with bookings for a hotel in London, alphabetically ordered by name in MySQL using subqueries and getting this Error:
Error Code: 1242. Subquery returns more than 1 row
Here's the query that I run:
select * from guest
where guest_no =
(
select guest_no
from booking
where hotel_no = (select hotel_no
from hotel
where city = 'London')
);
and here's the schema for hotel, booking and guest:
hotel (hotel_no, hotel_name, city)
booking (hotel_no, guest_no, date_from, date_to, room_no)
guest (guest_no, g_name, g_address)
additionally, here's the schema for room:
room (room_no, hotel_no, type, price)
Please help me with the above mentioned error and possible solutions.
Thanks and regards.

why not use join as
select
g.guest_no,
g.g_name,
g.g_address
from guest g
inner join booking b on b.guest_no = g.guest_no
inner join hotel h on h.hotel_no = b.hotel_no
where h.city = 'London'

When you use '=', it means that the result of your subquery is exactly 1 row. If you expect multiple results, you need to use the IN keyword, like so:
select * from guest where guest_no IN (select guest_no from booking where hotel_no IN (select hotel_no from hotel where city = 'London'));
EDIT: As #flaschenpost mentions, the performance could be degraded in case there is no proper indexing on the columns involved in the subqueries. You would probably do well to use JOIN rather than such nested subqueries.

Change you query to
select * from guest
where guest_no IN
(select guest_no from booking where hotel_no
IN (select hotel_no from hotel where city = 'London'));

you need joins !
try this !
select a.g_name,a.g_address from guest a inner join booking b on a.guest_no=b.guest_number inner join hotel h on b.hotel_no=h.hotel_no inner join rooms r on b.room_no=h.room_no
where h.city='London'

Related

SQL: Deleting something that is used less than two times in an other table

I've got the following tables:
Employee (#PNo, Name, *ANo, Salary)
Department (#ANo, AName)
Hotel (#HNo, HName, HCategory, ZIP, City)
Journey (#*Employee, #*Hotel, #BeginningDate, Duration, Costs)
(#=primary key, *=foreign key)
I want to delete all hotels which have been booked with a maximum of one stay and tried it with
DELETE hotel FROM hotel
INNER JOIN journey ON journey.Hotel = hotel.HNo
WHERE COUNT(journey.Hotel) < 2;
But that doesn't work. All I get is the following error:
"#1111 - Invalid use of group function"
How can I connect the two tables and delete the hotels in the table "hotel" that were not booked more than ones?
ANSI SQL complaint answer:
DELETE hotel FROM hotel
WHERE HNo not in (select Hotel
from journey
group by Hotel
having count(*) >= 2)
The sub-query will return Hotels that exist more than once in the journey table.
Use LEFT JOIN to join hotel with journey and count any column from journey table. This will return hotels + journey count, including hotels with zero journeys.
DELETE FROM hotel
WHERE HNo IN (SELECT * FROM (
SELECT hotel.HNo
FROM hotel
LEFT JOIN journey ON hotel.HNo = journey.Hotel
GROUP BY hotel.HNo
HAVING COUNT(journey.Hotel) < 2
) AS foobar)
The sub-sub-query trick is described here.
Try this
DELETE FROM hotel
WHERE HNo IN (SELECT hotel.HNo
FROM hotel
JOIN journey on (journey.hotel = hotel.HNo)
GROUP BY hotel.HNo
HAVING count(hotel.HNo) < 2)
DELETE FROM hotel WHERE secnum IN (SELECT secnum FROM journey GROUP BY secnum HAVING COUNT(*) > 2 )

How to filter the output based on the output of count in MySQL?

Tables in my database: 1. Employee
2.Aircraft
3.Certified
Query: I need to find pilot name, eid, aircraft name, cruising_range where pilot is certified to fly more than 3 aircraft's . i wrote a query and it works but i want to know if there is a simple way to achieve this because my query seems much complicated .
My query is :
Edit: Corrected the name of tables.
If you can assume that each AID in Certified had a corresponding value on Aircraft, then it can be done like this:
SELECT ename,employee.eid,aname,crusing_range
FROM employee JOIN certified
ON employee.eid = certified.eid
JOIN aircraft
ON certified.aid = aircraft.aid
WHERE exists(select 1 FROM certified t
WHERE t.eid = employee.eid
GROUP BY t.eid HAVING COUNT(*) >= 3)
Ahh man, don't prefix your columns with your table names. Just have employee ID column as id not eid
I would try this:
SELECT <columns>
FROM aircraft A
LEFT JOIN employee E ON E.eid = A.eid
LEFT JOIN certified C ON C.aid = A.aid
Where SUM(A.eid) > 3
I'm on mobile but I hope it helps.
The key information is in the Aircraft table so start with that and then join the tables you want the extra bits from. Chucking a distinct on employee id within the SELECT will stop duplicates too.
Rethink table names too.

SQL Query incorrect

I'm doing some past question papers and came across the following:
A company uses the following database:
customers - CustNo, CustName, CustAddress
Reservations - CustNo, TourID
Tours - TourID, Destination, Date, Time, Price
From these tables I have to create an SQL statement for finding the customer numbers of passengers who are booked on both any tour to London and also any tour to Edinburgh...
The attempt is this:
SELECT
R.custNo
FROM
Reservations R, Tours T
WHERE
T.tourID = R.tourID
AND T.destination = 'London'
AND T.destination = 'Edinburgh';
I have been told this is not correct and to find an alternative, correct, SQL statement. So if anyone can help me out with this question it'd be great.
You can try the following:
select R.custNo
from Reservations R
join Tours T on T.tourID = R.tourID
where T.destination in ('London', 'Edinburgh')
group by R.custNo
having count(distinct T.destination) = 2
This will look for customers that have 'London' or 'Edinburgh' destinations and retrieve only those, that have both.
SELECT R1.custNo
FROM Reservations R1 inner join Tours T1 on T1.tourID = R1.tourID
WHERE T1.destination = 'London'
INTERSECT
SELECT R2.custNo
FROM Reservations R2 inner join Tours T2 on T2.tourID = R2.tourID
WHERE T2.destination = 'Edinburgh'
ps: this will work only on sql server DBMS

Can't solve this sql statement to archive my real goal

SELECT hotel.hotel_id, hotel.hotel_name, hotel.hotel_address, hotel.hotel_pic,
room_accommodation.room_full_price
FROM hotel
INNER JOIN room_accommodation ON (room_accommodation.hotel_id = hotel.hotel_id )
INNER JOIN (
SELECT MIN( room_full_price ) AS minPrice
FROM room_accommodation INNER JOIN hotel ON (
hotel.hotel_id =room_accommodation.hotel_id )
WHERE hotel.hotel_address LIKE '%bangkok%'
)room_accommodation ON room_accommodation.room_full_price = room_accommodation.minPrice
This SQL can query each hotel that are in bangkok with a lowest rate of each hotel
But the problem is now I want to query all lowest rate of each hotel but when I cut
the condition where out the result just gave me only one lowest price of all hotel
what wrong and what should I do to archive this
Please Advice
Thank in advance.
This can be greatly simplified - there's no need for a subquery based on the results you need:
SELECT hotel.hotel_id,
hotel.hotel_name,
hotel.hotel_address,
hotel.hotel_pic,
MIN(room_accommodation.room_full_price) as room_full_price
FROM hotel
INNER JOIN room_accommodation
ON room_accommodation.hotel_id = hotel.hotel_id
AND hotel.hotel_address LIKE '%bangkok%'
GROUP BY hotel.hotel_id
Note that for other DBMS's you would need to specify each non-aggregate field in the GROUP BY clause. MySQL lets you get away without that - for better or worse.
i guess u are giving wrong alias to to ur inner query [room_accommodation]
ur query shows that u also have a table with name room_accommodation
SELECT hotel.hotel_id, hotel.hotel_name, hotel.hotel_address, hotel.hotel_pic,
room_accommodation.room_full_price
FROM hotel
INNER JOIN ***room_accommodation*** ON (room_accommodation.hotel_id = hotel.hotel_id )
INNER JOIN (
SELECT MIN( room_full_price ) AS minPrice
FROM room_accommodation INNER JOIN hotel ON (
hotel.hotel_id =room_accommodation.hotel_id )
WHERE hotel.hotel_address LIKE '%bangkok%'
)***room_accommodation*** ON room_accommodation.room_full_price = room_accommodation.minPrice

How to write this SQL query in JPQL

I'm looking to convert the following SQL into JPQL:
SELECT *
FROM rooms
WHERE NOT EXISTS
(
SELECT *
FROM booking, booking_has_rooms
WHERE rooms.number=booking_has_rooms.rooms_number AND
booking.booking_id=booking_has_rooms.booking_booking_id AND
:date BETWEEN booking.checkin AND booking.checkout
);
So far I have this:
SELECT rooms
FROM Rooms rooms
WHERE NOT EXISTS
(
SELECT bk
FROM Booking b
JOIN b.roomsCollection bk
WHERE :date BETWEEN b.checkin AND b.checkout
)
It returns all the rooms correctly if no bookings are on the specified date.
However if any bookings are on the specified date - it does not return any rooms at all.
You're missing a clause in the inner query:
SELECT rooms
FROM Rooms rooms
WHERE NOT EXISTS
(
SELECT bk
FROM Booking b
JOIN b.roomsCollection bk
WHERE :date BETWEEN b.checkin AND b.checkout
and bk.id = rooms.id
)
Your code would be much clearer if you renamed Rooms to Room. Each instance is a single room, so it should use the singular form.