we could use an antijoin pattern
briefly... a query to return all dates and users, with an outer join to include matching rows from posts, and then exclude all rows that had a matching row from posts, leaving rows that didnt't have a matching row in posts
As a starting point, we can get a Cartesian product (cross join
) of all dates with all users.
SELECT d.dt
, u.user_name
FROM ( SELECT '2018-01-01' + INTERVAL 0 DAY AS dt
UNION ALL SELECT '2018-01-01' + INTERVAL 1 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 2 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 3 DAY
) d
CROSS
JOIN `USERS` u
ORDER
BY d.dt
, u.user_name
(To return rows from a query, we need a source for those rows. We can't get "missing" rows returned from just the POSTS
table. We need the full set of rows, then we can compare to the contents of the POSTS
table.)
We we can add outer join, to identify matching rows, then exclude rows that had a match.
SELECT d.dt
, u.user_name
FROM ( SELECT '2018-01-01' + INTERVAL 0 DAY AS dt
UNION ALL SELECT '2018-01-01' + INTERVAL 1 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 2 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 3 DAY
) d
CROSS
JOIN `USERS` u
-- anti-join, exclude rows that have a matching row in posts
LEFT
JOIN `POSTS` p
ON p.user_name = u.user_name
AND p.dt = d.dt
WHERE p.dt IS NULL
ORDER
BY d.dt
, u.user_name
The example query returns each individual date, along with users that didn't have a post on that individual date. That satisfies one possible interpretation of the rather vague specification "who didn't post from ... to ... and group it by dates"
For this query to return the expected results, we could craft sample data:
USERS
user_name
---------
Ana
Charlie
John
Lucas
Sandra
and
POSTS
user_name dt
--------- ----------
Charlie 2020-01-01
Lucas 2020-01-01
Charlie 2020-01-02
John 2020-01-02
Lucas 2020-01-02
Ana 2020-01-03
Sandra 2020-01-03
John 2020-01-04
Lucas 2020-01-04
Sandra 2020-01-04
We could use a NOT EXISTS with a correlated subquery, in place of the anti-join, to return equivalent results ...
SELECT d.dt
, u.user_name
FROM ( SELECT '2018-01-01' + INTERVAL 0 DAY AS dt
UNION ALL SELECT '2018-01-01' + INTERVAL 1 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 2 DAY
UNION ALL SELECT '2018-01-01' + INTERVAL 3 DAY
) d
CROSS
JOIN `USERS` u
WHERE NOT EXISTS
( SELECT 1
FROM `POSTS` p
WHERE p.user_name = u.user_name
AND p.dt = d.dt
)
ORDER
BY d.dt
, u.user_name