Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL - JOIN only if a row exists from the left table

Here is MySQL:

SELECT  a.id,
        a.name,
        a.n,
        a.r,
        a.pot,
        a.ticket_price,
        a.starting_tickets,
        a.started,
        a.end,
        COUNT(b.id) tickets_bought 
FROM current_lotteries a
   JOIN lottery_tickets b ON b.lid=a.id
WHERE a.cid=1 
ORDER BY started DESC LIMIT 1    

In the search, if there is no row from a but there are rows in b (i.e COUNT(b.id) is not NULL) then this query returns a row with NULL values for a fields and whatever the value of COUNT(b.id) as tickets_bought. How do I modify this query so it does not return a row (num_rows = 0) if there is no result in table a?

A Snap.

query

like image 767
Keir Simmons Avatar asked Jan 06 '13 13:01

Keir Simmons


People also ask

Where Not Exists vs left outer join?

EXISTS and NOT EXISTS both short circuit - as soon as a record matches the criteria it's either included or filtered out and the optimizer moves on to the next record. LEFT JOIN will join ALL RECORDS regardless of whether they match or not, then filter out all non-matching records.

Can we use LEFT join instead of right join?

Yes, we can. Right and left outer joins are functionally equivalent. Neither provides any functionality that the other does not, so right and left outer joins may replace each other as long as the table order is switched.


1 Answers

Absent a GROUP BY clause, MySQL (which permits this where it would be an error in other RDBMS) is applying the aggregate group over all rows in b when it should be grouping them. Add GROUP BY a.id

SELECT  a.id,
        a.name,
        a.n,
        a.r,
        a.pot,
        a.ticket_price,
        a.starting_tickets,
        a.started,
        a.end,
        COUNT(b.id) tickets_bought 
FROM current_lotteries a
   JOIN lottery_tickets b ON b.lid=a.id
WHERE a.cid=1 
GROUP BY a.id
ORDER BY started DESC LIMIT 1    

The above will work in MySQL but not elsewhere. A more portable version uses a correlated subquery:

SELECT  a.id,
        a.name,
        a.n,
        a.r,
        a.pot,
        a.ticket_price,
        a.starting_tickets,
        a.started,
        a.end,
        b.tickets_bought
FROM current_lotteries a
        /* More portable to join against a subquery which returns the count per group */
        JOIN (
            SELECT b.lid, COUNT(*) AS tickets_bought 
            FROM lottery_tickets 
            GROUP BY lid
        ) b ON a.id = b.lid
WHERE a.cid = 1
ORDER BY started DESC LIMIT 1
like image 155
Michael Berkowski Avatar answered Sep 28 '22 19:09

Michael Berkowski