views:

44

answers:

3

Is there any better way to make this query work? I'm looking for a more efficient solution, if there is one available.

SELECT `unitid`, `name` FROM apartmentunits WHERE aptid IN (
    SELECT `aptid` FROM rentconditionsmap WHERE rentcondid = 4 AND condnum = 1
) AND aptid IN (
    SELECT `aptid` FROM rentconditionsmap WHERE rentcondid = 2 AND condnum = 1
) ORDER BY name ASC 
+2  A: 

I think you want a self-join here. Join table rentconditionsmap to itself, and indicate the conditions on either side of the join. Then join the results of that query into apartmentunits.

(Note: haven't tested this, may require some tweaking...)

SELECT `unitid`, `name` FROM `apartmentunits` 
 WHERE `unitid` IN (
        SELECT `unitid` FROM `rentconditionsmap` r1, `rentconditionsmap` r2
         WHERE r1.`unitid` = r2.`unitid`
           AND r1.`rentcondid` = 4
           AND r1.`condnum` = 1
           AND r2.`rentcondid` = 2
           AND r2.`condnum` = 1)
 ORDER BY `name` ASC
Tenner
@tenner: Your query works. Now, would I just want to proceed with more joins inside that query if I needed to add additional sets of rentcondid and condnum? SELECT unitid, name FROM apartmentunits WHERE aptid IN (SELECT r1.aptid FROM rentconditionsmap r1 JOIN rentconditionsmap r2 ON r1.aptid = r2.aptid WHERE r1.rentcondid = 4 AND r1.condnum = 1 AND r2.rentcondid = 2 AND r2.condnum = 1)
Ben Dauphinee
Yes, if you have three conditions, you'd need three tables in your self-join.
Tenner
A: 

Yes, using joins. Most DBMSes will optimise the join such that it need not pull rows it doesn't have to. MySQL still uses nested loops, but I belive Oracle will use hash joins.

So this query might better be expressed as

Select `unitid`, `name` FROM apartmentunits au
INNER JOIN rentconditionsmap rcm1
USING (aptid)
INNER JOIN rentconditionsmap rcm2
USING (aptid)
WHERE rcm1.rentcondid = 4
AND rcm1.condnum = 1
AND rcm2.rendcondid = 2
AND rcm2.condnum = 1
firebird84
More simply put, the join order will be optimized regardless of DBMS, and it may be better based on statistics to FETCH from the apartmentunits table first, and use its data to select out data on rentconditionsmap. In your query you've essentially dictated the join order.
firebird84
+1  A: 
SELECT a.`unitid`, 
       a.`name` 
FROM   apartmentunits a 
       INNER JOIN rentconditionsmap r 
       ON a.aptid = r.aptid
   AND
       r.rentcondid in (2,4)
   AND 
       r.condnum = 1
ORDER BY a.`name` 
Adam Bernier