Спецификация немного неясна.
Мы можем генерировать пары (имя пользователя, город), в которых в текущем месяце нет подходящего проекта. Если у нас нет источника для списка значений города, мы можем получить его из таблицы проектов, так же как мы получили список имени пользователя:
SELECT u.username
, c.city
FROM ( SELECT pu.username
FROM projects pu
GROUP
BY pu.username
) u
CROSS
JOIN ( SELECT pc.city
FROM projects pc
GROUP
BY pc.city
) c
-- anti-join
LEFT
JOIN projects p
ON p.username = u.username
AND p.city = c.city
AND p.date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 MONTH
AND p.date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 MONTH
WHERE p.username IS NULL
ORDER
BY u.username
, c.city
Если мы хотим «фильтровать», мы можем добавить к предложению WHERE
...
WHERE p.username IS NULL
AND c.city = 'Paris'
Или мы могли бы просто включить это условие во встроенное представление c
SELECT u.username
, c.city
FROM ( SELECT pu.username
FROM projects pu
GROUP
BY pu.username
) u
CROSS
JOIN ( SELECT pc.city
FROM projects pc
WHERE pc.city = 'Paris'
GROUP
BY pc.city
) c
-- anti-join
LEFT
JOIN projects p
ON p.username = u.username
AND p.city = c.city
AND p.date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 MONTH
AND p.date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 MONTH
WHERE p.username IS NULL
ORDER
BY u.username
, c.city