【数据分析】【SQL】学习笔记——sqlzoo(戴师兄)

目录

 【基础语句】

主知识点一:SELECT & FROM

【标准语法】

【SELECT中使用DISTINCT 进行去重】

【SELECT中计算字段的运用】

主知识点二:WHERE

【运算符一览】

【模糊查询like】

【多条件查询】

主知识点三:ORDER BY

主知识点四:LIMIT

主知识点五:聚合函数 & GROUP BY

【聚合函数】

【GROUP BY 单独使用】

【聚合函数和GROUP BY联用1】

【聚合函数和GROUP BY联用2】

主知识点六:HAVING & 简单运行原理

主知识点七:部分常见函数

【数学函数】

【字符串函数】

【数据类型转换函数】

【日期时间函数】

【条件判断函数】——根据满足不同条件,执行相应流程

【高级语句】

主知识点八:窗口函数(从原来的表中提出一个新的临时表)

【排序窗口函数语法】

【偏移分析函数语法】

主知识点九:表连接

【JOIN】 列连接

【UNION】行连接

主知识点十:子查询

【练习】


基于sqlzoo的mysql数据库引擎,只学习SQL语句的查询语句部分

SQL查询语句语法结构和运行顺序

  • 语法结构:select--from--where--group by--having--order by--limit
  • 运行顺序:from--where--group by--having--order by--limit--select

 【基础语句】

主知识点一:SELECT & FROM

【标准语法】

  • 基础语法

SELECT 字段名  决定这一段查询最后展示的字段    

FROM 表名  指定这段查询语句设计的数据来源

这是一段查询语句中必不可少的两个核心语句,SELECT 和 FROM 分别十两个核心语句中的关键字

  • 查询所有列

SELECT  *      

FROM 表名 

  • 别名语法

SELECT  字段名  as(可省略) 别名    

FROM 表名

【SELECT中使用DISTINCT 进行去重】

但是是对完全相同的行数据进行去重,不能指定字段名

注明是对SELECT出来的字段进行完全相同的行数据进行去重 不是原表

【SELECT中计算字段的运用】

字段名可以是表中有的字段名的简单计算式

主知识点二:WHERE

标准语法

SELECT 字段名

FROM 表名

[WHERE 表达式]    限定查询行必须满足的条件 进行筛选 是可选项

【运算符一览】

其中' is null ',用于查询空值(NULL),空值不同于0,也不同于null字符串

  • 空值

  • null字符串

【模糊查询like】

【多条件查询】

and且 or或 and的优先级大于or 

补充:

u.pay_method IS NULL   和   u.pay_method 是空字符串不一样吗?

u.pay_method IS NULL 和 u.pay_method = ''(或 u.pay_method <> '' 中所涉及的空字符串判断)不一样,它们代表了不同的情况,下面从概念、判断方式和实际应用等方面进行详细解释:

概念区别

  • u.pay_method IS NULLNULL 在 SQL 里表示 “未知” 或 “缺失的值”,意味着该字段没有被赋予任何值。它并不是一个具体的值,而是一种特殊的状态,表示数据的缺失。
  • u.pay_method = '':这里的 '' 代表空字符串,是一个明确的值,即该字段被赋予了一个长度为 0 的字符串。
  • u.pay_method <> '' 是一个条件表达式,用于筛选出 pay_method 字段的值不为空字符串的记录。
  • <>:这是 SQL 中的比较运算符,意思是 “不等于”。不同的数据库系统可能有不同的表示方式,例如在某些数据库中也可以用 != 来表示 “不等于”。
  • '':表示空字符串。

主知识点三:ORDER BY

SELECT 字段名

FROM 表名

[WHERE 表达式]

[ORDER BY 字段名 ASC/DESC]   对被查询出的结果集,指定依据字段排序 asc升序 desc降序 不写则默认升序排序 是可选项

主知识点四:LIMIT

SELECT 字段名

FROM 表名

[WHERE 表达式]

[ORDER BY 字段名 ASC/DESC]

[LIMIT [位置偏移量] 行数] 限制查询结果集显示的行数,是可选项,行数是子句中的必选参数,参数位置偏移量是可选参数

【查询结果返回前n行】

SELECT 字段名

FROM 表名

[WHERE 表达式]

[ORDER BY 字段名 ASC/DESC]

[LIMIT n]

【查询结果返回第x + 1行开始的 n 行到 x + n 行】

SELECT 字段名

FROM 表名

[WHERE 表达式]

[ORDER BY 字段名 ASC/DESC]

[LIMIT x, n]

主知识点五:聚合函数 & GROUP BY

标准语法:

SELECT 字段名

FROM 表名

[WHERE 表达式]

[GROUP BY 字段名1]  是可选项,使用该子句可依据相同字段值分组后进行聚合运算,常和聚合函数连用

[ORDER BY 字段名 ASC/DESC]

[LIMIT [位置偏移量] 行数]

  • 【聚合函数】

 聚合函数适用于需要获取数据的汇总信息,例如某字段行数,某字段平均值,某字段中最大最小数等

  • 【GROUP BY 单独使用】

 可以实现单独对字段continent进行去重的效果

world(name, continent, area, population, gdp)

SELECT continent
FROM world
GROUP BY continent;

注明:对于continent中的每一组,由于 SELECT 子句中没有使用聚合函数(如 COUNTSUMAVG 等),数据库只会从每组中选取一个 continent 值作为结果,从而实现了去重的效果

但是如果有使用聚合函数,是不去重的, 如果这里是COUNT(continent) 那么会显示每个大洲出现的次数总和,如果要输出大洲数需要添加DISTINCT :COUNT( DISTINCT continent)

  • 【聚合函数和GROUP BY联用1】

[例题24] 查询每个大洲(continent)和大洲内的国家(name)数量

SELECT continent, COUNT(name)
FROM world
GROUP BY continent
  •  【聚合函数和GROUP BY联用2】

nobel( yr, subject, winner)

[例题25] 查询2013至2015年每年每个科目的获奖人数,结果按年份从大到小,人数从大到小排序

SELECT yr, subject, COUNT(winner)
FROM nobel
WHERE yr between 2013 and 2015
GROUP BY yr, subject
ORDER BY yr DESC, COUNT(winner) DESC

 使用GROUP BY子句时,SELECT只能使用GROUP BY 和 聚合函数引用过字段

GROUP BY中的字段要考虑窗口函数和所有查询语段中的PARTITION BY ORDER BY字段

主知识点六:HAVING & 简单运行原理

标准语法:

SELECT 字段名

FROM 表名

[WHERE 表达式]

[GROUP BY 字段名1]  

[HAVING 表达式]  是可选项,限定分组聚合后(即group by分组后)的查询行进行筛选

[ORDER BY 字段名 ASC/DESC]

[LIMIT [位置偏移量] 行数]

只有使用了 GROUP BY 子句后才会使用HAVING子句,HAVING子句不能脱离GROUP BY 子句单独使用,因为HAVING子句本质上是对GROUP BY分组的筛选

HAVING的表达式和WHERE的表达式基本相同,但是HAVING的表达式中可以使用聚合函数,WHERE的表达式中不可以,因为WHERE是对原表的行数据进行筛选,HAVING是对GROUP BY 分组后的数据进行筛选 

主知识点七:部分常见函数

【数学函数】

 1. round(x, y)——四舍五入函数

  • round函数对x值进行四舍五入,精确到小数点后y位
  • y为负值时,保留小数点左边相应的位数为0,不进行四舍五入
  • 例如:round(3.15,1)返回3.2,round(14.15,-1)返回10

2.TRUNCATE(x,y)截断函数,只保留小数x的y位小数 

TRUNCATE(3.1415926, 3)

 返回3.141

3. 取整函数 

  • CEILING 函数向上取整,返回大于或等于输入值的最小整数CEILING(3.14)返回4
  • FLOOR 函数向下取整,返回小于或等于输入值的最大整数FLOOR(3.14)返回3

【字符串函数】

1. concat(s1,s2,...)——连接字符串函数

  • concat函数返回连接参数s1、s2等产生的字符串
  • 任一参数为null时,则返回null
  • 例如:concat('My',' ','SQL')返回My SQL,concat('My',null,'SQL')返回null

2. replace(s,s1,s2)——替换函数

  • replace函数使用字符串s2代替s中所有的s1
  • 例如:replace('MySQLMySQL','SQL','sql')返回MysqlMysql

3. left(s,n)——从左截取字符串一部分的函数

  • 返回字符串s最左边n个字符

4. right(s,n)——从右截取字符串一部分的函数

  • 返回字符串s最右边n个字符

5. substring(s,n,len)——从指定位置截取字符串一部分的函数

  • 返回字符串s从第n个字符起取长度为len的子字符串,n也可以为负值,则从倒数第n个字符起取长度为len的子字符串,没有len值则取从第n个字符起到最后一位
  • 例如:left('abcdefg',3)返回abc,right('abcdefg',3)返回efg,substring('abcdefg',2,3)返回bcd,substring('abcdefg',-2,3)返回fg,substring('abcdefg',2)返回bcdefg

6. UPPER() 全取大写字母 

【数据类型转换函数】

1. cast(x as type)——转换数据类型的函数

  • cast函数将一个类型的x值转换为另一个类型的值
  • type参数可以填写char(n)、date、time、datetime、decimal等转换为对应的数据类型

【日期时间函数】

1. year(date)——获取年的函数

2. month(date)——获取月的函数

3. day(date)——获取日的函数

  • year('2021-08-03')返回2021,month('2021-08-03')返回8,day('2021-08-03')返回3
  • 注意YEAR() 和 MONTH() 这类日期提取函数,需要传入标准的日期类型值才能正常发挥作用,而像 2025-01 这种格式并非标准日期类型,直接使用这些函数处理它会出现问题。

CURDATE() 函数主要用于返回当前系统日期,通常以 YYYY-MM-DD 格式输出。该函数无需传入参数,调用时直接使用函数名即可 

4. date_add(date,interval expr type)——对指定起始时间进行加操作

5. date_sub(date,interval expr type)——对指定起始时间进行减操作

  • 例如:date_add('2021-08-03 23:59:59',interval 1 second)返回2021-08-04 24:00:00,date_sub('2021-08-03 23:59:59',interval 2 month)返回2021-06-03 23:59:59

6. datediff(date1,date2)——计算两个日期之间间隔的天数

  • datediff函数由date1-date2计算出间隔的时间,只有date的日期部分参与计算,时间不参与
  • 例如:datediff('2021-06-08','2021-06-01')返回7,datediff('2021-06-08 23:59:59','2021-06-01 21:00:00')返回7,datediff('2021-06-01','2021-06-08')返回-7

 7.TIMESTAMPDIFF(unit, start_datetime, end_datetime)

  • unit 可以是 SECONDMINUTEHOURDAY 等,表示时间差的单位。这里我们使用 SECOND 计算秒数差,然后通过一系列的数学运算和字符串拼接得到时分秒格式。

8. date_format(date,format)——将日期和时间格式化 

 根据format指定的格式显示date值

例如:

  • date_format('2018-06-01 16:23:12','%b %d %Y %h:%i %p')返回Jun 01 2018 04:23 PM
  • date_format('2018-06-01 16:23:12','%Y/%d/%m')返回2018/01/06 

【条件判断函数】——根据满足不同条件,执行相应流程

1. if(expr,v1,v2)

  • 如果表达式expr是true返回值v1,否则返回v2
  • 例如:if(1<2,'Y','N')返回Y,if(1>2,'Y','N')返回N

在 MySQL 中可以使用 IFNULL 函数替代 if 函数,代码可能会写成 

sum(IFNULL(order_price, 0)) as 

即如果order_price列中有空值即替换成0

2. case when

          case expr when v1 then r1 [when v2 then r2] ...[else rn]  

end

case 2 
when 1 
then 'one' 
when 2 
then 'two' 
else 'more' 
end 

/返回two

 case when v1 then r1 [when v2 then r2]...[else rn]

    end

case 
when 1<0 
then 'T' 
else 'F' 
end

/返回F

【高级语句】

主知识点八:窗口函数(从原来的表中提出一个新的临时表)

partition by指定分区依据,order by指定排序依据 

【排序窗口函数语法】

  • rank()over([partition by 字段名] order by 字段名 asc|desc)  

 跳跃式排序——若数值为99,99,90,89 则排名1,1,3,4

  • dense_rank()over([partition by 字段名] order by 字段名 asc|desc)

 并列连续性排序——若数值为99,99,90,89 则排名1,1,2,3

  • row_number()over([partition by 字段名] order by 字段名 asc|desc)

 连续性排序——若数值为99,99,90,89 则排名1,2,3,4

若数值不重复则这三个函数可以通用

[例题29] 查询每一年S14000021选区中所有候选人所在的团体(party)和得票数(votes),并对每一年中的所有候选人根据选票数的高低赋予名次,选票数最高则为1,第二名则为2,后续以此类推,最后根据团体(party)和年份(yr)排序

SELECT 
    yr,
    party,
    votes,
    RANK() OVER (PARTITION BY yr ORDER BY votes DESC) AS posn
FROM 
    ge
WHERE 
    constituency = 'S14000021'
ORDER BY 
    party,
    yr;

【偏移分析函数语法】

  • lag(字段名,偏移量[,默认值])over([partition by 字段名] order by 字段名 asc|desc)

用于在查询结果集中访问当前行之前的某一行的数据。

  • lead(字段名,偏移量[,默认值])over([partition by 字段名] order by 字段名 asc|desc)

LEAD() 函数与 LAG() 函数相反,它用于访问当前行之后的某一行的数据。

 [例题] You can filter the data to view only Monday's figures WHERE WEEKDAY(whn) = 0.

Show the number of new cases in Italy for each week in 2020 - show Monday only.

SELECT 
    name,
    DATE_FORMAT(whn, '%Y-%m-%d') AS date,
    (confirmed - LAG(confirmed, 1) OVER (PARTITION BY name ORDER BY whn)) AS New
FROM 
    covid
WHERE 
    name = 'Italy'
    AND WEEKDAY(whn) = 0
ORDER BY 
    whn;
  • 在 MySQL 中,WEEKDAY()函数用于返回日期对应的星期索引。这个索引是从 0 开始的,其中 0 代表星期一,1 代表星期二,依此类推,6 代表星期日。

注:

  • 窗口函数只能写在SELECT子句中
  • 窗口函数中的partition by 子句可以指定数据的分区,和GROUP BY 要去重分组不同的是,PARTITION BY只分区不去重
  • 窗口函数中没有PARTITION BY 子句是,即不对数据分区,直接整个表为一个区
  • 排序窗口函数中ORDER BY 子句是必选项,窗口函数中ORDER BY 子句在分区内依据指定字段和排序方法对数据进行行排序

另外还有其他的窗口函数如SUM()用于求累计和,FIRST_VALUE()LAST_VALUE(),用于获取数据集中的第一个或最后一个值,PERCENT_RANK()计算当前行在结果集中的百分比排名,排名范围从 0 到 1。

主知识点九:表连接

【JOIN】 列连接

【内连接】(连不上的不保留)

select 字段名

from 表名1

inner join 表名2

on 表名1.字段名 = 表名2.字段名

注意内连接inner可以省略,直接使用join默认为内连接

【左连接】(保留左边表格内容)

select 字段名

from 表名1

left join 表名2

on 表名1.字段名 = 表名2.字段名

【右连接】(保留右边表格内容)

select 字段名

from 表名1

right join 表名2

on 表名1.字段名 = 表名2.字段名

左连接和右连接统称外连接(OUTER JOIN) 

 【UNION】行连接

join---连接表,对列操作

union--连接表,对行操作。

union--将两个表做行拼接,同时自动删除重复的行。

union all---将两个表做行拼接,保留重复的行。

  •  使用union组合查询时,只能使用一条order by字句,他必须位于最后一条select语句之后,因为对于结果集不存在对于一部分数据进行排序,而另一部分用另一种排序规则的情况。

[例题] 

 

SELECT 
    ga.mdate,
    ga.team1,
    SUM(CASE WHEN ga.team1 = go.teamid THEN 1 ELSE 0 END) AS score1,
    ga.team2,
    SUM(CASE WHEN ga.team2 = go.teamid THEN 1 ELSE 0 END) AS score2
FROM 
    game ga
LEFT JOIN 
    goal go ON ga.id = go.matchid
GROUP BY 
    ga.mdate, ga.team1, ga.team2
ORDER BY 
    ga.mdate, go.matchid, ga.team1, ga.team2;

主知识点十:子查询

  • 子查询本身就是一段完整的查询语句,然后用括号英文括号()包裹嵌套在主查询语句中,子查询可以多层嵌套 
  • 最常用的子查询运用在from和where子句中

[例题]  查询德国和意大利每天新增治愈人数并从高到低排名,查询结果按国家名,截至日期(输出格式为'xxxx年xx月xx日'),新增治愈人数,按排名排序

select 
    name, 
    日期, 
    lrecovered,
    rank() over(partition by name order by lrecovered desc) 排名
from
(
    select name,
           date_format(whn,'%Y年%m月%d日') 日期,
           recovered-lag(recovered,1)over(partition by name order by whn) lrecovered
    from covid
    where name in ('Germany','Italy')
    order by lrecovered desc
) re
order by 排名;

【练习】

### 师兄 SQL 数据分析 第4题 解答 #### 子查询的概念与应用 子查询是指一段能够独立运行的完整查询语句,通常被嵌套在主查询中。它可以在 `FROM` 和 `WHERE` 子句中使用,并且其执行顺序总是先于主查询完成[^3]。这种特性使得子查询成为解决复杂业务逻辑的重要工具。 #### 综合用法解析 根据已有资料,子查询的核心功能在于提供一种灵活的方式来处理多层次的数据关系。具体到题目中的场景,以下是可能涉及的关键知识点: 1. **单行子查询** 单行子查询返回单一值的结果集,常用于比较运算符(如 `=`, `<`, `>`)。例如,在筛选特定条件下的记录时,可以通过子查询动态计算阈值。 ```sql SELECT employee_id, salary FROM employees WHERE department_id = ( SELECT department_id FROM departments WHERE location_id = 1700 ); ``` 2. **多行子查询** 多行子查询返回多个值的结果集,适用于集合操作符(如 `IN`, `ANY`, `ALL`)。这类查询适合处理一对多或多对多的关系。 ```sql SELECT product_name FROM products WHERE category_id IN ( SELECT category_id FROM categories WHERE parent_category = 'Electronics' ); ``` 3. **关联子查询** 关联子查询依赖外部表的数据来构建内部查询逻辑,常见于复杂的过滤需求。它的特点是每次迭代都会重新评估一次子查询。 ```sql SELECT e.employee_id, e.salary FROM employees e WHERE e.salary > ALL ( SELECT avg_salary FROM department_averages d WHERE d.department_id = e.department_id ); ``` #### 假设第4题的具体情境 虽然未明确给出原题内容,但基于上述理论框架推测,该题很可能围绕以下几个方面展开: - 使用子查询实现跨表数据提取; - 结合聚合函数完成统计分析; - 应用层次化查询结构优化性能。 以下是一个典型的综合练习示例,假设目标是从订单表 (`orders`) 中找出销售额最高的客户及其总消费金额: ```sql SELECT c.customer_id, c.name, SUM(o.amount) AS total_spent FROM customers c JOIN orders o ON c.customer_id = o.customer_id GROUP BY c.customer_id, c.name HAVING SUM(o.amount) >= ALL ( SELECT SUM(amount) FROM orders GROUP BY customer_id ); ``` 此脚本展示了如何利用子查询配合窗口函数达成精准定位的目的[^4]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值