SQL167 连续签到领金币

SQL167 连续签到领金币

题目描述

用户行为日志表 tb_user_log

iduidartical_idin_timeout_timesign_in
110102021-07-07 10:00:002021-07-07 10:00:091
210102021-07-08 10:00:002021-07-08 10:00:091
310102021-07-09 10:00:002021-07-09 10:00:421
41010

2021-07-10 10:00:00

2021-07-10 10:00:091
510102021-07-11 23:59:552021-07-11 23:59:591
610102021-07-12 10:00:282021-07-12 10:00:501
710102021-07-13 10:00:28

2021-07-13 10:00:50

1
810202021-10-01 10:00:282021-10-01 10:00:501
910202021-10-02 10:00:012021-10-02 10:01:501
1010202021-10-03 10:00:552021-10-03 11:00:591
1110202021-10-04 10:00:452021-10-04 11:00:550
1210202021-10-05 10:00:532021-10-05 11:00:591
1310202021-10-06 10:00:452021-10-06 11:00:551

(uid-用户ID, artical_id-文章ID, in_time-进入时间, out_time-离开时间, sign_in-是否签到)

场景逻辑说明

  • artical_id-文章ID代表用户浏览的文章的ID,特殊情况artical_id-文章ID0表示用户在非文章内容页(比如App内的列表页、活动页等)。注意:只有artical_id为0时sign_in值才有效。
  • 2021年7月7日0点开始,用户每天签到可以领1金币,并可以开始累积签到天数,连续签到的第3、7天分别可额外领2、6金币
  • 每连续签到7天后重新累积签到天数(即重置签到天数:连续第8天签到时记为新的一轮签到的第一天,领1金币)

问题

计算每个用户2021年7月以来每月获得的金币数(该活动到10月底结束,11月1日开始的签到不再获得金币)。结果按月份、ID升序排序。

:如果签到记录的in_time-进入时间和out_time-离开时间跨天了,也只记作in_time对应的日期签到了

输出示例

示例数据的输出结果如下:

uidmonthcoin
10120210715
1022021107

解释:

101在活动期内连续签到了7天,因此获得1*7+2+6=15金币;

102在10.01~10.03连续签到3天获得5金币

10.04断签了,10.05~10.06连续签到2天获得2金币,共得到7金币。


思路

参考大佬:题解 | #连续签到领金币# 解题思路总结_牛客博客

问题理解

我们需要计算每个用户在2021年7月至10月期间,每月通过签到获得的金币总数。签到规则如下:

  1. 每天签到可获得1金币
  2. 连续签到第3天额外获得2金币
  3. 连续签到第7天额外获得6金币
  4. 每连续签到7天后重新开始计算(第8天视为新一轮的第1天)

解题思路

步骤1:提取有效签到记录

首先需要从用户行为日志中筛选出符合条件的签到记录:

  • 时间范围:2021-07-07至2021-10-31
  • 文章ID为0(表示在非文章页面)
  • 签到位为1(表示成功签到)
SELECT DISTINCTuid,DATE(in_time) AS sign_date
FROM tb_user_log
WHERE in_time BETWEEN '2021-07-07 00:00' AND '2021-10-31 23:59'AND artical_id = 0AND sign_in = 1

步骤2:识别连续签到分组

为了计算连续签到天数,我们使用一个技巧:用签到日期减去行号,相同结果的日期属于同一连续签到组

SELECT uid,sign_date,DATE_SUB(sign_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY uid ORDER BY sign_date) DAY) AS group_date
FROM sign_dates

例如:

  • 用户连续签到3天:2021-07-07、2021-07-08、2021-07-09
  • 计算 group_date:
    • 2021-07-07 - 1天 = 2021-07-06
    • 2021-07-08 - 2天 = 2021-07-06
    • 2021-07-09 - 3天 = 2021-07-06
      这三个日期的 group_date 相同,表示它们是连续的

步骤3:计算连续签到天数

在每组内,按日期排序并编号,得到连续签到天数。

SELECT uid,sign_date,ROW_NUMBER() OVER (PARTITION BY uid, group_date ORDER BY sign_date) AS continuous_day
FROM sign_groups

步骤4:计算每日金币

根据连续签到天数计算每日获得的金币:

  • 第3天:1基础金币 + 2额外 = 3金币
  • 第7天:1基础金币 + 6额外 = 7金币
  • 其他天数:1金币
SELECT uid,sign_date,CASE WHEN continuous_day % 7 = 3 THEN 3WHEN continuous_day % 7 = 0 THEN 7ELSE 1END AS coin
FROM continuous_days

步骤5:按月汇总金币

最后,按用户ID和月份分组,汇总金币总数。

SELECT uid,DATE_FORMAT(sign_date, '%Y%m') AS month,SUM(coin) AS coin
FROM daily_coins
GROUP BY uid, DATE_FORMAT(sign_date, '%Y%m')
ORDER BY month, uid

关键点

  1. 连续签到识别​:通过日期减去行号的方法识别连续签到组
  2. 金币计算规则​:正确处理第3天和第7天的额外金币
  3. 7天周期重置​:使用模运算(continuous_day % 7)实现7天后重置

代码

WITH 
-- 获取有效的签到日期
sign_dates AS (SELECT DISTINCTuid,DATE(in_time) AS sign_dateFROM tb_user_logWHERE in_time BETWEEN '2021-07-07 00:00' AND '2021-10-31 23:59'AND artical_id = 0AND sign_in = 1
),-- 计算连续签到分组
sign_groups AS (SELECT uid,sign_date,-- 计算连续签到分组标识DATE_SUB(sign_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY uid ORDER BY sign_date) DAY) AS group_dateFROM sign_dates
),-- 计算每组内的连续签到天数
continuous_days AS (SELECT uid,sign_date,-- 计算每组内的连续签到天数ROW_NUMBER() OVER (PARTITION BY uid, group_date ORDER BY sign_date) AS continuous_dayFROM sign_groups
),-- 计算每日金币
daily_coins AS (SELECT uid,sign_date,CASE WHEN continuous_day % 7 = 3 THEN 3  -- 第3天额外2金币WHEN continuous_day % 7 = 0 THEN 7  -- 第7天额外6金币ELSE 1                              -- 其他天1金币END AS coinFROM continuous_days
)-- 最终按月汇总
SELECT uid,DATE_FORMAT(sign_date, '%Y%m') AS month,SUM(coin) AS coin
FROM daily_coins
GROUP BY uid, DATE_FORMAT(sign_date, '%Y%m')
ORDER BY month, uid;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/916845.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916845.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP性能优化与高并发处理:从基础到高级实践

引言 在当今高流量的互联网环境中,PHP应用的性能优化变得至关重要。本文将全面探讨PHP性能优化的各个层面,从基础优化技巧到高级并发处理方案,帮助开发者构建高性能的PHP应用。 基础性能优化 OPcache配置优化 ; php.ini 推荐OPcache配置 [opcache] opcache.enable=1 opc…

C++ std::map erase() 和迭代器详解:常见面试陷阱与深入理解

在使用 C 的 std::map 时,配合 erase() 和迭代器的使用是一个经典面试点,也是实际开发中经常出错的地方。本文将深入讲解 erase() 的行为、end() 的本质以及迭代器失效规则,帮助你写出更健壮的代码。1. erase(it) 的行为当你使用 erase(it) 删…

求职招聘小程序源码搭建招聘小程序开发定制人力资源系统

身份:求职者、企业求职者:完善简历,简历投递企业:企业入驻,查看简历企业会员:半年 、年度 权益:每日发布条数、刷新条数,简历下载数量聊天:求职者可以和企业聊天招聘会…

【31】C# WinForm入门到精通 ——保存文件SaveFileDialog 【属性、方法、事件、实例、源码】

WinForm 是 Windows Form 的简称,是基于 .NET Framework 平台的客户端(PC软件)开发技术,是 C# 语言中的一个重要应用。 .NET 提供了大量 Windows 风格的控件和事件,可以直接拿来使用。 本专栏内容是按照标题序号逐渐…

socket网络编程(1)

socket网络编程(1) 设计echo server进行接口使用 生成的Makefile文件如下 .PHONY:all all:udpclient udpserverudpclient:UdpClient.ccg -o $ $^ -stdc17 -static udpserver:UdpServer.ccg -o $ $^ -stdc17.PHONY:clean clean:rm -f udpclient udpserver…

数据集:机器学习的基石

三、数据集:机器学习的基石1. sklearn 玩具数据集:快速入门的理想选择1.1 玩具数据集的特点与价值sklearn 内置的玩具数据集(Toy Datasets)是机器学习入门的绝佳资源。这类数据集通常具有以下特点:数据量小&#xff1a…

SQL排查、分析海量数据以及锁机制

1. SQL排查 1.1 慢查询日志: mysql提供的一种日志记录, 用户记录MySQL中响应时间超过阈值的SQL语句(long_query_time, 默认10秒), 慢查询日志默认是关闭的, 建议开发调优时打开, 最终部署的时候关闭 1.1.1 检查是否开启了慢查询日志 show variables like %slow_query_log%;临…

conda 安装prokka教程

本章教程,记录如何在wsl2+ubuntu下载通过conda安装prokka软件包。 Prokka 是一个快速的、功能强大的基因组注释工具,特别适用于细菌基因组的注释。它能够自动化完成从基因组序列到功能注释的整个流程,包括基因的识别、功能预测和注释,并且支持多种文件格式输出,广泛应用于…

CSS3 圆角

CSS3 圆角 引言 CSS3圆角是现代网页设计中非常重要的一项功能,它使得网页元素的外观更加平滑、美观。本文将详细介绍CSS3圆角的概念、实现方法以及相关属性,帮助您更好地掌握这一技巧。 CSS3圆角概念 CSS3圆角指的是通过CSS3属性为元素(如div…

牛顿-拉夫森法求解非线性方程组

牛顿-拉夫森法(Newton-Raphson method)是一种用于求解非线性方程组的迭代方法。该方法通过线性化非线性方程组,并逐步逼近方程组的解。以下是牛顿-拉夫森法求解非线性方程组的详细步骤和MATLAB实现。 1. 牛顿-拉夫森法的基本原理 对于非线性方…

Windows系统使用命令生成文件夹下项目目录树(文件结构树)的两种高效方法

Windows系统使用命令生成文件夹下项目目录树(文件结构树)的两种高效方法前言:**方法一:tree 命令 —— 快速生成经典目录树****方法二:PowerShell —— 可以精准过滤“降噪”的命令**这份列表非常精炼,只包…

react中暴露事件useImperativeHandle

注:本页面模块主要是使用 useImperativeHandle ,一、概述1、要点hooks 中的暴露事情件方法useImperativeHandle,需要和forwardRef、ref 结合一起使用。1、外层校验的时候会校验里面所有需要校验的验证2、基础使用二、demo案例1、场景1、弹框打…

【论文阅读】-《RayS: A Ray Searching Method for Hard-label Adversarial Attack》

RayS:一种用于硬标签对抗攻击的光线搜索方法 Jinghui Chen University of California, Los Angeles jhchencs.ucla.edu Quanquan Gu University of California, Los Angeles qgucs.ucla.edu 原文链接:https://arxiv.org/pdf/2006.12792 摘要 深度神经…

15K的Go开发岗,坐标北京

好久没有分享最新的面经了,今天分享一下北京某公司Go开发岗的面经,薪资是15K左右,看看难度如何: 为什么要用分布式事务 分布式事务的核心作用是解决跨服务、跨数据源操作的数据一致性问题。在单体应用中,数据库本地事务…

Linux 文件管理高级操作:复制、移动与查找的深度探索

目录一、文件复制:从基础到企业级同步的全维度解析1. cp命令:基础工具的进阶密码(1)文件属性保留:从基础到极致(2)特殊文件处理:稀疏文件与设备文件(3)安全操…

Redis内存使用耗尽情况分析

目录 1、内存上限介绍 1.1、产生原因 1.2、Redis的maxmemory限额 1.3、影响的命令与场景 2. 内存用完后的策略 2.1、淘汰策略分类 2.2、淘汰策略介绍 2.3、不同策略对比 3、常见业务示例 3.1、影响 3.2、监控与自动告警 前言 在日常项目中,不知道你思考过…

Ubuntu 系统中配置 SSH 服务教程

一、什么是 SSH?SSH(Secure Shell)是一种加密的网络协议,用于在不安全的网络中安全地进行远程登录、远程命令执行和文件传输。它是 Telnet、FTP 等传统协议的安全替代品。二、确认系统环境在开始配置之前,请确认你的系…

基于springboot的编程训练系统设计与实现(源码+论文)

一、开发环境 技术/工具描述MYSQL数据库一个真正的多用户、多线程SQL数据库服务器,适用于Web站点或其他应用软件的数据库后端开发。B/S结构基于互联网系统的软件系统开发架构,利用浏览器进行访问,支持多平台使用。Spring Boot框架简化新Spri…

K8s集群两者不同的对外暴露服务的方式

在工作中,我们暴露集群内的服务通常有几种方式,对于普通的http或者https,我们通常使用​Ingress Nginx​ ,对于原始的TCP或者UDP端口服务,可能需要选择 ​LoadBalancer​ ,它们的核心区别在于工作层级、协议支持和流量…

实习日志111

第一天 加入内网和内网域,设置自己的操作系统 第二天 安装常用软件和平台 Notepad 是一款免费的源代码编辑器,支持多种编程语言,其功能强大且界面友好,适用于 Windows 操作系统。WinMerge 是一款开源的差异比较和合并工具&…