WITH RECURSIVE
cte1 AS ( SELECT MIN(DATE(create_date)) mindate, MAX(DATE(create_date)) maxdate
FROM shops
UNION ALL
SELECT MIN(DATE(create_date)) mindate, MAX(DATE(create_date)) maxdate
FROM users ),
cte2 AS ( SELECT MIN(mindate) mindate, MAX(maxdate) maxdate
FROM cte1 ),
dates AS ( SELECT mindate thedate, maxdate
FROM cte2
UNION ALL
SELECT thedate + INTERVAL 1 DAY, maxdate
FROM dates
WHERE thedate < maxdate ),
shopstat AS ( SELECT DATE(create_date) thedate, COUNT(*) cnt
FROM shops
GROUP BY thedate ),
userstat AS ( SELECT DATE(create_date) thedate, COUNT(*) cnt
FROM users
GROUP BY thedate )
SELECT thedate `date`,
COALESCE(shopstat.cnt, 0) shops,
COALESCE(userstat.cnt, 0) users
FROM dates
LEFT JOIN shopstat USING (thedate)
LEFT JOIN userstat USING (thedate)
Если нужны данные за определённый период - убрать
cte1 и
cte2, использовать границы диапазона в
dates (поле
maxdate - не нужно, убрать), добавить соотв.
WHERE в остальные CTE.