SQL学习笔记7:综合查询与高级技巧全解析 + LeetCode实战

重要知识点(题目中提取)

UNION/UNION ALL

SELECT column1, column2, ...

FROM table1

UNION

SELECT column1, column2, ...

FROM table2;

SELECT column1, column2, ...

FROM table1

UNION ALL

SELECT column1, column2, ...

FROM table2;

两者主要的区别在于是否重复

IFNULL

IFNULL(expression, alt_value)

定义变量

MySQL 中的变量

用户变量(会话级)
  • @ 开头,无需声明,直接赋值使用。

  • 作用域为当前会话。

sql 复制代码
SET @var = 10;
SELECT @var;  -- 输出 10

SELECT @var := column_name FROM table_name LIMIT 1;
局部变量(存储过程/函数中)
  • 使用 DECLARE 声明,作用域限于代码块。
sql 复制代码
DELIMITER $$
CREATE PROCEDURE example()
BEGIN
    DECLARE v_count INT DEFAULT 0;
    SET v_count = 10;
    SELECT v_count;
END$$
DELIMITER ;
系统变量
  • @@ 开头,分为全局和会话级。
sql 复制代码
SELECT @@version;              -- 当前版本
SET GLOBAL max_connections = 200;

时间函数

1. 获取当前时间

用于获取服务器当前的日期或时间。

数据库 函数/语句 说明
MySQL NOW(), CURDATE(), CURTIME() 分别获取日期时间、日期、时间
SQL Server GETDATE(), SYSDATETIME() 获取当前数据库系统时间
Oracle SYSDATE, SYSTIMESTAMP 分别获取日期时间和带时戳时间
PostgreSQL NOW(), CURRENT_DATE 标准 SQL 兼容性好

示例:

sql 复制代码
SELECT NOW(); -- MySQL/PG
SELECT GETDATE(); -- SQL Server
SELECT SYSDATE FROM DUAL; -- Oracle
2. 提取时间部分

从时间字段中提取年、月、日、小时等。

  • MySQL: YEAR(date), MONTH(date), DAY(date), HOUR(time)

  • SQL Server: DATEPART(YEAR, date), YEAR(date)

  • Oracle: EXTRACT(YEAR FROM date), TO_CHAR(date, 'YYYY')

  • PostgreSQL: EXTRACT(YEAR FROM date), DATE_PART('year', date)

示例(获取年份):

sql 复制代码
SELECT YEAR(order_date) FROM orders; -- MySQL/SQL Server
SELECT EXTRACT(YEAR FROM order_date) FROM orders; -- Oracle/PG
3. 格式化与转换

将时间转为字符串,或将字符串转为时间类型。

数据库 时间转字符串 字符串转时间
MySQL DATE_FORMAT(date, '%Y-%m-%d') STR_TO_DATE(str, '%Y-%m-%d')
SQL Server CONVERT(VARCHAR, date, 120) CONVERT(DATETIME, str, 120)
Oracle TO_CHAR(date, 'YYYY-MM-DD') TO_DATE(str, 'YYYY-MM-DD')
PostgreSQL TO_CHAR(date, 'YYYY-MM-DD') TO_TIMESTAMP(str, 'YYYY-MM-DD')

示例:

sql 复制代码
-- MySQL: 将时间格式化为 '2023-10-01'
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d');
4. 时间计算(加减与差值)

用于计算时间间隔或增减时间。

  • 增加/减少时间:

    • MySQL: DATE_ADD(date, INTERVAL 7 DAY), date + INTERVAL 1 MONTH

    • SQL Server: DATEADD(DAY, 7, date)

    • Oracle: date + 7 (天), ADD_MONTHS(date, 1)

    • PostgreSQL: date + INTERVAL '7 days'

  • 计算差值:

    • MySQL: DATEDIFF(date1, date2) (返回天数)

    • SQL Server: DATEDIFF(DAY, date1, date2)

    • Oracle: date1 - date2 (返回天数,含小数)

    • PostgreSQL: AGE(date1, date2) 或直接相减

示例(查询最近 7 天的数据):

sql 复制代码
-- MySQL
SELECT * FROM table WHERE date_col >= DATE_SUB(NOW(), INTERVAL 7 DAY);

-- SQL Server
SELECT * FROM table WHERE date_col >= DATEADD(DAY, -7, GETDATE());

-- Oracle
SELECT * FROM table WHERE date_col >= SYSDATE - 7;

LeetCodeSQL 重要50题重点习题(考点:高级查询连接和子查询 难度:简单-中等 完成进度:41/50)

1.1164指定日期的产品价格

sql 复制代码
-- 这个是我自己写的答案,对照着官方题解,需要进行的改进
-- 更改的地方在于直接使用子查询,不应该使用连接
-- 直接写ifnull()
select
    Product_ID.product_id,
    (case when Price_Table.new_price is not NULL then Price_Table.new_price else 10 end) as price
from (select distinct
    product_id,
    (case when 1=1 then 10 end) as origin_price
from Products) as Product_ID
left join (select 
    Max_Date.product_id,
    Products.new_price
from
(select
    product_id,
    max(date(change_date)) as max_date
from Products
where date(change_date) <= date('2019-08-16') 
group by product_id) as Max_Date
left join Products 
on Max_Date.product_id=Products.product_id
and Max_Date.max_date=Products.change_date) as Price_Table
on Product_ID.product_id=Price_Table.product_id
;
-- 官方题解
select p1.product_id, ifnull(p2.new_price, 10) as price
from (
    select distinct product_id
    from products
) as p1 -- 所有的产品
left join (
    select product_id, new_price 
    from products
    where (product_id, change_date) in (
        select product_id, max(change_date)
        from products
        where change_date <= '2019-08-16'
        group by product_id
    )
) as p2 -- 在 2019-08-16 之前有过修改的产品和最新的价格
on p1.product_id = p2.product_id;

2.1907按分类统计薪水

sql 复制代码
-- 这道题需要掌握的是UNION,记得抽空复习一下呀
SELECT 
    'Low Salary' AS category,
    SUM(CASE WHEN income < 20000 THEN 1 ELSE 0 END) AS accounts_count
FROM 
    Accounts
    
UNION
SELECT  
    'Average Salary' category,
    SUM(CASE WHEN income >= 20000 AND income <= 50000 THEN 1 ELSE 0 END) 
    AS accounts_count
FROM 
    Accounts

UNION
SELECT 
    'High Salary' category,
    SUM(CASE WHEN income > 50000 THEN 1 ELSE 0 END) AS accounts_count
FROM 
    Accounts

3.1204最后一个能进入巴士的人

sql 复制代码
select
    person_name
from Queue
where turn=(
    select max(t)
    from(select
    turn as t,
    person_id,
    weight,
    (select sum(weight) from Queue where turn<=t) as total_weight
from Queue
having total_weight<=1000
order by t) as T
) 
-- 改进
SELECT a.person_name
FROM Queue a, Queue b
WHERE a.turn >= b.turn
GROUP BY a.person_id HAVING SUM(b.weight) <= 1000
ORDER BY a.turn DESC
LIMIT 1
-- 把定义变量的方式进行学习一下
SELECT a.person_name
FROM (
        SELECT person_name, @pre := @pre + weight AS weight
        FROM Queue, (SELECT @pre := 0) as tmp
        ORDER BY turn
) as s
WHERE a.weight <= 1000
ORDER BY a.weight DESC
LIMIT 1

4.1978上级经理已离职员工

python 复制代码
# Write your MySQL query statement below
select
    employee_id
from Employees
where salary<30000
and manager_id not in (select employee_id from Employees)
order by employee_id;

5.626换座位

sql 复制代码
# Write your MySQL query statement below
#复习一下union用法
/*
这是对于具有重复值
SELECT column1, column2, ...
FROM table1
UNION ALL
SELECT column1, column2, ...
FROM table2;
这是不具有重复值
SELECT column1, column2, ...
FROM table1
UNION
SELECT column1, column2, ...
FROM table2;
*/
#直接加1
/*

*/

SELECT 
    case
    when id = (SELECT max(id) FROM Seat) then id else id+1 end as id,
    student
FROM Seat
WHERE id%2 <> 0
UNION
SELECT
    id-1 as id,
    student
FROM Seat
WHERE id%2 = 0
order by id;

6.1341电影评分

sql 复制代码
#查找评论电影数量最多的用户名。如果出现平局,返回字典序较小的用户名。
#使用count
/*

#查找在 February 2020 平均评分最高 的电影名称。如果出现平局,返回字典序较小的电影名称。

*/
(SELECT
    name as results
FROM (
SELECT
    MovieRating.user_id,
    Users.name,
    COUNT(MovieRating.user_id) as id_count
FROM MovieRating
left join Users
on MovieRating.user_id=Users.user_id
GROUP BY user_id
ORDER BY id_count DESC,name) as Max_Comments
limit 1)
UNION ALL
(SELECT
    title as results
FROM(
SELECT
    MovieRating.movie_id,
    Movies.title,
    avg(MovieRating.rating) as avg_rating
FROM MovieRating
left join Movies
on MovieRating.movie_id=Movies.movie_id
WHERE date(created_at) >= date('2020-02-01') and date(created_at) <= date('2020-02-29')
GROUP BY movie_id
ORDER BY avg_rating DESC, title) as Max_Rating
limit 1)

7.1321餐馆营业额变化增长

sql 复制代码
# Write your MySQL query statement below
# 这道题和之前那道题目有共同点
# 先算一下一共可以有多少个星期:以案列为例子,假设有11天,那一共有四个日期可以算星期,所以可以有

/*SELECT
    visited_on,
    amount,
    round(amount/7, 2) as average_amount
FROM (
SELECT
    v_end as visited_on,
    (SELECT sum(amount) FROM Customer WHERE DATE(visited_on) BETWEEN DATE(v_begin) AND DATE(v_end)) as amount
FROM (
SELECT DISTINCT
    visited_on as v_end,
    DATE_SUB(visited_on, INTERVAL 6 DAY) as V_begin
FROM Customer
WHERE DATE(visited_on)>DATE_SUB((SELECT MAX(DATE(visited_on)) FROM Customer), INTERVAL 4 DAY) 
ORDER BY visited_on DESC
) as Date_week) as DATE_Amount
ORDER BY visited_on
*/
SELECT
    visited_on,
    amount,
    round(amount/7, 2) as average_amount
FROM (
SELECT
    v_end as visited_on,
    (SELECT sum(amount) FROM Customer WHERE DATE(visited_on) BETWEEN DATE(V_begin) AND DATE(v_end)) as amount
FROM (
SELECT DISTINCT
    visited_on as v_end,
    DATE_SUB(visited_on, INTERVAL 6 DAY) as V_begin
FROM Customer
WHERE DATE_SUB(visited_on, INTERVAL 6 DAY) in (SELECT visited_on FROM Customer)
ORDER BY visited_on DESC) as Date_week) as DATE_Amount
ORDER BY visited_on

8.1667修复表中的名字

以上SQL语句使用了三个函数来实现首字母大写的效果:

-- SUBSTRING(name, 1, 1):提取出字符串的第一个字符

-- UPPER(SUBSTRING(name, 1, 1)):将第一个字符转换为大写

-- LOWER(SUBSTRING(name, 2)):将第二个字符开始的字符串转换为小写

-- CONCAT函数将前两个处理后的字符串拼接在一起,得到首字母大写的字符串

sql 复制代码
# Write your MySQL query statement below
SELECT
    user_id,
    CONCAT(UPPER(SUBSTRING(name, 1, 1)), LOWER(SUBSTRING(name, 2))) as name
FROM Users
ORDER BY user_id
相关推荐
GocNeverGiveUp2 小时前
大模型学习1
学习
我命由我123452 小时前
Photoshop - Photoshop 工具栏(69)前景色和背景色
学习·ui·职场和发展·求职招聘·职场发展·学习方法·photoshop
菩提小狗2 小时前
第17天:信息打点-语言框架&开发组件&FastJson&Shiro&Log4j_笔记|小迪安全2023-2024|web安全|渗透测试|
笔记·安全·log4j
强子感冒了2 小时前
JSON和XML学习笔记
xml·学习·json
愚公搬代码3 小时前
【愚公系列】《数据可视化分析与实践》019-数据集(自定义SQL数据集)
数据库·sql·信息可视化
我命由我123453 小时前
Photoshop - Photoshop 工具栏(70)以快速蒙版/标准模式编辑
学习·ui·职场和发展·求职招聘·职场发展·学习方法·photoshop
蒸蒸yyyyzwd3 小时前
后端学习笔记计网
笔记·学习
red_redemption3 小时前
自由学习记录(120)
学习
lzhdim3 小时前
SQL 入门 2:LIKE、正则、 ORDER BY 与LIMIT
数据库·sql·mysql