SQL连续登录、活跃、持仓天数问题

面试常问问题之SQL连续问题@SQL连续**问题
编辑于2024-10-10
在我们面试过程当中,经常会被问到经典的SQL连续问题,可能是连续10天活跃用户数,可能是连续十天登录的用户,也可能是计算用户的持仓天数。下面我们综合chatGPT和力扣来进行一下SQL连续问题的一个汇总。

问题1:sql连续十天活跃用户数怎么算

要计算连续十天活跃用户数,我们可以使用SQL中的窗口函数(LEAD和SUM)来实现。以下是一个示例,假设我们有一个名为user_activity的表,其中包含两列:user_id和activity_date

SELECT 
    COUNT(DISTINCT user_id) AS active_users
FROM (
    SELECT 
        user_id, 
        SUM(is_consecutive) OVER (PARTITION BY user_id ORDER BY activity_date) AS consecutive_days
    FROM (
        SELECT 
            user_id, 
            activity_date, 
            CASE 
                WHEN activity_date = DATE_ADD(LAG(activity_date) OVER (PARTITION BY user_id ORDER BY activity_date), INTERVAL 1 DAY) 
                THEN 1 
                ELSE 0 
            END AS is_consecutive
        FROM 
            user_activity
    ) AS user_activity_with_flag
) AS users_with_consecutive_days
WHERE 
    consecutive_days = 10;

问题2:sql计算连续持仓小时数怎么算

问题3:连续递增交易

编写一个 SQL 查询,找出至少连续三天 amount 递增的客户。并包括 customer_id 、连续交易期的起始日期和结束日期。一个客户可以有多个连续的交易。
表: Transactions

+------------------+------+
| 字段名            | 类型 |
+------------------+------+
| transaction_id   | int  |
| customer_id      | int  |
| transaction_date | date |
| amount           | int  |
+------------------+------+

transaction_id 是该表的主键。
每行包含有关交易的信息,包括唯一的 (customer_id, transaction_date),以及相应的 customer_id 和 amount。
返回结果并按照 customer_id 升序 排列。

查询结果的格式如下所示

select 
    customer_id,
    min(transaction_date) as consecutive_start,
    max(transaction_date) as consecutive_end
from
(    select 
			customer_id,
      transaction_date,
      sum(case when amount > last_amount then 0 else 1 end) over(partition by customer_id order by transaction_date asc) as flag_amount,
			date_sub(transaction_date,interval rn day) as flag_day
		from (
			select 
		    transaction_id,
		    customer_id,
		    transaction_date,
        amount,
        lag(amount,1,0) over(partition by customer_id order by transaction_date asc) as last_amount,
		    row_number() over(partition by customer_id order by transaction_date asc) as rn 
			from Transactions
	) t1
) t2 
group by customer_id,flag_amount,flag_day 
having count(1) > 2
order by customer_id asc
;

解析:

  1. 用户发生连续交易
    通用解法,使用 日期 - row_number做标识即可
  2. 连续交易的几天中交易金额持续增长
    1.逐日判断当日金额是否大于前一天金额,大于则标识0否则标识1。目的是为了使用1作为“不连续”情况的分界线
    2.开窗累加标识,当存在不连续情况的“分界线”时累计值会发生变化,即可识别金额的连续增长情况。

问题4:连续空余座位

表: Cinema

+-------------+------+
| Column Name | Type |
+-------------+------+
| seat_id     | int  |
| free        | bool |
+-------------+------+

Seat_id 是该表的自动递增主键列。
在 PostgreSQL 中,free 存储为整数。请使用 ::boolean 将其转换为布尔格式。
该表的每一行表示第 i 个座位是否空闲。1 表示空闲,0 表示被占用。

查找电影院所有连续可用的座位。
返回按 seat_id 升序排序 的结果表。
测试用例的生成使得两个以上的座位连续可用。

select distinct seat_id
from(select seat_id,free,
    sum(free) over(rows between 1 preceding and current row) as flag1,
    sum(free) over(rows between current row and 1 following) as flag2
from Cinema) a
where flag1>1 or flag2>1
order by seat_id;

解析:当flag1等于2时,此座位连续,但是无法识别连续座位的第一个,因为上一个是0,这一个是1,之和为1。
当flag2等于2时,此座位连续,但是无法识别连续座位的最后一个,因为下一个是0,这一个是1,之和为1。
所以通过同时判断flag1和flag2,可以得到连续座位。

问题5:连续空余座位2

SQL Schema
Pandas Schema
表:Cinema

+-------------+------+
| Column Name | Type |
+-------------+------+
| seat_id     | int  |
| free        | bool |
+-------------+------+

seat_id 是这张表中的自增列。
这张表的每一行表示第 i 个作为是否空余。1 表示空余,而 0 表示被占用。
编写一个解决方案来找到电影院中 最长的空余座位 的 长度。

注意:

保证 最多有一个 最长连续序列。
如果有 多个 相同长度 的连续序列,将它们全部输出。
返回结果表以 first_seat_id 升序排序。

select min(seat_id) as first_seat_id,
        max(seat_id) as last_seat_id,
        count(seat_id) as consecutive_seats_len
from(select seat_id,free,flag1,flag2
from(select seat_id,free,
    sum(free) over(rows between 1 preceding and current row) as flag1,
    sum(free) over(rows between current row and 1 following) as flag2
 from Cinema) a
 where flag1 > 1 or flag2 > 1) b

解析:非常规做法,根据连续空余座位得出思路,先找到连续的座位,然后再找连续座位中最小的就是开始座位,最大的就是结束座位,count计数一共有多少个连续的座位。风险当多次连续时可能无法计算。

 WITH t1 AS(          # 找出空闲座位
    SELECT seat_id
    FROM Cinema
    WHERE free = 1 
),t2 AS(            # 计算seat_id与row_number之差,num相同的代表连续空闲
    SELECT
        seat_id,
        seat_id - ROW_NUMBER() OVER(ORDER BY seat_id ASC) AS num
    FROM t1
),t3 AS(           
    SELECT
        MIN(seat_id) AS first_seat_id,   # 连续空闲开始的seat_id
        MAX(seat_id) AS last_seat_id,    # 连续空闲结束的seat_id
        COUNT(*) AS consecutive_seats_len,    # 空闲座位数
        DENSE_RANK() OVER(ORDER BY COUNT(*) DESC) rnk  # 根据空闲座位数降排列
    FROM t2
    GROUP BY num  # 根据num分组,同组连续空闲
)
SELECT
    first_seat_id,
    last_seat_id,
    consecutive_seats_len
FROM t3
WHERE rnk = 1               # 连续空闲最大座位数
ORDER BY first_seat_id ASC
;

解析常规做法

问题6:连续出现的数字

表:Logs

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| id          | int     |
| num         | varchar |
+-------------+---------+

在 SQL 中,id 是该表的主键。
id 是一个自增列。

找出所有至少连续出现三次的数字。
返回的结果表中的数据可以按 任意顺序 排列。

SELECT DISTINCT
    l1.Num AS ConsecutiveNums
FROM
    Logs l1,
    Logs l2,
    Logs l3
WHERE
    l1.Id = l2.Id - 1
    AND l2.Id = l3.Id - 1
    AND l1.Num = l2.Num
    AND l2.Num = l3.Num
;

解析常规做法:相当于自连接,但是没有join可能产生的笛卡尔积,因此执行速度更快。ID连续即ID的差值是1,连续出现三次即值相等。

问题7:报告系统状态的连续日期

表:Failed

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| fail_date    | date    |
+--------------+---------+

该表主键为 fail_date (具有唯一值的列)。
该表包含失败任务的天数.

表: Succeeded

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| success_date | date    |
+--------------+---------+

该表主键为 success_date (具有唯一值的列)。
该表包含成功任务的天数.

系统 每天 运行一个任务。每个任务都独立于先前的任务。任务的状态可以是失败或是成功。
编写解决方案找出 2019-01-01 到 2019-12-31 期间任务连续同状态 period_state 的起止日期(start_date 和 end_date)。即如果任务失败了,就是失败状态的起止日期,如果任务成功了,就是成功状态的起止日期。

最后结果按照起始日期 start_date 排序

select 
    case when label =</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值