查找没有重新订阅的用户
Find users who did not re-subscribe
我在 PostgreSQL 10.5 中有一个 table 订阅:
id user_id starts_at ends_at
--------------------------------
1 233 02/04/19 03/03/19
2 233 03/04/19 04/03/19
3 296 02/09/19 03/08/19
4 126 02/01/19 02/28/19
5 126 03/01/19 03/31/19
6 922 02/22/19 03/22/19
7 111 01/22/19 02/21/19
8 111 02/22/19 03/21/19
我想获取 3 月份未重新订阅的用户 ID 列表。根据以上数据,它应该显示:
user_id
-------
296
922
我将如何计算这个。我尝试了一些查询,但它们不起作用,不值得发布
您可以使用不存在且不获取开始日期为三月的客户。
with cte as
(
select 1 as ID, 233 as User_Id, '02/04/2019' as Startsat , '03/03/2019' ends_at union all
select 2 as ID, 233 as User_Id, '03/04/2019' as Startsat , '04/03/2019' ends_at union all
select 3 as ID, 296 as User_Id, '02/09/2019' as Startsat , '03/08/2019' ends_at union all
select 4 as ID, 126 as User_Id, '02/01/2019' as Startsat , '02/28/2019' ends_at union all
select 5 as ID, 126 as User_Id, '03/01/2019' as Startsat , '03/31/2019' ends_at union all
select 6 as ID, 922 as User_Id, '02/22/2019' as Startsat , '03/22/2019' ends_at)
select * from cte c
where not exists
(select 1 from cte c1 where c.User_Id = c1.User_Id and date_part('Month',to_date(c1.Startsat,'MM/DD/YYYY'))= '3' )
输出:
id user_id startsat ends_at
3 296 02/09/2019 03/08/2019
6 922 02/22/2019 03/22/2019
这里是 fiddle link:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=84e24cd517fa0810bef011d6fb1b2be2
据推测,您想要特定的三月,而不是任何一年的三月。所以:
select s.userId
from subscriptions s
group by s.userId
having count(*) filter (where startsAt >= '2019-03-01' and startsAt < '2019-04-01') = 0;
您也可以使用 not exists
。如果您有用户列表,这会更好:
select u.*
from users u
where not exists (select 1
from subscriptions s
where s.userid = u.userid and
s.startsAt >= '2019-03-01' and
s.startsAt < '2019-04-01'
);
除了users
,您还可以使用:
select distinct s.userId
from subscriptions
where . . .
除了其他答案,这里还有几个其他选项:
选项 1
您可以创建 2 个 CTE,每个月一个(假设您查看的是特定月份,而不只是一般的 February/March)。请注意,这使用 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
window 函数找出哪些用户没有重新订阅。此选项的好处是它更具可扩展性。
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
我在 PostgreSQL 10.5 中有一个 table 订阅:
id user_id starts_at ends_at
--------------------------------
1 233 02/04/19 03/03/19
2 233 03/04/19 04/03/19
3 296 02/09/19 03/08/19
4 126 02/01/19 02/28/19
5 126 03/01/19 03/31/19
6 922 02/22/19 03/22/19
7 111 01/22/19 02/21/19
8 111 02/22/19 03/21/19
我想获取 3 月份未重新订阅的用户 ID 列表。根据以上数据,它应该显示:
user_id
-------
296
922
我将如何计算这个。我尝试了一些查询,但它们不起作用,不值得发布
您可以使用不存在且不获取开始日期为三月的客户。
with cte as
(
select 1 as ID, 233 as User_Id, '02/04/2019' as Startsat , '03/03/2019' ends_at union all
select 2 as ID, 233 as User_Id, '03/04/2019' as Startsat , '04/03/2019' ends_at union all
select 3 as ID, 296 as User_Id, '02/09/2019' as Startsat , '03/08/2019' ends_at union all
select 4 as ID, 126 as User_Id, '02/01/2019' as Startsat , '02/28/2019' ends_at union all
select 5 as ID, 126 as User_Id, '03/01/2019' as Startsat , '03/31/2019' ends_at union all
select 6 as ID, 922 as User_Id, '02/22/2019' as Startsat , '03/22/2019' ends_at)
select * from cte c
where not exists
(select 1 from cte c1 where c.User_Id = c1.User_Id and date_part('Month',to_date(c1.Startsat,'MM/DD/YYYY'))= '3' )
输出:
id user_id startsat ends_at
3 296 02/09/2019 03/08/2019
6 922 02/22/2019 03/22/2019
这里是 fiddle link:
https://dbfiddle.uk/?rdbms=postgres_10&fiddle=84e24cd517fa0810bef011d6fb1b2be2
据推测,您想要特定的三月,而不是任何一年的三月。所以:
select s.userId
from subscriptions s
group by s.userId
having count(*) filter (where startsAt >= '2019-03-01' and startsAt < '2019-04-01') = 0;
您也可以使用 not exists
。如果您有用户列表,这会更好:
select u.*
from users u
where not exists (select 1
from subscriptions s
where s.userid = u.userid and
s.startsAt >= '2019-03-01' and
s.startsAt < '2019-04-01'
);
除了users
,您还可以使用:
select distinct s.userId
from subscriptions
where . . .
除了其他答案,这里还有几个其他选项:
选项 1
您可以创建 2 个 CTE,每个月一个(假设您查看的是特定月份,而不只是一般的 February/March)。请注意,这使用 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
window 函数找出哪些用户没有重新订阅。此选项的好处是它更具可扩展性。
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