1

I have 3 table Room, Hotel, City, how can i select ten cheapest room and its hotel_id for each city possible to execute the subquery for each city?

SELECT price, room_id, hotel_id, city_id
    FROM Hotel 
    JOIN  Room USING(hotel_id)
ORDER BY price
LIMIT 10


Scheme
CREATE TABLE `City` (
  `city_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_name` varchar(50) NOT NULL,
  PRIMARY KEY (`city_id`)
) 

CREATE TABLE `Hotel` (
  `hotel_id` int(11) NOT NULL AUTO_INCREMENT,
  `city_id` int(11) NOT NULL,
  `hotel_name` varchar(100) NOT NULL,
   PRIMARY KEY (`hotel_id`),
   CONSTRAINT `Hotel_FK_1` FOREIGN KEY (`city_id`) REFERENCES `City` (`city_id`) ON DELETE CASCADE ON UPDATE CASCADE
)

CREATE TABLE `Room` (
  `room_id` int(11) NOT NULL AUTO_INCREMENT,
  `hotel_id` int(11) NOT NULL,
  `room_name` varchar(255) DEFAULT NULL,
  `room_price1` int(11) DEFAULT NULL,
  PRIMARY KEY (`room_id`),
  CONSTRAINT `Room_FK_1` FOREIGN KEY (`hotel_id`) REFERENCES `Hotel` (`hotel_id`) ON DELETE CASCADE ON UPDATE CASCADE
)

query with subquery

SELECT 
     r.room_price1, r.room_id, h.hotel_name, c.city_name
FROM Hotel h 
INNER JOIN Room r ON
    h.hotel_id = r.hotel_id
INNER JOIN City c USING(city_id)
WHERE (
   SELECT count(*) from Room as rt
   JOIN Hotel ht using(hotel_id)
   where c.city_id = ht.city_id and rt.room_price1 < r.room_price1 OR (rt.room_price1 = r.room_price1 AND rt.room_id < r.room_id)
) < 3 
ORDER BY c.city_name, h.hotel_id, r.room_price1

if some hotels have some room_price1 this query return more then 3 row for city and i need 3 unique hotel per city this query can return 3 room from one hotel

ill try use user vars

set @num := 0, @type := '';
select *
from (
   select r.room_price1 pr, r.room_id, h.hotel_name, c.city_name,
      @num := if(@type = city_id, @num + 1, 1) as row_number,
      @type := city_id as dummy
  from Hotel h
  JOIN Room r USING(hotel_id)
  INNER JOIN City c USING(city_id)
  order by city_name, r.room_price1 asc
) as x where x.row_number <=3;

this method return wrong sort for row_number < 6 (my init data)

eugenes
  • 25
  • 1
  • 7
  • maybe you can describe the schema for _hotel_ _room_ and _City_? – gideon Apr 13 '11 at 15:31
  • Is this actually homework as Kynth has assumed? That will affect my answer as the best way of doing it in MySQL is to use user variables but homework probably wants you to use a sub query. – Martin Smith Apr 13 '11 at 15:33

2 Answers2

2

there a ton of different blog post about this topic out there.

The most valuable for me, possibly was

Xaprb post (see section "Select the top N rows from each group" for a detailed explaination)

http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/

In your case that would mean. Modelling this SQL to your needs.

select type, variety, price
from fruits
where (
   select count(*) from fruits as f
   where f.type = fruits.type and f.price < fruits.price
) <= 2;

lets try it out

SELECT 
   r.price, r.room_id, h.hotel_id, h.city_id
FROM Hotel h INNER JOIN Room r ON
  h.hotel_id = r.hotel_id
WHERE (
   select count(*) from Room as rt
   where r.hotel_id = rt.hotel_id and r.price > rt.price
) <= 10;
ORDER BY h.city_id,h.hotel_id,r.price

as you can see you make an subquery to select the count of all rooms that have a price that is lower than the current root and see if the count is less than or equal to 10.

Observe in particular how i changed the

f.price < fruits.price

to

r.price > rt.price

because in the example of Xaprb he selects the N cheapest fruits

Hope that helps.

BTW Stackoverflow isn't for solving homework. You should learn something your self as well ;-)

Jeremy S.
  • 6,423
  • 13
  • 48
  • 67
  • It's ok to ask about homework: http://meta.stackexchange.com/questions/10811/how-to-ask-and-answer-homework-questions – Kynth Apr 14 '11 at 08:49
  • +1 for working through a solution using a similar problem to demonstrate the technique. – Kynth Apr 14 '11 at 08:53
  • try using query from post http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ by can't adapt it in semle above if tow or more fruit have some price, number of result row not equal 3, increases in the number of price matches – eugenes Apr 14 '11 at 10:00
  • sample with mysql user vars not sorting result correctly. `set @num := 0, @type := ''; select * from ( select r.room_price1 pr, r.room_id, h.hotel_name, c.city_name, @num := if(@type = city_id, @num + 1, 1) as row_number, @type := city_id as dummy from Hotel h JOIN Room r USING(hotel_id) INNER JOIN City c USING(city_id) order by city_name, r.room_price1 asc ) as x where x.row_number <=4;` minimal price for some hotel selected only if row_number > 6 – eugenes Apr 14 '11 at 10:06
1

I am assuming the table Room has a reference to the Hotel it belongs to

SELECT price, room_id, hotel_id, city_id
    FROM Hotel,Room 
    WHERE Hotel.hotel_id = Room.hotel_id
ORDER BY price GROUP BY city_id
LIMIT 10
Aravindan R
  • 3,084
  • 1
  • 28
  • 44
  • This doesn't seem to meet the "for each city" requirement. – Martin Smith Apr 13 '11 at 15:36
  • Worth noting, especially if this is indeed homework related, that even though the question is tagged for MySQL that the "Limit 10" clause is MySQL dialect specific. Other SQL dialects have different command clauses. For example, T-SQL used by MS SQL Server would use "SELECT TOP 10 price..." instead. – Kynth Apr 13 '11 at 15:53