免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

SQL数据分析7天速成:从基础查询到窗口函数与项目实战

SQL数据分析7天速成:从基础查询到窗口函数与项目实战 很多人学SQL数据分析时走的路是先把语法全部背一遍再刷几十套题最后遇到真实业务数据还是不知道从哪里下手。这种学法不仅慢还特别容易放弃。更合理的路径应该是以分析任务为驱动先掌握高频语法再直接拿真实项目练手。这篇文章把这种方法拆成7天可执行的学习路线覆盖查询、清洗、聚合、窗口函数、性能优化和项目实战适合零基础转行数据分析、初级分析师、在校学生。下面我会把每天该学什么、练什么、练到什么程度算过关全部拆开讲。1. 学数据分析前先重新理解SQL的角色1.1 数据分析中SQL到底解决什么问题SQL是一门结构化查询语言本质上就是通过一些固定模式的操作从数据库里把数据找出来并整理成适合分析的样子。在数据分析岗位上SQL不是用来做系统开发也不是用来做算法它最常见的用途只有四个字取数、清洗。取数是从业务库、数仓、离线表中把需要的数据按条件拿出来清洗是按统一口径处理空值、重复值、格式和派生字段接下来再配合Excel、Python、BI工具做可视化或建模。所以SQL学得好不好不看语法背得多少而是看能不能快速从一堆无关字段里取出干净、准确、可解释的数据。很多教程把SQL讲成一种编程语言反复强调变量、流程控制、存储过程这会把初学者带偏。对数据分析来说SQL更像是一组“查数据”的工具组合筛选、连接、分组、聚合、排序掌握这些就覆盖了90%的日常工作。1.2 不需要学的和必须学的很多人都被“SQL从入门到精通”这种大部头吓住其实数据分析中用到的SQL非常集中。必须优先掌握的是SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、DISTINCT、LIMIT聚合函数COUNT、SUM、AVG、MAX、MIN字符串和日期处理CASE WHENJOIN子查询窗口函数。不需要一开始深挖的是复杂的存储过程、触发器、游标、动态SQL、复杂的数据库管理、高级索引设计。这些属于数据库开发岗位的范畴数据分析师只需要理解基本概念、能看执行计划就够了。主次分清学习效率会提高很多。我见过不少同学把《SQL必知必会》翻了三遍但连一个按月销售额统计都写不出来原因就是把精力浪费在了低频知识点上。1.3 判断学没学会的标准我建议不要用“我看完了视频”当标准而是用“我能不能不看笔记写出某个查询”当标准。比如给你几张表要求输出每个月的销售额、订单量、客单价你能在10分钟内写出正确SQL那这一关就过了。再比如要求输出每个商品分类销售额排名前3的商品你能用窗口函数写出来就算进阶掌握了。学习过程中每天都要有可运行的结果不能只看不练。视频弹幕里经常会刷“老师讲得好”“先码后看”但真正能学会的只有那些跟着动手敲的人。SQL是一个实践性极强的技能眼睛会了不等于手会了。2. 第一天到第七天一套可执行的7天学习路径2.1 第1天环境搭建与基础查询第1天只做两件事把数据库环境跑起来然后学会最简单的查询。先用自带库或造几张简单表练习SELECT *、SELECT指定字段、LIMIT限制条数、ORDER BY排序。完成标准是能从表里取指定字段能有意识地控制返回行数。这里不要急着学JOIN先把单表查询打牢固。环境搭建最容易拖慢进度。如果你在安装数据库上卡了超过两小时不要死磕先换一种方式云数据库、在线SQL练习环境都可以。学习阶段的目的是把精力放在写SQL上而不是被安装细节劝退。2.2 第2天过滤、排序、去重、空值处理第2天开始处理真实数据常见的脏问题。WHERE条件比较运算符、IN、LIKE、BETWEEN、逻辑运算符AND、ORDISTINCT去重NULL判断要用IS NULL而不是 NULL用IFNULL或COALESCE给空值填充默认值。完成标准是能从一个订单表中筛选出符合多个条件的数据并去掉重复记录。这里有一个重要认知数据分析过程中大部分时间不是在写花哨的查询而是在处理“为什么这个数不一样”的问题。重复记录、空值、大小写不一致、前后空格这些脏数据才是常态。所以第2天不要急着往前赶多找几个带脏数据的表来练。2.3 第3天聚合函数与分组统计数据分析最核心的一类SQL就是“分组计数”。掌握COUNT、SUM、AVG、MAX、MINGROUP BY的使用如果分组后要过滤需要用HAVING而不是WHERE。这里有一个很常见的误区WHERE是对原始行过滤HAVING是对分组后的结果过滤。完成标准能输出每周、每月的订单量、销售额、平均客单价。建议自己造一份“订单流水表”包含订单日期、用户ID、金额、状态字段然后反复练习按天、按周、按月、按用户分组统计。第3天如果能熟练掌握“分组—聚合—排序”这条链路后面很多需求都能覆盖。2.4 第4天Case When 和常用函数CASE WHEN是数据分析里做逻辑打标和透视的利器。比如按金额把用户分成高、中、低价值或用它实现行转列。同时学习日期函数DATE_FORMAT、DATE_ADD、DATEDIFF字符串函数SUBSTRING、CONCAT、LEFT、RIGHT类型转换CAST。完成标准能在一个查询中生成多个统计口径比如“按支付状态分类的订单金额”。很多初学者看到CASE WHEN会觉得很绕其实就是SQL里的if-else。你需要养成一个习惯拿到一个分析需求先想“这个逻辑有几个分支”再考虑用CASE WHEN还是WHERE。比如“高价值、中价值、低价值”就是三个分支适合CASE WHEN“只看已支付订单”是一个条件适合WHERE。2.5 第5天多表连接与子查询业务数据很少放在一张表里用户表、订单表、商品表要连起来才有分析价值。这一天集中练JOININNER JOIN、LEFT JOIN、RIGHT JOIN。理解什么是驱动表、关联键、会不会产生多行子查询则可以放在FROM后面当临时表或放在WHERE中用IN、EXISTS。完成标准能关联用户和订单表计算每个用户的首次下单时间、订单数量、累计消费金额。这一天的核心坑点是“一对多”会产生重复数据。一个用户有多个订单用户表LEFT JOIN订单表后用户信息会重复多行这是正常的。但如果统计用户数时直接COUNT(user_id)就会把同一个用户算多次。正确做法是COUNT(DISTINCT user_id)或者先聚合订单表再连接用户表。2.6 第6天窗口函数完成进阶分析第6天是拉开差距的地方。窗口函数能解决“分组后不丢失明细”的问题。典型有ROW_NUMBER()、RANK()、DENSE_RANK()做排名SUM() OVER(PARTITION BY ... ORDER BY ...)做累计LAG()、LEAD()做前后对比FIRST_VALUE、LAST_VALUE做区间首尾。完成标准能输出每个部门业绩前3名或者每个用户按月累计消费。窗口函数不用全部记住关键是能判断什么时候该用。比如需求是“每个分类销售额排名前3”普通GROUP BY会把明细压扁拿不到排名加个ROW_NUMBER() OVER(PARTITION BY category ORDER BY sales DESC)就能给每一行标上组内序号再通过外层过滤取得前3。这一招在面试题和真实项目中出现频率非常高。2.7 第7天综合项目实战与复盘前6天练的是局部能力第7天要把它们串起来。做一个小型电商分析项目从建表、导数据到完成销售额、复购率、TopN商品、用户分层等需求。第7天不只写SQL还要把结果整理成一份“分析结论清单”。完成标准给任意一个模拟业务表能自己拆解出3个可分析的问题并用SQL输出可验证的结果。7天不是终点。第7天晚上可以做一次复盘把每一天写的SQL重新跑一遍标注哪些是凭记忆写的、哪些是翻笔记写的。翻笔记写出来的内容第二天再复习。这个步骤看起来琐碎但比“每天学新内容”更重要。3. 环境准备用最不容易卡壳的方式跑起来3.1 数据库选型为什么建议先用MySQL 8.0网上很多教程用SQL Server演示版本可能还停留在2008 R2界面老、安装包大、配置步骤多也有教程用PostgreSQL功能很好但很多初学者装完以后连默认用户都找不到。如果目标是数据分析我更推荐先用MySQL 8.0。原因有三个第一大多数业务分析案例、面试题和开源项目默认用MySQL资料最多第二安装包和安装步骤相对简单第三语法上和其他主流数据库差异不大后期迁移理解成本低。这里要注意如果你的公司或项目指定了SQL Server 2022、Oracle或PostgreSQL不要慌核心语法80%以上是通用的主要区别在函数名、分页写法、类型转换上。你先学MySQL的通用查询思路后面换到其他数据库时再去查对应的函数文档就好。3.2 安装和连接Windows、macOS、Linux 三种情况Windows上安装MySQL 8.0通常会提供MySQL Installer注意安装类型选Server only就可以。安装过程中会让你设置root密码这个密码要记住后面连接和做项目都要用。服务端口默认3306基本不用改。macOS上可以用官方安装包也可以直接通过Homebrew安装装完执行启动命令。Linux上如果使用Ubuntu或Debian可以通过包管理器安装装完查看服务状态。步骤不复杂但很多人会卡在“安装成功却连不上”这一步。最常见的三个原因服务没启动、端口被占用、root密码策略太严格。如果你装的是旧版SQL Server 2008 R2还要额外处理兼容性问题没必要在入门阶段投入这些成本。如果本地装不上或者不想在电脑里增加软件环境可以直接用云数据库比如各大云平台都有免费试用实例也可以使用在线SQL练习环境。学习阶段目标是让你把精力放在写SQL上而不是被安装细节劝退。只要能稳定运行手段不重要。3.3 练习数据集不要只用学生表尽量贴近业务很多入门教程喜欢用student、course、score这类学生选课表方便演示但到了面试和实际业务里你会发现业务表和教学表差别很大。教学表行数少字段规范业务表通常有大量重复值、空值、脏数据和奇怪的字段命名。所以建议练习时用订单表、用户表、商品表、支付流水表这一套虚构电商数据。下面给出一个三张表的最小结构示例-- 用户表 CREATE TABLE users ( user_id INT PRIMARY KEY, reg_date DATE, city VARCHAR(50) ); -- 商品表 CREATE TABLE products ( product_id INT PRIMARY KEY, category VARCHAR(50), price DECIMAL(10,2) ); -- 订单表 CREATE TABLE orders ( order_id INT PRIMARY KEY, user_id INT, product_id INT, order_date DATE, amount DECIMAL(10,2), status VARCHAR(20) );这个结构不复杂但已经能覆盖大部分数据分析需求时间维度、用户维度、商品维度、订单状态。你可以用Excel生成几百行数据再导入MySQL或者用Python脚本造数。如果不会造数就先手动输入10行20行先把流程跑通。关键是让自己在真实的“带脏数据”的表上练习而不是全在理想数据上抄答案。3.4 客户端工具命令行、DBeaver、NavicatMySQL装好以后自带命令行客户端适合执行简单语句但不适合写长SQL看结果也不够直观。我建议安装一个可视化客户端。DBeaver是免费开源的选择支持MySQL、PostgreSQL、SQL Server等能看到表结构、编辑数据、执行计划对练习和项目都够用。Navicat界面更友好但收费如果有条件可以使用。选择工具的标准只有一个你能快速看到查询结果并且方便排查语法错误不用花费太多时间研究工具本身。注意不管用什么客户端连接MySQL时要确认几个参数主机名localhost或127.0.0.1端口3306用户名root密码是安装时设置的如果是云数据库主机名换成公网地址端口可能有不同。保存连接时先点测试连接能通过再接。4. 数据分析最常用的SQL技能拆解4.1 查询主干掌握书写顺序和执行顺序数据分析SQL最基础的骨架是SELECT city, COUNT(*) AS user_cnt FROM users WHERE reg_date 2024-01-01 GROUP BY city HAVING COUNT(*) 10 ORDER BY user_cnt DESC LIMIT 10;书写顺序是SELECT、FROM、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT但执行顺序不一样。从逻辑执行顺序看先FROM拿到表再WHERE过滤行再GROUP BY分组再聚合再HAVING过滤分组再SELECT选择列最后ORDER BY排序然后LIMIT。理解执行顺序的好处是排查报错或结果不对时知道问题出在哪一环。比如WHERE里不能用聚合函数因为WHERE执行时聚合还没发生HAVING里可以使用聚合函数因为HAVING在分组之后执行。很多人一开始记不住这两个过滤条件的区别就是没有理解执行顺序。4.2 去重和空值最容易翻车的两个地方“SQL语句去重查询”是搜索频率很高的词。去重最简单的是SELECT DISTINCT它会对查询结果的所有列组合去重。如果只想对某一列去重可以用GROUP BY这一列。还要注意DISTINCT放在多列前跟放在单独一列前结果完全不同。空值处理上一个有经验的排查顺序是先看字段是否允许NULL再统计NULL数量最后决定过滤还是填充。判断NULL一定要用IS NULL或IS NOT NULL不能用 NULL。如果要对NULL做统一替换MySQL中可以用IFNULL(column, 0)或COALESCE(column, 0)。给一个常见需求示例SELECT city, COUNT(DISTINCT user_id) AS active_user_cnt FROM users WHERE city IS NOT NULL GROUP BY city ORDER BY active_user_cnt DESC;这个查询在统计时把城市为空的数据去掉了避免把无城市用户混入分析结果。实际业务里空值到底是删除、填0、还是单独分一类要结合分析口径判断不能一刀切。4.3 条件逻辑CASE WHEN 完成分组、标记和透视CASE WHEN是SQL里的if-else逻辑。比如把用户按消费金额分成三个等级SELECT user_id, SUM(amount) AS total_amount, CASE WHEN SUM(amount) 10000 THEN 高价值 WHEN SUM(amount) 1000 THEN 中价值 ELSE 低价值 END AS user_level FROM orders WHERE status paid GROUP BY user_id;注意这里CASE WHEN应用在聚合结果上因此放在GROUP BY后面才合理。如果想事先把订单金额大小分组再统计也可以放在SELECT和GROUP BY里。还有一类用法是做透视比如统计每天不同支付渠道的订单量通过SUM(CASE WHEN ... THEN 1 ELSE 0 END)把行转列。这类思路在实际项目和面试中经常出现。4.4 窗口函数分组后不丢明细的进阶能力窗口函数解决的是“既要分组统计又要保留每行明细”的矛盾。最常见的三个排名函数是ROW_NUMBER、RANK、DENSE_RANK区别在于并列时名次是否跳号。比如销售业绩相同ROW_NUMBER会给不同序号RANK会给相同名次同时跳过后续名次DENSE_RANK相同名次但不跳号。SELECT category, product_id, sales_amount, ROW_NUMBER() OVER(PARTITION BY category ORDER BY sales_amount DESC) AS rn FROM daily_sales;如果想取每个分类销量前3就在外层套一层WHERE rn 3。窗口函数在数据分析中的用途还包括累计求和SUM(amount) OVER(PARTITION BY user_id ORDER BY order_date) AS cum_amount可以算每个用户按时间累计的消费LAG(order_date)可以算上一单时间用来判断复购间隔。这一块第6天花一整段时间练习重点不是记住函数名而是能判断什么时候该用窗口函数。4.5 多表关联JOIN 的几种玩法业务分析里多表连接最常见。INNER JOIN只保留两表匹配的数据LEFT JOIN以左表为准右表没有匹配就记为NULLRIGHT JOIN方向相反。给一个常见试误点如果两表关联键不是唯一的连接结果会翻倍产生笛卡尔积。比如用户表和订单表一个用户有多个订单用户表直接LEFT JOIN订单表后用户信息会重复多行这是正常的聚合时要注意去重或合理统计。如果要统计用户数不能直接COUNT(users.user_id)要COUNT(DISTINCT users.user_id)。这个坑几乎每个初学者都会踩。5. 用一个电商订单项目把所有技能串起来5.1 项目需求与表结构设计学习SQL最终要落到项目上。下面用一个比较常见的电商场景练手。需求是统计最近30天的整体销售情况、用户复购情况和商品销售排名并输出一份分析结论。表结构可以用前面定义的三张表users、products、orders。为了贴近实际可以给orders表增加create_time和pay_time给users表增加gender。这个项目不需要一开始就追求完美的业务建模只要能把关系理清楚。分析目标拆成三个子任务第一每日或每月的销售额和订单量第二用户维度的新增、活跃、复购率第三商品维度的TopN和分类占比。5.2 任务一每日销售额和订单量先写最基础的时间趋势分析SELECT DATE(order_date) AS dt, COUNT(DISTINCT order_id) AS order_cnt, SUM(amount) AS sales_amount, ROUND(SUM(amount) / COUNT(DISTINCT order_id), 2) AS avg_order_amount FROM orders WHERE status paid AND order_date CURRENT_DATE - INTERVAL 30 DAY GROUP BY DATE(order_date) ORDER BY dt;这里要理解几个点订单量要COUNT(DISTINCT order_id)避免连接其他表后产生重复客单价等于销售额除以订单量时间过滤使用当前日期减去30天。输出以后可以先画一条趋势线判断数据是否有明显的周末波动或活动日波动。5.3 任务二用户复购率分析复购率通常有两种口径第一个是“购买两次及以上用户数 / 总购买用户数”第二个是“本月有过复购行为的人数 / 本月活跃买家数”。先用全局口径算WITH user_buy_cnt AS ( SELECT user_id, COUNT(DISTINCT order_id) AS buy_cnt FROM orders WHERE status paid GROUP BY user_id ) SELECT COUNT(*) AS total_buyer, SUM(CASE WHEN buy_cnt 2 THEN 1 ELSE 0 END) AS repeat_buyer, ROUND(SUM(CASE WHEN buy_cnt 2 THEN 1 ELSE 0 END) / COUNT(*), 4) AS repeat_rate FROM user_buy_cnt;这里使用CTE公用表表达式先把每个用户购买次数算出来再在外层统计占比。CTE在写复杂分析SQL时非常有用能让逻辑更清晰也能避免一层层嵌套子查询。如果数据库版本比较老不支持WITH也可以用子查询嵌套效果一样。5.4 任务三商品TopN和分类占比推荐商品要看销售额和销量两者可能不一致要分别输出。用窗口函数取每个分类销售额前3SELECT category, product_id, sales_amount, rn FROM ( SELECT p.category, p.product_id, SUM(o.amount) AS sales_amount, ROW_NUMBER() OVER(PARTITION BY p.category ORDER BY SUM(o.amount) DESC) AS rn FROM orders o LEFT JOIN products p ON o.product_id p.product_id WHERE o.status paid GROUP BY p.category, p.product_id ) t WHERE rn 3;这里的关键是LEFT JOIN后仍然按商品分组聚合的是订单金额。如果把订单表直接JOIN商品表可能因为商品维度产生重复一定要确认GROUP BY字段。5.5 把SQL结果转换成业务结论项目不是写完SQL就结束还要能解释数字。比如发现复购率只有10%可能是统计口径问题也可能代表商品低客单价、低频消费需要继续拆时间维度或商品维度。建议把每个查询结果存成CSV用Excel或BI工具做可视化再写三到五句结论。第7天完成这个项目后你可以把整个过程整理成一套“需求—SQL—结果—结论”的文档这就是一个能放进简历或作品集的完整分析案例。6. 性能与面试慢SQL优化和常见面试题6.1 遇到慢SQL先别改索引先看执行计划“SQL优化”和“慢SQL优化”是高频搜索词。遇到一条查询很慢不要第一反应就加索引。先看数据量级再看执行计划。MySQL中可以用EXPLAINEXPLAIN SELECT * FROM orders WHERE status paid AND order_date 2024-01-01;重点看type、key、rows三个列。type最好不是ALLALL意味着全表扫描key表示实际用到的索引rows是估算扫描行数。如果rows很大再考虑加索引。日常开发中很多慢查询都能用“复合索引 避免在条件列上做函数运算”解决。比如经常按status和order_date筛选可以建组合索引(status, order_date)。但索引不是越多越好会拖慢写入和增加存储。6.2 数据分析写SQL时容易忽略的优化细节下面几个点在面试和代码评审里经常被问到尽量不要用SELECT *只取需要的字段减少网络和内存开销。WHERE条件里不要对字段做函数包裹比如WHERE DATE(order_date) 2024-01-01会让索引失效可以改成order_date 2024-01-01 AND order_date 2024-01-02。分页查询深度很大的时候LIMIT 100000, 20会扫描很多行可以用上一页的最大值做条件或者用延迟关联。JOIN时确保关联字段有索引小表驱动大表在优化器中未必绝对但在理解上可以帮助你判断。这些优化不是让入门阶段就死磕而是当你的SQL跑在几十万上百万行数据上时能快速意识到问题出在哪里。第6天或第7天可以专门拿一个慢查询案例先看执行计划再改SQL体会一下“数据量变大后写法不同”的意义。6.3 高频SQL面试题类型结合“SQL面试题”这个高频关注点我把最常见的题型列一下去重统计比如统计每天活跃用户数用COUNT(DISTINCT user_id)。分组TopN比如每个部门工资最高的员工用窗口函数ROW_NUMBER()。连续登录判断用户是否连续N天登录常用DATE_SUB和ROW_NUMBER配合。累计求和用SUM() OVER(ORDER BY date)算累计销售额。行列转换用CASE WHEN加聚合把竖表转成横表。找中位数用排名函数或PERCENTILE_CONT。经典表连接A表有B表没有的数据用LEFT JOIN加右表IS NULL。建议每类题自己动手写三到五遍不要只看题解。面试官通常不会只考一个函数而是看你能不能结构化拆解问题、能不能考虑边界条件。6.4 把排查顺序变成面试表达优势面试题遇到不会的SQL时不要沉默。可以说我会先确认题目里的表结构和数据样例判断是一对多还是多对多再拆解需求是基础统计、分组排名还是行列转换写完以后用一个小数据样例验证边界。这种表达方式比直接报答案更值钱。背题只能过一面能讲清楚思路才是真正掌握。7. 常见报错和排查清单7.1 数据库连接失败连接失败时先看四个地方服务是否启动、端口是否被占用、账号密码是否正确、客户端连接地址是否为localhost或127.0.0.1。如果刚装完MySQLroot密码可能涉及密码策略太简单会被拒绝可以重新设置密码或调整密码策略。如果使用云数据库确认白名单和安全组是否放行。7.2 SQL语法报错先定位到第一个报错位置数据库报错通常会指出错误附近的内容但有时不准确。排查思路是先看这一条SQL里有没有明显拼写错误再看表名前是否有空格字段名大小写是否匹配字符串和日期是否加了引号括号是否左右匹配。新手常见的问题是多了一个逗号、少了GROUP BY字段、聚合函数用错了位置。建议写长SQL时分成小段先跑再逐步拼接不要一次性写完一大段才发现报错。7.3 结果集不符合预期检查连接方式和过滤条件如果查询出来的行数比预想多最常见的怀疑对象是JOIN使关联键重复产生了笛卡尔积。可以用COUNT(*)和COUNT(DISTINCT 主键)对比判断。如果查询结果为空先单独验证每一张表是否有数据再检查JOIN条件是否写反、过滤条件是否把数据全部筛掉、状态字段值的大小写和空格是否和预期一致。很多问题不是SQL写错而是输入数据本身有脏值。7.4 中文乱码和编码问题MySQL出现中文乱码大多是因为数据库、表或客户端的字符集不一致。建库时推荐使用utf8mb4客户端连接时设置字符集。如果只是某个表乱码可以查看表的字符集设置。在DBeaver里连接参数可以加上编码设置。这一项在日常项目里很容易踩到建议一开始就把字符集设置清楚。7.5 不同数据库的函数差异如果你平时用MySQL面试或工作中需要用SQL Server、PostgreSQL、Oracle要特别注意这几点分页查询MySQL用LIMITSQL Server用OFFSET FETCH或TOP字符串拼接MySQL用CONCATSQL Server用PostgreSQL用||取当前日期MySQL用CURRENT_DATESQL Server用GETDATE()PostgreSQL用CURRENT_DATE。核心逻辑不变函数差异查看官方文档即可。别被“我会的是MySQL公司用的是SQL Server”吓到转换成本没有想象中高。把这7天走完不是让你背完所有SQL语法而是让你养成一种“拿到业务需求先拆解成查询逻辑”的思维方式。我个人的建议是7天之后不要急着学新东西把电商项目里的SQL重新默写一遍再换一套业务流程比如订单退款分析、用户留存分析看看能不能独立写出来。多写几次以后你会发现SQL数据分析的核心不是语言技巧而是准确理解业务口径和严谨取得数据的能力。如果中间某一天卡住了先不要跳过回到当天例题把数据结构和结果逻辑理清楚再继续。学SQL不怕慢怕的是看着都会写起来全不会。
返回列表