It is best to always specify what type of join you are doing. By default it is using an inner join. An inner join will only show items that have a match in both tables. In your example, you want all the records returned from the placemark_types and zero-to-many of the records from the placemarks table that match.
To do this just use a left join as shown below. The left join always returns all the records from the left side (placemark_types) and only the matching records from the right side (placemarks). Next lets get rid of the COUNT(*)
and use COUNT(placemarks.type_id), because we don't want to count all the rows, just the ones with matches in the placemarks table. Else you would get 1 even when their where zero matches because it would still be counting the placemark_types.
SELECT COUNT(placemarks.type_id) AS type_count, placemark_types.name
FROM placemark_types
LEFT JOIN placemarks ON placemark_types.id = placemarks.type_id
WHERE placemark_types.parent_id = 0
GROUP BY placemark_types.id
To understand this better, run the query without the GROUP BY
. You'll see that even when their are no entries in the placemarks table, you will get the fields from the placemark_types table and nulls for the placemarks fields. Since the COUNT(placemarks.type_id)
will not count nulls, this will give you the correct number.