leetcode 数据库刷题笔记,持续更新中

📅 发布时间:2026/7/6 11:03:50 👁️ 浏览次数:
leetcode 数据库刷题笔记,持续更新中
刷的是leetcode 高频 SQL 50 题基础版个别简单的题型没有记录只记录了自己认为有需要学习的题文章目录570.至少有5名直接下属的经理1934.确认率197.上升的温度1661.每台机器的进程平均运行时间1667.修复表中的名字代码解释577.员工奖金1280.学生们参加各科测试的次数代码关键解释1. 为什么用 CROSS JOIN全连接2. 为什么用 LEFT JOIN 关联考试表3. COUNT() 为什么用 exam.subject_name 而不是 exam.student_id4. GROUP BY 必须包含哪些字段易错1251.平均售价总结1075.项目员工 11633.各赛事的用户注册率1141.查询近30天活跃用户数1084.销售分析III1527.患某种疾病的患者570.至少有5名直接下属的经理570. 至少有5名直接下属的经理 - 力扣LeetCodeselecte2.namefromEmployee e1rightjoinEmployee e2one1.managerIde2.idgroupbye2.idhavingcount(e1.id)5-- e1是员工表e2是经理表1934.确认率1934. 确认率 - 力扣LeetCode# Write your MySQL query statement below-- select si.user_id,round(sum(confirm.actionconfirmed)/count(*),2) as confirmation_rate-- from Signups si left join Confirmations confirm on si.user_idconfirm.user_id-- group by si.user_id-- 错没有处理好‘没有请求任何确认消息的用户’-- 2026.2.28selectsi.user_id,round(avg(if(c.actionconfirmed,1,0)),2)asconfirmation_ratefromSignups sileftjoinConfirmations consi.user_idc.user_idgroupbysi.user_id-- avg(if(c.actionconfirmed,1,0))会直接计算确认率这些数字的 平均值 (AVG) 恰好就是确认率。-- 使用case whenselectsi.user_id,round(avg(casewhenc.actionconfirmedthen1else0end),2)asconfirmation_ratefromSignups sileftjoinConfirmations consi.user_idc.user_idgroupbysi.user_id-- 2026.3.6selects.user_id,round(ifnull(avg(actionconfirmed),0),2)confirmation_ratefromSignups sleftjoinConfirmations cons.user_idc.user_idgroupbys.user_idavg(if(c.action‘confirmed’,1,0))会直接计算确认率这些数字的 平均值 (AVG) 恰好就是确认率197.上升的温度-- 找出与之前昨天的日期相比温度更高的所有日期的 idselectw_af.idfromWeather w_bejoinWeather w_afonw_af.recordDatedate_add(w_be.recordDate,interval1day)wherew_af.temperaturew_be.temperature-- 连接条件也可以写成w_be.recordDatedate_sub(w_af.recordDate,interval 1 day)DATE_ADD和DATE_SUB是 MySQL 中用于日期 / 时间增减计算的核心函数DATE_ADD(date, INTERVAL expr type)给指定日期date增加一个时间间隔exprDATE_SUB(date, INTERVAL expr type)给指定日期date减少一个时间间隔expr。1661.每台机器的进程平均运行时间1661. 每台机器的进程平均运行时间 - 力扣LeetCode-- 结果表必须包含machine_id机器ID 和对应的 average time平均耗时 别名 processing_time且四舍五入保留3位小数。机器 0 的平均耗时: ((1.520 - 0.712) (4.120 - 3.140)) / 2 0.894selectmachine_id,round(avg(time),3)processing_timefrom(selectmachine_id,process_id,max(timestamp)-min(timestamp)timefromactivitygroupbymachine_id,process_id)timegroupbymachine_id1667.修复表中的名字1667. 修复表中的名字 - 力扣LeetCodeselectuser_id,concat(upper(substring(name,1,1)),lower(substring(name,2)))namefromUsersorderbyuser_id代码解释SUBSTRING(name, 1, 1)截取name字段的第 1 个字符首字母SUBSTRING(字段, 起始位置, 截取长度)。UPPER(…)将截取的首字母转为大写。SUBSTRING(name, 2)截取name字段从第 2 个字符开始的所有剩余字符省略长度参数表示截取到末尾。LOWER(…)将剩余字符统一转为小写。CONCAT(…)将大写首字母和小写剩余字符拼接成完整的名字。ORDER BY user_id按照用户 ID 升序排列结果题目要求的输出格式。577.员工奖金577. 员工奖金 - 力扣LeetCodeselecte.name,b.bonusfromEmployee eleftjoinBonus bone.empIdb.empIdwhereb.bonus1000orb.bonusisnull注意判断一个是否为空时不能使用等于号要使用 is nullNULL 判断的正确写法❌ 错误b.bonus null永远不成立✅ 正确b.bonus IS NULL专门用于判断 NULL 值1280.学生们参加各科测试的次数1280. 学生们参加各科测试的次数 - 力扣LeetCodeselectstu.student_id,stu.student_name,sub.subject_name,count(exam.subject_name)asattended_examsfrom(Students stu,Subjects sub)leftjoinExaminations exam-- Students stu join Subjects sub left join Examinations exam先进行全连接再进行成绩表的左连接onstu.student_idexam.student_idandsub.subject_nameexam.subject_namegroupbystu.student_id,stu.student_name,sub.subject_nameorderbystu.student_id,sub.subject_name代码关键解释1. 为什么用CROSS JOIN全连接Students和Subjects做CROSS JOIN笛卡尔积会生成所有学生 × 所有科目的组合比如 3 个学生、2 个科目会生成 6 行这是实现 “每个学生每科都显示” 的基础。2. 为什么用LEFT JOIN关联考试表左连接可以保留 “学生 科目” 的所有组合即使该学生没参加该科目考试此时exam表的字段都是 NULL。3.COUNT()为什么用exam.subject_name而不是exam.student_idCOUNT(字段)会统计该字段非 NULL 的行数如果学生参加了考试exam.subject_name非 NULLCOUNT1如果没参加exam.subject_name是 NULLCOUNT0如果用 COUNT(*)会统计所有行包括 NULL结果永远是 1就错了。4. GROUP BY 必须包含哪些字段易错MySQL 中SELECT里的非聚合字段student_id/student_name/subject_name必须出现在GROUP BY中否则会报错或结果混乱。1251.平均售价1251. 平均售价 - 力扣LeetCodeselectp.product_id,ifnull(round(sum(units*price)/sum(units),2),0)average_pricefromprices pleftjoinunitssold uonp.product_idu.product_idandu.purchase_datebetweenstart_dateandend_date-- where u.purchase_date between start_date and end_date-- 这是我原来写的错误的代码先用where过滤后就没有null的行了-- 在想保存就没有了所以应该改成筛选条件没有的变为null-- 不是直接过滤掉null的行后续还需要注意这个地方groupbyproduct_id总结核心错误WHERE 条件过滤了 u 表为空的行LEFT JOIN 失去意义需将时间条件移到 ON 子句关键原则LEFT JOIN 时“过滤右表u的条件” 写在 ON 子句“过滤左表p的条件” 写在 WHERE 子句IFNULL 生效前提必须先保留 u 表为空的行才能通过 IFNULL 将均价转为 0。1075.项目员工 11075. 项目员工 I - 力扣LeetCodeselectproject_id,round(sum(experience_years)/count(p.employee_id),2)average_yearsfromproject p,employee ewherep.employee_ide.employee_idgroupbyproject_id1633.各赛事的用户注册率1633. 各赛事的用户注册率 - 力扣LeetCodeselectcontest_id,round(count(r.user_id)/(selectcount(*)fromusers)*100,2)percentagefromusers ujoinregister ronu.user_idr.user_idgroupbycontest_idorderbypercentagedesc,contest_idasc;select count(*) from users使用了动态子查询确保数量跟随表格一起变化我发现了最后输出的前缀是什么就根据什么进行分组比如group by contest_id输出contest_id就不会有重复因为已经按照这个进行分组了1141.查询近30天活跃用户数1141. 查询近30天活跃用户数 - 力扣LeetCodeselectactivity_dateday,count(distinctuser_id)active_usersfromactivitygroupbyactivity_datehavingactivity_datebetween2019-06-28and2019-07-27selectactivity_dateday,count(distinctuser_id)active_usersfromactivitygroupbyactivity_datehavingactivity_datebetweendate_sub(2019-07-28,interval30day)and2019-07-27-- 后面这个时间更短603ms统计每天的独立用户数量count(distinct user_id)having语句再group by 后面进行筛选where语句在group by 前面进行筛选1084.销售分析III1084. 销售分析 III - 力扣LeetCodeselects.product_id,product_namefromproduct pjoinsales sonp.product_ids.product_idgroupbyp.product_idhavingmin(sale_date)2019-01-01andmax(sale_date)2019-03-31having分组后筛选该产品所有销售日期的极值都在目标区间内使用max和min值可以判断有多种情况下的产品的相对应条件可以筛选只满足条件的内容-- all错误用法,all必须用在子查询前面不能想怎么用就怎么用where错误用法all(selectsale_datefromSales)between2019-01-01and2019-03-311527.患某种疾病的患者1527. 患某种疾病的患者 - 力扣LeetCodeselectpatient_id,patient_name,conditionsfromPatientswhereconditionslikeDIAB1%orconditionslike% DIAB1%判断某一项的内容是否符合某一种格式的时候多多想到like 占位符-是模糊匹配的作用_匹配单个字符%匹配多个字符