tags:

views:

47

answers:

5

Hi Everyone...

Consider the following table....

hotel     facilities
1       internet
1       swimming pool
1       wi-fi
1       parking
2       swimming pool
2       sauna
2       parking
3       toilets
3       bungee-jumping
3       internet
4       parking
4       swimming pool

I need to select only the hotels that have parking, swimming pool and internet....?

I worked out the following....

SELECT hotel
FROM   table
WHERE  facilties IN(internet, swimming pool, parking)

This query selects the hotels that has atleast one among the choices.

But what i need is a query that selects the hotels that has ALL of the selected facilities...

Thanks for your suggestions....

Edit : I should also mention that the number of choices are given by the user and the query should be built dynamically at runtime...

+3  A: 
SELECT first.hotel
FROM table AS first
INNER JOIN table AS second
  ON first.hotel=second.hotel
INNER JOIN table AS third
  ON second.hotel=third.hotel
WHERE first.facilities='internet'
  AND second.facilities='swimming pool'
  AND third.facilities='parking'
Ignacio Vazquez-Abrams
Thanks for the suggestion.... but will this affect performance over a potentially large DB?
SpikETidE
Make sure you have appropriate indexes in place.
Ignacio Vazquez-Abrams
Please see the edit...
SpikETidE
And? There's nothing preventing you from making a larger query in [programming language of choice].
Ignacio Vazquez-Abrams
+1 for the comment.. But if the choices are dynamic won't it be a bit difficult to build a query with "first", "second", "third" and so on...?
SpikETidE
`table_inst1`, `table_inst2`, etc.
Ignacio Vazquez-Abrams
+1  A: 

You could use a GROUP BY and HAVING:

SELECT hotel
FROM table
WHERE facilties IN('internet', 'swimming pool', 'parking')
GROUP BY hotel
HAVING SUM(facilities = 'internet') AND SUM(facilities = 'swimming pool') AND SUM(facilities = 'parking')
Martijn
WHERE facilties IN(internet, swimming pool, parking) Is that syntax valid? I thought those were values and should be within single quotes.
ydobonmai
what is the logic of using SUM()..?
SpikETidE
@Ashish Gupta: you're right. Edited the answer. @SpikETidE: SUM() acts as an OR operator on many booleans: the SUM() will be the number of rows having TRUE, which is positive (hence interpreted as TRUE) if there is at least one row having TRUE.
Martijn
Good suggestion.. Thanks....
SpikETidE
+1  A: 
select t1.hotel
from tab t1,tab t2, tab,t3
where t1.hotel = t2.hotel and t2.hotel = t3.hotel
and t1.facilities = 'internet' and t2.facilities = 'parking'
and t3.facilities = 'swimming pool'
codaddict
@codaddict : This one is similiar to what Ignacio Vazquez-Abrams and cletus posted above.... But the join operations are specified more clearly in the top two posts.. Anyway.. Thanks for the idea and +1 for the same....
SpikETidE
+4  A: 

There are three ways of doing this:

Joins

SELECT hotel
FROM table t1
JOIN table t2 ON t1.hotel = t2.hotel AND t2.facilities = 'swimming pool'
JOIN table t3 ON t1.hotel = t3.hotel AND t3.facilities = 'parking'
WHERE t1.facilities = 'internet'

Aggregation

SELECT hotel
FROM table
GROUP BY hotel
WHERE facilities IN ('internet', 'swimming pool', 'parking')
HAVING COUNT(1) = 3

Note: this assumes no duplicates of (hotel,facilities)

EXISTS

SELECT hotel
FROM table t
WHERE facilities = 'internet'
WHERE EXISTS (SELECT 1 FROM table WHERE hotel = t.hotel AND facilities = 'swimming pool')
AND EXISTS (SELECT 1 FROM table WHERE hotel = t.hotel AND facilities = 'parking')

A good SQL optimizer will probably optimize them all to be the same but I've found MySQL can be somewhat unpredictable in this department so you'll need to benchmark them with meaningful datasets (>1 million rows) to determine which is best.

See Oracle vs MySQL vs SQL Server: Aggregation vs Joins as an example of some of the differences.

cletus
A great Answer... What if i get the number of choices at runtime and have to build the query dynamically..?
SpikETidE
@Spike it depends on what persistence framework you're using. In Java for example I could use Ibatis to quite easily construct the dynamic SQL for any of these options. Constructing them by hand might be painful otherwise. The aggregation one is probably the most straightforward to generate however.
cletus
What does the "count(1) = 3" in the aggregate method do...? And by the way i am using php....
SpikETidE
@Spike the `COUNT(1) = 3` ensures there are three rows per value of `hotel`. If (hotel,facilities) is unique this means the hotel has all three. If it's not unique then you can't use this version of the query as there's no (easy) way of differentiating between a hotel that has one of each vs a hotel with three swimming pool rows.
cletus
Each hotel will have only one row per facility.. There won't be any duplicates within each hotel.. i.e to say.. a hotel will have only one swimming pool row...
SpikETidE
Among the above three the join method works the best.. and it's also easy to build dynamically... Similar to what Ignacio Vazquez-Abrams has posted above but more concise.. Thanks cletus..
SpikETidE
A: 

Another approach.

If you want to build the query dynamically:

Select Distinct hotel from facilities where 1=1
<logic here>
and facilities='internet'
<logic here>
and facilities='pool'
<logic here>
......

Execute your query

andrewWinn