В дополнение к другим ответам, здесь есть пара других вариантов:
Вариант 1
Вы можете создать 2 CTE, по одному на каждый месяц (при условии, что вы смотрите на определенные месяцы, а не только на февраль / март в целом). Обратите внимание, что для фильтрации дат используется тип данных range .
WITH
-- sample data
Subscriptions("id", user_id, starts_at, ends_at) AS
(
VALUES
(1, 233, DATE'02/04/19', DATE'03/03/19'),
(2, 233, DATE'03/04/19', DATE'04/03/19'),
(3, 296, DATE'02/09/19', DATE'03/08/19'),
(4, 126, DATE'02/01/19', DATE'02/28/19'),
(5, 126, DATE'03/01/19', DATE'03/31/19'),
(6, 922, DATE'02/22/19', DATE'03/22/19')
),
-- separate CTEs for February and March data
-- using range type for easy filter.
FebruarySubscriptions AS
(
SELECT * FROM Subscriptions
WHERE daterange('2019-02-01', '2019-03-01') @> starts_at
),
MarchSubscriptions AS
(
SELECT * FROM Subscriptions
WHERE daterange('2019-03-01', '2019-04-01') @> starts_at
)
SELECT *
FROM FebruarySubscriptions
LEFT JOIN MarchSubscriptions ON
MarchSubscriptions.user_id = FebruarySubscriptions.user_id
WHERE MarchSubscriptions."id" IS NULL
Вариант 2
Используйте оконную функцию LEAD
, чтобы определить, у каких пользователей нет повторной подписки. Преимущество этой опции в том, что она более расширяема.
WITH
Subscriptions("id", user_id, starts_at, ends_at) AS
(
VALUES
(1, 233, DATE'02/04/19', DATE'03/03/19'),
(2, 233, DATE'03/04/19', DATE'04/03/19'),
(3, 296, DATE'02/09/19', DATE'03/08/19'),
(4, 126, DATE'02/01/19', DATE'02/28/19'),
(5, 126, DATE'03/01/19', DATE'03/31/19'),
(6, 922, DATE'02/22/19', DATE'03/22/19')
),
Resubscriptions(user_id, current_subscription, next_subscription) AS
(
SELECT
user_id,
starts_at,
LEAD(starts_at) OVER
(
PARTITION BY user_id
ORDER BY starts_at ASC
)
FROM Subscriptions
)
SELECT *
FROM Resubscriptions
WHERE
daterange('2019-02-01', '2019-03-01') @> current_subscription
AND next_subscription IS NULL