About the same as Gsquared - either should work, I think
select cityname as City, groupname as [Groupname],
isnull(subqty.qty, 0) as Qty
from (select groupid, group.name groupname, city.name Cityname, cityid
from dbo.Group CROSS JOIN city) cartesianX
left outer join
(select cityid, groupid, count(*) as Qty
from dbo.User
where joindate >= @startdate
and joindate < @enddate
group by cityid, groupid) SubQty
on cartesianX.cityid = subqty.cityid
and cartesianX.groupid = subqty.groupid
order by cityname, groupname
----------------------------------------------------------------------------------
Your lack of planning does not constitute an emergency on my part...unless you're my manager...or a director and above...or a really loud-spoken end-user..All right - what was my emergency again?