Эти типы запросов легче всего решить, если у вас есть таблица дат.
В вашей БД запустите этот пакет разово, чтобы создать заполненную таблицу дат.
DROP PROCEDURE IF EXISTS FillDateTable;
delimiter //
CREATE PROCEDURE FillDateTable()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
drop table if exists datetable;
create table datetable (thedate datetime primary key, isweekday smallint);
SET @x := date('2000-01-01');
REPEAT
insert into datetable (thedate, isweekday) SELECT @x, case when dayofweek(@x) in (1,7) then 0 else 1 end;
SET @x := date_add(@x, interval 1 day);
UNTIL @x >= '2030-12-31' END REPEAT;
END//
delimiter ;
CALL FillDateTable;
Тогда вы можете просто использовать обычный LEFT JOIN
SELECT thedate
FROM datetable
LEFT JOIN posts on posts.date = datetable.thedate
WHERE posts.date IS NULL
Конечно, вы не хотите, чтобы все «пропущенные» даты были с 2000 по 2030 год. Ограничьте его минимальными и максимальными датами в таблице сообщений (для пользователя), т.е.
SELECT thedate
FROM datetable
INNER JOIN (select min(date) postStart, max(date) postEnd
FROM posts
where userid=123) p on datetable.thedate BETWEEN p.postStart and p.postEnd
LEFT JOIN posts on posts.date = datetable.thedate
WHERE posts.date IS NULL