MySQL - JOIN only if a row exists from the left table
27,187
Solution 1
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
Solution 2
Try this:
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
RIGHT 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;
Related videos on Youtube
Author by
Keir Simmons
Updated on July 09, 2022Comments
-
Keir Simmons almost 2 years
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 inb
(i.eCOUNT(b.id)
is notNULL
) then this query returns a row withNULL
values fora
fields and whatever the value ofCOUNT(b.id)
astickets_bought
. How do I modify this query so it does not return a row (num_rows = 0
) if there is no result in tablea
?A Snap.
-
Keir Simmons over 11 yearsNo,
tickets_bought
is an alias. -
John Dvorak over 11 years"this query returns a row with NULL values for
a
fields" I beg to differ, unlessa
can contain NULL values itself. -
Michael Berkowski over 11 yearsThat is really the query you are using? The behavior you are describing is not that of an
INNER JOIN
, but rather that of aRIGHT JOIN
-
Keir Simmons over 11 yearsI've checked the table structure, and under
NULL
each column hasno
. But when I run the above query it returnsNULL
for each of those fields. -
Michael Berkowski over 11 yearsWait I think I see it - there's no GROUP BY and MySQL is being its usual confusing self with the aggregate.
-
Keir Simmons over 11 years
-
Keir Simmons over 11 years@MichaelBerkowski Thank you.
GROUP BY(b.lid)
after theWHERE
clause fixes it.
-
-
Keir Simmons over 11 yearsI grouped by
b.lid
and it seems to work, what's the difference? -
Michael Berkowski over 11 years@KeirSimmons In that version, no difference since it is an inner join. The second query I posted is more appropriate though because it does not depend on a weird MySQL behavior.
-
Andriy M over 11 years@KeirSimmons: Without
GROUP BY
, it counts all rows returned by your query. But it is apparent from the query that you want counts pera.id
. That's why you need to specify grouping by that criterion, and that affects the result(s) ofCOUNT()
.