力扣刷题(sql)--零散知识点(1)

通过一段时间的刷题,感觉自己的sql能力逐渐上去,所以不会像前三道题一样讲那么详细了,这里主要会讲到一些特殊的知识点和方法。另外,我的建议是做完一个题有好的想法赶紧记录下来,不要想着最后汇总,不然会懒得整理,也会忘记一些当时才发现的知识点。

------------------------------------------------------------------------------------------------------------------------

1. 不用if的sum

这里的sum(order_date= customer_pref_delivery_date),没有用到if也能用聚集函数sum把满足order_date= customer_pref_delivery_date条件的行数加起来。说明有的时候可以不用if,用if的话还要设置两个正确与否的值,通常是1和0.

select
    round(sum(order_date= customer_pref_delivery_date)/count(*)*100,2) immediate_percentage
from
    delivery
where
    (customer_id,order_date)
in
    (select
        customer_id, min(order_date)  
    from
        delivery
    group by
        customer_id);

2. 多个列名的in

上面代码的where后面是判断某一行中两列对应的值能否另一个表(这里是个子查询)对上。我们之前往往用到的都是只有一个列,比如where id in (201,203),这里可以很好的扩展思维,个人认为很有用的知识点。

3. datediff的误区

select
    activity_date day , count(distinct user_id) active_users
from
    activity
where
    datediff('2019-07-27',activity_date)<29
group by
    activity_date;

这里我想找出activity_date在’2019-07-27’近 30 天的日期,但是后面我发现这是错的,因为没有限制 activity_date 不能超出‘2019-07-27’。这会导致某些未来的日期(如 2019-08-252021-08-25)也符合条件(做差后为负数,也小于29)。

所以解决这一问题的方法就是用between。between也有两种用法:

activity_date BETWEEN DATE_SUB('2019-07-27', INTERVAL 29 DAY) AND '2019-07-27'

DATEDIFF('2019-07-27', activity_date) BETWEEN 1 AND 29

以上两种都可以实现找到近 30 天日期的作用。

******值得一提的是,题目要求近30天,而上面的代码输入的关键字都是29,这点需要注意,因为DATEDIFF() 的结果是天数差,不包括起始日期的那一天。

4. min()求最小日期

MIN()函数:会返回某个列中的最小值,在时间数据上,它返回最早的日期。

select MIN(activity_date) from activity;

5. lag()窗口函数

刷题的时候用到了一下,感觉特别好用,再次讲解一下,这次还用到了“PARTITION BY

LAG() 是 SQL 中的一种窗口函数,用于获取当前行的前一行的值,而无需在查询中自连接。这在需要对比相邻记录(如日期、订单、活动等)时非常有用。 

语法如下:

LAG(column_name, [offset], [default_value]) 
OVER (PARTITION BY partition_column ORDER BY order_column)

实际用例:

user_idactivity_dateactivity_type
12019-07-20open_session
12019-07-21send_message
12019-07-22end_session
22019-07-21open_session
22019-07-23end_session
SELECT 
    user_id, 
    activity_date, 
    activity_type,
    LAG(activity_date) OVER (PARTITION BY user_id ORDER BY activity_date) AS previous_activity_date
FROM 
    activity;

结果:

user_idactivity_dateactivity_typeprevious_activity_date
12019-07-20open_sessionNULL
12019-07-21send_message2019-07-20
12019-07-22end_session2019-07-21
22019-07-21open_sessionNULL
22019-07-23end_session2019-07-21

有的时候还是能发挥一定的作用。 

6.筛选部分组内数据满足条件的分组

例题:编写解决方案,报告 2019年春季 才售出的产品。即 仅 在 2019-01-01 (含)至 2019-03-31 (含)之间出售的商品。

输入:
Product table:
+------------+--------------+------------+
| product_id | product_name | unit_price |
+------------+--------------+------------+
| 1          | S8           | 1000       |
| 2          | G4           | 800        |
| 3          | iPhone       | 1400       |
+------------+--------------+------------+
table:
+-----------+------------+----------+------------+----------+-------+
| seller_id | product_id | buyer_id | sale_date  | quantity | price |
+-----------+------------+----------+------------+----------+-------+
| 1         | 1          | 1        | 2019-01-21 | 2        | 2000  |
| 1         | 2          | 2        | 2019-02-17 | 1        | 800   |
| 2         | 2          | 3        | 2019-06-02 | 1        | 800   |
| 3         | 3          | 4        | 2019-05-13 | 2        | 2800  |
+-----------+------------+----------+------------+----------+-------+
输出:
+-------------+--------------+
| product_id  | product_name |
+-------------+--------------+
| 1           | S8           |
+-------------+--------------+

 刚开始我写的代码如下:

select
    p.product_id, p.product_name
from
    product p
join
    sales s
on
    p.product_id = s.product_id
and
    date(s.sale_date) between '2019-01-01' and '2019-03-31'; 

上面代码利用简单联结找出sale_date在2019-01-01到2019-03-31,这样会返回错误的结果,因为产品2不仅在这个区间里出售了,在其他区间也出售了,没有实现“仅”的目的。

后面使用分组(group by+having)的办法,比较巧妙的解决了这一问题,即对该组内所有数据都进行验证,排除这种有的满足、有的不满足的数据,却加入了要求所有数据满足的分组里面。

# Write your MySQL query statement below
select
    p.product_id, p.product_name
from
    product p
join
    sales s
on
    p.product_id = s.product_id
group by
    p.product_id, p.product_name
having
    min(sale_date) >= '2019-01-01' and max(sale_date) <= '2019-03-31';

即GROUP BY + HAVING:适用于简单的按组汇总,并进行唯一性判断。

7. distinct在多列上的的使用

DISTINCT 是 SQL 中的关键字,用于去除查询结果中的重复行,返回唯一值。它通常用于 SELECT 语句中,确保查询的结果集中不包含重复的数据。

这里DISTINCT 不仅可以应用于单列,也可以用于多个列(放在多个列名的最前面),它会返回这些列的组合的唯一值。

SELECT DISTINCT product_id FROM sales;

SELECT DISTINCT product_id, buyer_id FROM sales;

---------------------------------------------------------------------------------------------------------------------------------例题: 一个员工可以属于多个部门。当一个员工加入超过一个部门的时候,他需要决定哪个部门是他的直属部门。请注意,当员工只加入一个部门的时候,那这个部门将默认为他的直属部门,虽然表记录的值为'N'.

输入:
Employee table:
+-------------+---------------+--------------+
| employee_id | department_id | primary_flag |
+-------------+---------------+--------------+
| 1           | 1             | N            |
| 2           | 1             | Y            |
| 2           | 2             | N            |
| 3           | 3             | N            |
| 4           | 2             | N            |
| 4           | 3             | Y            |
| 4           | 4             | N            |
+-------------+---------------+--------------+
输出:
+-------------+---------------+
| employee_id | department_id |
+-------------+---------------+
| 1           | 1             |
| 2           | 1             |
| 3           | 3             |
| 4           | 3             |
+-------------+---------------+

这题我写了很长串,思路是先把有“Y”的分一组,然后其他没“Y”就是只有一行的分一组,然后拼起来。我觉得太长,而gpt给出了两种方法,可以来学习一下。(gpt懂得太多了,有能借鉴而且实用的才拿出来记录下。)

8. max()配合case求出分组中某个符合条件的值

如图所示,下面是上一题的更优解,这里用到了一些配合。

SELECT 
    employee_id, 
    COALESCE(
        MAX(CASE WHEN primary_flag = 'Y' THEN department_id ELSE NULL END),
        MAX(department_id)
    ) AS department_id
FROM 
    employee
GROUP BY 
    employee_id;

首先来个错误示范(我写的):

SELECT 
    employee_id, 
    if(primary_flag='Y',department_id,null) department_id
FROM 
    employee
GROUP BY 
    employee_id;

代码意思好像要求把分组后primary_flag='Y'的department_id值打印出来,结果如图:

employee_id为1和3返回null正常,它们没有符合primary_flag='Y'条件的行,但employee_id为4有满足条件的行,但也返回null,说明语法还是有问题,貌似这里只会判断每一组的第一行是否满足rimary_flag='Y'条件,所有2有返回值,4返回null

这里就要配合max()函数了,MAX(CASE WHEN primary_flag = 'Y' THEN department_id ELSE NULL END),这里if和case差别不大,作用都一样,条件语句把每一组的每一行判断条件后每一行都会得到要么是一个数值,要么是null,用max()比较数值和null后,就能让那个合适的返回值返回出来了。

这里加上max()函数后,2和4就能正常返回正确的department_id值了,但1和3依旧返回null,因为它们压根没有primary_flag='Y'条件的行啊。为了满足题意,即只有一行时,不管primary_flag='Y'条件是否成立,都返回其department_id,那还要配合COALESCE()。 

9.COALESCE()

COALESCE() 是 SQL 中的一个非常实用的空值处理函数,用于返回第一个非 NULL 的值。它的主要作用是提供一个默认值,避免返回 NULL 结果。这个函数在处理缺失数据、替代空值、进行多层判断时非常有用。coalesce(合并的意思)

COALESCE(value1, value2, ..., valueN)

下面的代码当employee_id的1、3的max()配合case依然返回null后,直接返回其department_id,这个不是null,直接返回。

 COALESCE(
        MAX(CASE WHEN primary_flag = 'Y' THEN department_id ELSE NULL END),
        department_id
    )

8、9的总结:希望能很好地帮助到以后对某个列分组后求另外一个列符合条件的值。 

10. ROW_NUMBER()

依然是刚才那题,看一下另一种思路:

WITH ranked_departments AS (
    SELECT 
        employee_id, 
        department_id, 
        ROW_NUMBER() OVER (
            PARTITION BY employee_id 
            ORDER BY primary_flag DESC
        ) AS rn
    FROM 
        employee
)
SELECT 
    employee_id, 
    department_id
FROM 
    ranked_departments
WHERE 
    rn = 1;

这些代码的思路大概是:用到了一个类似子表的东西,同时自己设置了一列,这一列是利用ROW_NUMBER(),根据employee_id分区,然后通过primary_flag这一列来排序最终设计得到,最后在新表中根据新得到的这一列,取出新列中所有编号为1的employee_id, department_id.

这里的语法和之前的lag()函数一样。

ROW_NUMBER() 是 SQL 中的一个窗口函数,用于为查询结果中的每一行分配一个唯一的编号,这个编号通常按某种顺序排列(如时间、ID等)。它常用于需要按某种顺序进行排序、排名或者找出每个分组的第一条或最后一条记录的场景。

ROW_NUMBER() OVER (PARTITION BY partition_column ORDER BY order_column)

这种编号后提取指定编号的思维值得学习。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM平面设计课程在线学习系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;课程类型管理&#xff0c;课程学习管理&#xff0c;试题讲解管理&#xff0c;作业信息管理 前台账号功能包括&#xff1a;系统首页&#xff0c;个人中心&…

Vue3实现获取验证码按钮倒计时效果

Vue3实现获取验证码按钮倒计时效果 效果描述&#xff1a;用户点击获取验证码按钮&#xff0c;发送请求给后端&#xff0c;按钮失效&#xff0c;并且开始倒计时60秒&#xff1b;在此期间&#xff0c;用户无法再次点击按钮&#xff0c;即使用户刷新页面&#xff0c;倒计时依然存在…

Java项目实战II基于微信小程序的马拉松报名系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 马拉松运动…

XQT_UI 组件|01|颜色

介绍 XColor 是一个用于处理颜色的类&#xff0c;提供了获取颜色和样式的方法。它可以与 Qt 的 UI 组件结合使用&#xff0c;以便在应用程序中实现丰富的颜色效果。 安装 确保你已经在项目中包含了 xqt_color_palette.hpp 和相关的头文件。 #include "xqt_color_palet…

【Go语言】Gin框架的简单基本文档

思维导图 一、go 原生的http服务 在go中写一个web服务非常方便和快速&#xff1a; package mainimport ("encoding/json""fmt""io""net/http" )type Response struct {Code int json:"code"Data any json:"dat…

Spring中配置文件方式来配置实现数据源

我的后端学习大纲 我Spring学习大纲 1.1.数据源&#xff08;连接池&#xff09;的作用&#xff1a; 1.数据源&#xff08;连接池&#xff09;是提高程序性能而出现的2.数据源的使用步骤 &#xff1a; 创建数据源对象&#xff0c;在对象创建的时候会初始化部分连接资源使用连接…

【jvm】堆的内部结构

目录 1. 说明2. 年轻代&#xff08;Young Generation&#xff09;2.1 说明2.2 Eden区2.3 Survivor区 3. 老年代&#xff08;Old Generation&#xff09;3.1 说明3.2 对象存放3.3 垃圾回收 4. jdk7及之前5. jdk8及之后 1. 说明 1.JVM堆的内部结构主要包括年轻代&#xff08;You…

录屏软件推荐,4个工具助你高效录屏。

不同的录屏软件具有不同的特点和优势&#xff0c;如果只是偶尔需要录制&#xff0c;Win10 自带的录制功能就很方便&#xff1b;如果需要更加专业的录制和编辑功能&#xff0c;我可以推荐几款功能更加多样也效果较好的第三方软件。 1、福昕高清录屏 直达&#xff1a;www.foxits…

SVM(支持向量机)

SVM&#xff08;支持向量机&#xff09; 引言 支持向量机(Support Vector Machine,SVM)&#xff0c;可以用来解答二分类问题。支持向量(Support Vector)&#xff1a;把划分数据的决策边界叫做超平面&#xff0c;点到超平面的距离叫做间隔。在SVM中&#xff0c;距离超平面最近…

基于neo4j的新冠治疗和新冠患者轨迹的知识图谱问答系统

毕业设计还在苦恼选题&#xff1f;想做一个兼具前沿性和实用性的技术项目&#xff1f;了解下这款基于Neo4j的新冠治疗和患者轨迹的知识图谱问答系统吧&#xff01; 系统可以实现两大功能模块&#xff1a;新冠医疗信息和患者活动轨迹的展示与问答。通过图谱技术&#xff0c;你可…

VBA技术资料MF219:创建一个新的类型模块

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

【方波转正弦波谐波二阶】2022-6-10

缘由怎么用555时基电路将方波转换为正弦波&#xff1f;-其他-CSDN问答 可参带通滤波器电路图大全&#xff08;三款带通滤波器电路设计原理图详解&#xff09; - 全文 - 应用电子电路 - 电子发烧友网

《关于构图问题》

这是一本讲绘画技巧的书&#xff0c;但仔细琢磨体现出不易察觉的东方哲学思想。中国画讲究意境与留白&#xff0c;留白不代表“空”&#xff0c;而是代表对“实”的延伸&#xff0c;留下瞎想空间&#xff0c;实现对“有限&#xff08;实&#xff09;”的超越。 总论 文艺是人们…

演员王丹妮化身岛屿姐姐 开启少年们的欢乐挑战之旅

全民海岛真人秀《岛屿少年》正在持续热播中&#xff0c;少年们迎来了“茶嵛饭后”⻩⻥馆的开业日&#xff0c;知名演员王丹妮以岛屿姐姐的身份&#xff0c;悄然降临此地&#xff0c;为岛屿少年们带来了一场别开生面的考验。 在餐厅正式开业前夕&#xff0c;王丹妮巧妙地伪装成普…

【Spark+Hive大数据】基于spark抖音数据分析预测舆情系统(完整系统源码+数据库+开发笔记+详细部署教程)✅

目录 【SparkHive大数据】基于spark抖音数据分析预测舆情系统&#xff08;完整系统源码数据库开发笔记详细部署教程&#xff09;✅ 一、项目背景 二、研究目的 三、项目意义 四、项目功能 五、项目创新点​​​​​​​ 六、算法介绍 七、项目展示 八、启动文档 九、…

Android Kotlin中协程详解

博主前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住也分享一下给大家&#xff0c; &#x1f449;点击跳转到教程 前言 Kotlin协程介绍&#xff1a; Kotlin 协程是 Kotlin 语言中的一种用于处理异步编程的机制。它提供了一…

Chromium127调试指南 Windows篇 - 安装C++扩展与配置(五)

前言 在前面的文章中&#xff0c;我们已经安装了Visual Studio Code&#xff08;VS Code&#xff09;并配置了基本的扩展。现在&#xff0c;我们将进一步优化我们的开发环境&#xff0c;重点关注C相关的依赖扩展。这些扩展对于在VS Code中高效开发和调试Chromium项目至关重要。…

如何在 Linux 中对 USB 驱动器进行分区

如何在 Linux 中对 USB 驱动器进行分区 一、说明 为了在 Linux 上访问 USB 驱动器&#xff0c;它需要有一个或多个分区。由于 USB 驱动器通常相对较小&#xff0c;仅用于临时存储或轻松传输文件&#xff0c;因此绝大多数用户会选择只配置一个跨越整个 USB 磁盘的分区。但是&a…

基于Django+python的车牌识别系统设计与实现(带文档)

项目运行 需要先安装Python的相关依赖&#xff1a;pymysql&#xff0c;Django3.2.8&#xff0c;pillow 使用pip install 安装 第一步&#xff1a;创建数据库 第二步&#xff1a;执行SQL语句&#xff0c;.sql文件&#xff0c;运行该文件中的SQL语句 第三步&#xff1a;修改源…

Unity C#脚本的热更新

以下内容是根据Unity 2020.1.0f1版本进行编写的   目前游戏开发厂商主流还是使用lua框架来进行热更&#xff0c;如xlua&#xff0c;tolua等&#xff0c;也有的小游戏是直接整包更新&#xff0c;这种小游戏的包体很小&#xff0c;代码是用C#写的&#xff1b;还有的游戏就是通过…