|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
一、SQL基础入门
1. SQL简介与历史
SQL(Structured Query Language,结构化查询语言)是一种专门用于管理关系型数据库的标准化语言。它最早由IBM的研究员在1970年代开发,并逐渐成为数据库领域的事实标准。SQL允许用户执行各种操作,包括查询数据、插入记录、更新数据、删除记录以及创建和修改数据库结构。
SQL的主要特点包括:
• 简单易学:语法直观,接近自然语言
• 功能强大:能够处理复杂的数据操作和分析
• 标准化:大多数关系型数据库都支持SQL
• 声明式:只需告诉数据库”要什么”,而不需要告诉”怎么做”
2. 数据库基本概念
在开始学习SQL之前,我们需要了解一些基本的数据库概念:
• 数据库(Database):存储数据的容器,通常由多个表组成
• 表(Table):数据库中存储数据的结构,由行和列组成
• 行(Row):表中的水平记录,也称为记录或元组
• 列(Column):表中的垂直字段,也称为字段或属性
• 主键(Primary Key):唯一标识表中每一行的列
• 外键(Foreign Key):引用其他表主键的列,用于建立表之间的关系
3. SQL语言分类
SQL语言可以分为以下几个主要部分:
• DQL(Data Query Language):数据查询语言,主要用于从数据库中检索数据,最常用的命令是SELECT
• DML(Data Manipulation Language):数据操作语言,用于修改数据库中的数据,包括INSERT、UPDATE和DELETE
• DDL(Data Definition Language):数据定义语言,用于定义和管理数据库结构,包括CREATE、ALTER和DROP
• DCL(Data Control Language):数据控制语言,用于控制数据库的访问权限,包括GRANT和REVOKE
• TCL(Transaction Control Language):事务控制语言,用于管理数据库事务,包括COMMIT、ROLLBACK和SAVEPOINT
4. SQL环境搭建
对于初学者,有几种简单的方法可以搭建SQL学习环境:
SQLite是一个轻量级的数据库引擎,无需安装服务器,非常适合初学者:
- # 在Linux或macOS上安装SQLite
- sudo apt-get install sqlite3 # Debian/Ubuntu
- brew install sqlite # macOS
- # 在Windows上,可以从SQLite官网下载预编译的二进制文件
复制代码
安装完成后,可以通过命令行启动SQLite:
如果不想安装任何软件,可以使用在线SQL编辑器,如:
• SQLFiddle (http://sqlfiddle.com/)
• DB-Fiddle (https://www.db-fiddle.com/)
• W3Schools SQL Tryit (https://www.w3schools.com/sql/trysql.asp?filename=trysql_select_all)
如果希望使用更完整的数据库系统,可以安装MySQL或PostgreSQL:
- # 安装MySQL
- # Ubuntu/Debian
- sudo apt-get update
- sudo apt-get install mysql-server
- # CentOS/RHEL
- sudo yum install mysql-server
- # macOS
- brew install mysql
- # 安装PostgreSQL
- # Ubuntu/Debian
- sudo apt-get install postgresql postgresql-contrib
- # CentOS/RHEL
- sudo yum install postgresql-server postgresql-contrib
- # macOS
- brew install postgresql
复制代码
二、SQL基本语法
1. SELECT语句基础
SELECT语句是SQL中最常用的命令,用于从数据库中检索数据。基本语法如下:
- SELECT column1, column2, ...
- FROM table_name;
复制代码
如果要选择表中的所有列,可以使用星号(*):
- SELECT * FROM table_name;
复制代码
假设我们有一个名为”employees”的表,包含以下数据:
要查询所有员工的信息:
要查询员工的姓名和薪资:
- SELECT name, salary FROM employees;
复制代码
可以使用AS关键字为列或表指定别名,使查询结果更易读:
- SELECT name AS '姓名', salary AS '薪资' FROM employees;
复制代码
使用DISTINCT关键字可以去除重复的行:
- SELECT DISTINCT department FROM employees;
复制代码
2. WHERE条件过滤
WHERE子句用于过滤记录,只返回满足指定条件的记录。基本语法如下:
- SELECT column1, column2, ...
- FROM table_name
- WHERE condition;
复制代码
WHERE子句中可以使用各种比较运算符:
查询IT部门的员工:
- SELECT * FROM employees WHERE department = 'IT';
复制代码
查询薪资大于7000的员工:
- SELECT * FROM employees WHERE salary > 7000;
复制代码
查询年龄在25到30岁之间的员工:
- SELECT * FROM employees WHERE age >= 25 AND age <= 30;
复制代码
WHERE子句中可以使用逻辑运算符组合多个条件:
查询IT部门且薪资大于7500的员工:
- SELECT * FROM employees WHERE department = 'IT' AND salary > 7500;
复制代码
查询IT部门或HR部门的员工:
- SELECT * FROM employees WHERE department = 'IT' OR department = 'HR';
复制代码
查询不是IT部门的员工:
- SELECT * FROM employees WHERE NOT department = 'IT';
复制代码
IN操作符允许在WHERE子句中指定多个可能的值:
- SELECT * FROM employees WHERE department IN ('IT', 'HR');
复制代码
BETWEEN操作符用于选取介于两个值之间的范围内的值:
- SELECT * FROM employees WHERE age BETWEEN 25 AND 30;
复制代码
LIKE操作符用于在WHERE子句中搜索列中的指定模式。可以使用两个通配符:
• %:表示零个或多个字符
• _:表示单个字符
查询姓”张”的员工:
- SELECT * FROM employees WHERE name LIKE '张%';
复制代码
查询名字中包含”三”的员工:
- SELECT * FROM employees WHERE name LIKE '%三%';
复制代码
IS NULL操作符用于查找NULL值:
- SELECT * FROM employees WHERE column_name IS NULL;
复制代码
3. ORDER BY排序
ORDER BY子句用于对结果集进行排序。默认为升序(ASC),可以指定降序(DESC):
- SELECT column1, column2, ...
- FROM table_name
- ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;
复制代码
按薪资升序排序:
- SELECT * FROM employees ORDER BY salary ASC;
复制代码
按年龄降序排序:
- SELECT * FROM employees ORDER BY age DESC;
复制代码
先按部门升序,再按薪资降序排序:
- SELECT * FROM employees ORDER BY department ASC, salary DESC;
复制代码
4. GROUP BY分组
GROUP BY子句通常与聚合函数一起使用,用于将相同值的行分组:
- SELECT column1, column2, ..., aggregate_function(column)
- FROM table_name
- WHERE condition
- GROUP BY column1, column2, ...;
复制代码
常用的聚合函数包括:
• COUNT():计算行数
• SUM():计算总和
• AVG():计算平均值
• MAX():找出最大值
• MIN():找出最小值
计算每个部门的员工人数:
- SELECT department, COUNT(*) AS employee_count
- FROM employees
- GROUP BY department;
复制代码
计算每个部门的平均薪资:
- SELECT department, AVG(salary) AS average_salary
- FROM employees
- GROUP BY department;
复制代码
计算每个部门的最高薪资和最低薪资:
- SELECT department, MAX(salary) AS max_salary, MIN(salary) AS min_salary
- FROM employees
- GROUP BY department;
复制代码
5. HAVING子句
HAVING子句用于过滤GROUP BY子句返回的分组。与WHERE子句不同,HAVING子句可以包含聚合函数:
- SELECT column1, column2, ..., aggregate_function(column)
- FROM table_name
- WHERE condition
- GROUP BY column1, column2, ...
- HAVING condition;
复制代码
查询员工人数大于1的部门:
- SELECT department, COUNT(*) AS employee_count
- FROM employees
- GROUP BY department
- HAVING COUNT(*) > 1;
复制代码
查询平均薪资大于7000的部门:
- SELECT department, AVG(salary) AS average_salary
- FROM employees
- GROUP BY department
- HAVING AVG(salary) > 7000;
复制代码
三、SQL高级查询技巧
1. 多表连接查询
在实际应用中,数据通常分布在多个表中,需要通过连接查询来获取完整的信息。SQL提供了多种连接方式:
内连接返回两个表中匹配条件的记录:
- SELECT columns
- FROM table1
- INNER JOIN table2
- ON table1.column = table2.column;
复制代码
假设我们有两个表:employees和departments。
employees表:
departments表:
查询员工及其所在部门的信息:
- SELECT e.name, e.salary, d.name AS department_name, d.location
- FROM employees e
- INNER JOIN departments d
- ON e.department_id = d.id;
复制代码
左连接返回左表中的所有记录,以及右表中匹配的记录。如果右表没有匹配,则结果中右表的列为NULL:
- SELECT columns
- FROM table1
- LEFT JOIN table2
- ON table1.column = table2.column;
复制代码
查询所有员工及其部门信息,即使某些员工没有分配部门:
- SELECT e.name, e.salary, d.name AS department_name, d.location
- FROM employees e
- LEFT JOIN departments d
- ON e.department_id = d.id;
复制代码
右连接返回右表中的所有记录,以及左表中匹配的记录。如果左表没有匹配,则结果中左表的列为NULL:
- SELECT columns
- FROM table1
- RIGHT JOIN table2
- ON table1.column = table2.column;
复制代码
查询所有部门及其员工信息,即使某些部门没有员工:
- SELECT e.name, e.salary, d.name AS department_name, d.location
- FROM employees e
- RIGHT JOIN departments d
- ON e.department_id = d.id;
复制代码
全连接返回两个表中的所有记录,无论它们是否匹配:
- SELECT columns
- FROM table1
- FULL JOIN table2
- ON table1.column = table2.column;
复制代码
注意:MySQL不支持FULL JOIN,但可以通过UNION组合LEFT JOIN和RIGHT JOIN来模拟:
- SELECT columns
- FROM table1
- LEFT JOIN table2
- ON table1.column = table2.column
- UNION
- SELECT columns
- FROM table1
- RIGHT JOIN table2
- ON table1.column = table2.column;
复制代码
自连接是指表与自身进行连接,通常用于比较同一表中的不同行:
- SELECT columns
- FROM table1 AS a
- JOIN table1 AS b
- ON a.column = b.column;
复制代码
查询薪资高于张三的员工:
- SELECT e1.name, e1.salary
- FROM employees e1, employees e2
- WHERE e1.salary > e2.salary AND e2.name = '张三';
复制代码
2. 子查询
子查询是嵌套在其他SQL查询中的查询。子查询可以出现在SELECT、FROM、WHERE和HAVING子句中。
- SELECT column1, column2, ...
- FROM table_name
- WHERE column_name operator (SELECT column_name FROM table_name WHERE condition);
复制代码
查询薪资高于平均薪资的员工:
- SELECT name, salary
- FROM employees
- WHERE salary > (SELECT AVG(salary) FROM employees);
复制代码
查询IT部门的员工:
- SELECT name, salary
- FROM employees
- WHERE department_id = (SELECT id FROM departments WHERE name = 'IT');
复制代码- SELECT column1, column2, ...
- FROM (SELECT column1, column2, ... FROM table_name WHERE condition) AS alias_name
- WHERE condition;
复制代码
查询各部门平均薪资高于公司平均薪资的部门:
- SELECT department_name, average_salary
- FROM (
- SELECT d.name AS department_name, AVG(e.salary) AS average_salary
- FROM employees e
- JOIN departments d ON e.department_id = d.id
- GROUP BY d.name
- ) AS dept_avg
- WHERE average_salary > (SELECT AVG(salary) FROM employees);
复制代码- SELECT column1, (SELECT column_name FROM table_name WHERE condition) AS alias_name
- FROM table_name;
复制代码
查询每个员工及其所在部门的员工总数:
- SELECT e.name, d.name AS department_name,
- (SELECT COUNT(*) FROM employees WHERE department_id = e.department_id) AS dept_count
- FROM employees e
- JOIN departments d ON e.department_id = d.id;
复制代码
相关子查询是指子查询依赖于外部查询的值:
- SELECT column1, column2, ...
- FROM table_name AS outer_table
- WHERE column_name operator (
- SELECT column_name
- FROM table_name AS inner_table
- WHERE inner_table.column = outer_table.column
- );
复制代码
查询每个部门中薪资高于该部门平均薪资的员工:
- SELECT name, salary, department_id
- FROM employees e
- WHERE salary > (
- SELECT AVG(salary)
- FROM employees
- WHERE department_id = e.department_id
- );
复制代码
3. 聚合函数
聚合函数对一组值执行计算,并返回单个值。常用的聚合函数包括:
COUNT()函数返回匹配指定条件的行数:
- SELECT COUNT(column_name) FROM table_name WHERE condition;
复制代码
查询员工总数:
- SELECT COUNT(*) FROM employees;
复制代码
查询IT部门的员工人数:
- SELECT COUNT(*) FROM employees WHERE department_id = 1;
复制代码
SUM()函数返回数值列的总和:
- SELECT SUM(column_name) FROM table_name WHERE condition;
复制代码
计算所有员工的总薪资:
- SELECT SUM(salary) FROM employees;
复制代码
AVG()函数返回数值列的平均值:
- SELECT AVG(column_name) FROM table_name WHERE condition;
复制代码
计算所有员工的平均薪资:
- SELECT AVG(salary) FROM employees;
复制代码
MAX()函数返回指定列的最大值:
- SELECT MAX(column_name) FROM table_name WHERE condition;
复制代码
查询最高薪资:
- SELECT MAX(salary) FROM employees;
复制代码
MIN()函数返回指定列的最小值:
- SELECT MIN(column_name) FROM table_name WHERE condition;
复制代码
查询最低薪资:
- SELECT MIN(salary) FROM employees;
复制代码
GROUP_CONCAT()(MySQL)或STRING_AGG()(PostgreSQL/SQL Server)函数将分组中的值连接成一个字符串:
- -- MySQL
- SELECT department_id, GROUP_CONCAT(name) AS employee_names
- FROM employees
- GROUP BY department_id;
- -- PostgreSQL/SQL Server
- SELECT department_id, STRING_AGG(name, ', ') AS employee_names
- FROM employees
- GROUP BY department_id;
复制代码
4. 高级过滤条件
CASE表达式用于在SQL中实现if-then-else逻辑:
- SELECT column1,
- CASE
- WHEN condition1 THEN result1
- WHEN condition2 THEN result2
- ...
- ELSE default_result
- END AS alias_name
- FROM table_name;
复制代码
根据薪资给员工分级:
- SELECT name, salary,
- CASE
- WHEN salary > 8000 THEN '高薪'
- WHEN salary > 6000 THEN '中薪'
- ELSE '低薪'
- END AS salary_level
- FROM employees;
复制代码
COALESCE函数返回参数列表中的第一个非NULL值:
- SELECT COALESCE(column1, column2, ..., default_value) FROM table_name;
复制代码
如果员工的联系电话为NULL,则显示”无”:
- SELECT name, COALESCE(phone, '无') AS contact_phone
- FROM employees;
复制代码
NULLIF函数如果两个表达式相等,则返回NULL,否则返回第一个表达式:
- SELECT NULLIF(expression1, expression2) FROM table_name;
复制代码
防止除以零错误:
- SELECT name, salary / NULLIF(commission, 0) AS salary_ratio
- FROM employees;
复制代码
四、SQL数据操作
1. INSERT插入数据
INSERT语句用于向表中插入新记录:
- INSERT INTO table_name (column1, column2, ...)
- VALUES (value1, value2, ...);
复制代码
向employees表中插入一条新记录:
- INSERT INTO employees (name, age, department_id, salary)
- VALUES ('孙八', 29, 1, 8500);
复制代码
插入多条记录:
- INSERT INTO employees (name, age, department_id, salary)
- VALUES
- ('周九', 31, 2, 6800),
- ('吴十', 26, 3, 9200),
- ('郑十一', 33, 1, 8800);
复制代码
从另一个表插入数据:
- INSERT INTO employees (name, age, department_id, salary)
- SELECT name, age, department_id, salary
- FROM temp_employees
- WHERE age > 25;
复制代码
2. UPDATE更新数据
UPDATE语句用于修改表中的现有记录:
- UPDATE table_name
- SET column1 = value1, column2 = value2, ...
- WHERE condition;
复制代码
更新张三的薪资:
- UPDATE employees
- SET salary = 8500
- WHERE name = '张三';
复制代码
更新IT部门所有员工的薪资,增加10%:
- UPDATE employees
- SET salary = salary * 1.1
- WHERE department_id = 1;
复制代码
使用子查询更新数据:
- UPDATE employees
- SET salary = salary * 1.05
- WHERE department_id = (SELECT id FROM departments WHERE name = 'HR');
复制代码
3. DELETE删除数据
DELETE语句用于删除表中的记录:
- DELETE FROM table_name WHERE condition;
复制代码
删除名为”钱七”的员工:
- DELETE FROM employees WHERE name = '钱七';
复制代码
删除HR部门的所有员工:
- DELETE FROM employees WHERE department_id = 2;
复制代码
使用子查询删除数据:
- DELETE FROM employees
- WHERE department_id = (SELECT id FROM departments WHERE name = 'Finance');
复制代码
TRUNCATE TABLE语句用于删除表中的所有行,但保留表结构:
- TRUNCATE TABLE table_name;
复制代码
TRUNCATE TABLE与DELETE的区别:
• TRUNCATE TABLE更快,因为它不记录单个行的删除
• TRUNCATE TABLE不能带WHERE条件
• TRUNCATE TABLE不能触发ON DELETE触发器
• TRUNCATE TABLE重置自增计数器
五、SQL性能优化
1. 索引的使用
索引是提高数据库查询性能的重要工具。它们类似于书籍的目录,可以帮助数据库快速定位数据,而不必扫描整个表。
- CREATE INDEX index_name
- ON table_name (column1, column2, ...);
复制代码
为employees表的name列创建索引:
- CREATE INDEX idx_employee_name
- ON employees (name);
复制代码
为employees表的department_id和salary列创建复合索引:
- CREATE INDEX idx_employee_dept_salary
- ON employees (department_id, salary);
复制代码
唯一索引确保索引列中的所有值都是唯一的:
- CREATE UNIQUE INDEX index_name
- ON table_name (column1, column2, ...);
复制代码
为employees表的email列创建唯一索引:
- CREATE UNIQUE INDEX idx_employee_email
- ON employees (email);
复制代码- DROP INDEX index_name ON table_name;
- -- 或者在某些数据库中
- DROP INDEX index_name;
复制代码
• 为经常用于WHERE子句、JOIN条件和ORDER BY排序的列创建索引
• 避免为频繁更新的表创建过多索引,因为索引会降低插入、更新和删除的速度
• 对于小表,可能不需要索引,因为全表扫描可能更快
• 复合索引的顺序很重要,应该将最常用于过滤的列放在前面
2. 查询优化技巧
避免使用SELECT *,只选择需要的列:
- -- 不推荐
- SELECT * FROM employees;
- -- 推荐
- SELECT id, name, salary FROM employees;
复制代码
尽量在WHERE子句中过滤数据,减少返回的行数:
- -- 不推荐
- SELECT name, salary FROM employees;
- -- 推荐
- SELECT name, salary FROM employees WHERE department_id = 1;
复制代码
如果只需要部分结果,使用LIMIT限制返回的行数:
- -- MySQL/PostgreSQL/SQLite
- SELECT name, salary FROM employees LIMIT 10;
- -- SQL Server/Oracle
- SELECT TOP 10 name, salary FROM employees;
复制代码
在WHERE子句中使用函数会阻止索引的使用:
- -- 不推荐
- SELECT name, salary FROM employees WHERE YEAR(hire_date) = 2020;
- -- 推荐
- SELECT name, salary FROM employees WHERE hire_date >= '2020-01-01' AND hire_date < '2021-01-01';
复制代码
在某些情况下,使用EXISTS代替IN可以提高性能:
- -- 不推荐
- SELECT name, salary FROM employees
- WHERE department_id IN (SELECT id FROM departments WHERE location = '北京');
- -- 推荐
- SELECT name, salary FROM employees e
- WHERE EXISTS (SELECT 1 FROM departments d WHERE d.id = e.department_id AND d.location = '北京');
复制代码
在某些情况下,使用JOIN代替子查询可以提高性能:
- -- 不推荐
- SELECT name, salary FROM employees
- WHERE department_id = (SELECT id FROM departments WHERE name = 'IT');
- -- 推荐
- SELECT e.name, e.salary FROM employees e
- JOIN departments d ON e.department_id = d.id
- WHERE d.name = 'IT';
复制代码
3. 执行计划分析
执行计划是数据库优化器为执行SQL查询而选择的步骤序列。分析执行计划可以帮助识别查询性能问题。
在MySQL中:
- EXPLAIN SELECT name, salary FROM employees WHERE department_id = 1;
复制代码
在PostgreSQL中:
- EXPLAIN ANALYZE SELECT name, salary FROM employees WHERE department_id = 1;
复制代码
在SQL Server中:
- SET SHOWPLAN_TEXT ON;
- GO
- SELECT name, salary FROM employees WHERE department_id = 1;
- GO
复制代码
在Oracle中:
- EXPLAIN PLAN FOR
- SELECT name, salary FROM employees WHERE department_id = 1;
- SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
复制代码
• type:访问类型,如ALL(全表扫描)、index(索引扫描)、range(范围扫描)、ref(索引查找)等
• key:实际使用的索引
• rows:估计需要检查的行数
• Extra:额外信息,如Using where(使用WHERE过滤)、Using index(使用索引覆盖)、Using filesort(使用文件排序)等
• 确保查询使用适当的索引
• 避免全表扫描,特别是对于大表
• 减少返回的行数和列数
• 优化JOIN操作
• 避免使用临时表和文件排序
六、实战案例
1. 常见业务场景SQL解决方案
分页查询是Web应用中常见的需求,用于在大量数据中分批显示:
- -- MySQL/PostgreSQL/SQLite
- SELECT name, salary, department_id
- FROM employees
- ORDER BY salary DESC
- LIMIT 10 OFFSET 20; -- 显示第3页,每页10条记录
- -- SQL Server 2012+
- SELECT name, salary, department_id
- FROM employees
- ORDER BY salary DESC
- OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY; -- 显示第3页,每页10条记录
- -- Oracle
- SELECT name, salary, department_id
- FROM (
- SELECT e.*, ROWNUM rn
- FROM (
- SELECT name, salary, department_id
- FROM employees
- ORDER BY salary DESC
- ) e
- WHERE ROWNUM <= 30
- )
- WHERE rn > 20; -- 显示第3页,每页10条记录
复制代码
层次查询用于处理具有父子关系的数据,如组织结构、评论回复等:
- -- MySQL 8.0+/PostgreSQL/SQL Server/Oracle使用递归CTE
- WITH RECURSIVE employee_hierarchy AS (
- -- 基础查询:选择顶级员工(没有经理的员工)
- SELECT id, name, manager_id, 1 AS level
- FROM employees
- WHERE manager_id IS NULL
-
- UNION ALL
-
- -- 递归查询:选择下级员工
- SELECT e.id, e.name, e.manager_id, eh.level + 1
- FROM employees e
- JOIN employee_hierarchy eh ON e.manager_id = eh.id
- )
- SELECT * FROM employee_hierarchy ORDER BY level, name;
复制代码
时间序列分析用于分析随时间变化的数据趋势:
- -- 按月统计销售额
- SELECT
- DATE_FORMAT(order_date, '%Y-%m') AS month,
- COUNT(*) AS order_count,
- SUM(amount) AS total_amount
- FROM orders
- GROUP BY DATE_FORMAT(order_date, '%Y-%m')
- ORDER BY month;
- -- 计算同比增长率
- SELECT
- current.month,
- current.order_count,
- previous.order_count AS prev_year_count,
- (current.order_count - previous.order_count) / previous.order_count * 100 AS growth_rate
- FROM (
- SELECT
- DATE_FORMAT(order_date, '%Y-%m') AS month,
- COUNT(*) AS order_count
- FROM orders
- GROUP BY DATE_FORMAT(order_date, '%Y-%m')
- ) current
- LEFT JOIN (
- SELECT
- DATE_FORMAT(DATE_SUB(order_date, INTERVAL 1 YEAR), '%Y-%m') AS month,
- COUNT(*) AS order_count
- FROM orders
- GROUP BY DATE_FORMAT(DATE_SUB(order_date, INTERVAL 1 YEAR), '%Y-%m')
- ) previous ON current.month = previous.month
- ORDER BY current.month;
复制代码
数据透视表用于将行数据转换为列数据,便于分析:
- -- MySQL 8.0+/PostgreSQL/SQL Server使用条件聚合
- SELECT
- department_id,
- SUM(CASE WHEN gender = '男' THEN 1 ELSE 0 END) AS male_count,
- SUM(CASE WHEN gender = '女' THEN 1 ELSE 0 END) AS female_count,
- COUNT(*) AS total_count
- FROM employees
- GROUP BY department_id;
- -- Oracle使用PIVOT
- SELECT *
- FROM (
- SELECT department_id, gender
- FROM employees
- )
- PIVOT (
- COUNT(gender)
- FOR gender IN ('男' AS male_count, '女' AS female_count)
- )
- ORDER BY department_id;
复制代码
2. 复杂查询实例分析
假设我们有以下表结构:
• products:产品表
• sales:销售记录表
• customers:客户表
- -- 查询每个产品类别的月度销售额和同比增长率
- WITH monthly_sales AS (
- SELECT
- p.category,
- DATE_FORMAT(s.sale_date, '%Y-%m') AS month,
- SUM(s.amount) AS total_amount
- FROM sales s
- JOIN products p ON s.product_id = p.id
- GROUP BY p.category, DATE_FORMAT(s.sale_date, '%Y-%m')
- ),
- yearly_comparison AS (
- SELECT
- m1.category,
- m1.month,
- m1.total_amount AS current_year_amount,
- m2.total_amount AS previous_year_amount,
- (m1.total_amount - m2.total_amount) / m2.total_amount * 100 AS growth_rate
- FROM monthly_sales m1
- LEFT JOIN monthly_sales m2
- ON m1.category = m2.category
- AND DATE_FORMAT(DATE_SUB(STR_TO_DATE(m1.month, '%Y-%m'), INTERVAL 1 YEAR), '%Y-%m') = m2.month
- )
- SELECT
- category,
- month,
- current_year_amount,
- previous_year_amount,
- growth_rate
- FROM yearly_comparison
- ORDER BY category, month;
复制代码- -- 使用RFM模型分析客户价值
- -- R (Recency): 最近一次购买时间
- -- F (Frequency): 购买频率
- -- M (Monetary): 购买金额
- WITH customer_rfm AS (
- SELECT
- c.id AS customer_id,
- c.name AS customer_name,
- DATEDIFF(NOW(), MAX(s.sale_date)) AS recency,
- COUNT(DISTINCT s.id) AS frequency,
- SUM(s.amount) AS monetary
- FROM customers c
- JOIN sales s ON c.id = s.customer_id
- GROUP BY c.id, c.name
- ),
- rfm_scores AS (
- SELECT
- customer_id,
- customer_name,
- recency,
- frequency,
- monetary,
- NTILE(5) OVER (ORDER BY recency DESC) AS r_score,
- NTILE(5) OVER (ORDER BY frequency) AS f_score,
- NTILE(5) OVER (ORDER BY monetary) AS m_score
- FROM customer_rfm
- ),
- rfm_segments AS (
- SELECT
- customer_id,
- customer_name,
- recency,
- frequency,
- monetary,
- r_score,
- f_score,
- m_score,
- CASE
- WHEN r_score >= 4 AND f_score >= 4 AND m_score >= 4 THEN 'Champions'
- WHEN r_score >= 3 AND f_score >= 3 AND m_score >= 3 THEN 'Loyal Customers'
- WHEN r_score >= 4 AND f_score <= 2 THEN 'New Customers'
- WHEN r_score <= 2 AND f_score >= 3 AND m_score >= 3 THEN 'At Risk'
- WHEN r_score <= 2 AND f_score <= 2 AND m_score <= 2 THEN 'Lost'
- ELSE 'Others'
- END AS segment
- FROM rfm_scores
- )
- SELECT
- segment,
- COUNT(*) AS customer_count,
- AVG(recency) AS avg_recency,
- AVG(frequency) AS avg_frequency,
- AVG(monetary) AS avg_monetary
- FROM rfm_segments
- GROUP BY segment
- ORDER BY customer_count DESC;
复制代码- -- 计算库存周转率和安全库存水平
- WITH inventory_analysis AS (
- SELECT
- p.id AS product_id,
- p.name AS product_name,
- p.category,
- p.current_stock,
- p.unit_cost,
- COALESCE(SUM(s.quantity), 0) AS total_sold,
- COALESCE(COUNT(DISTINCT s.sale_date), 0) AS days_with_sales,
- DATEDIFF(NOW(), COALESCE(MIN(s.sale_date), NOW())) AS days_since_first_sale
- FROM products p
- LEFT JOIN sales s ON p.id = s.product_id
- GROUP BY p.id, p.name, p.category, p.current_stock, p.unit_cost
- ),
- inventory_metrics AS (
- SELECT
- product_id,
- product_name,
- category,
- current_stock,
- unit_cost,
- total_sold,
- days_with_sales,
- days_since_first_sale,
- CASE
- WHEN days_with_sales > 0 THEN (total_sold / days_with_sales) * 30 -- 月均销售量
- ELSE 0
- END AS avg_monthly_sales,
- CASE
- WHEN days_with_sales > 0 THEN current_stock / (total_sold / days_with_sales) -- 库存天数
- ELSE 999
- END AS days_of_inventory,
- CASE
- WHEN days_with_sales > 0 THEN (total_sold / days_with_sales) * 7 * 2 -- 2周销量作为安全库存
- ELSE 0
- END AS safety_stock
- FROM inventory_analysis
- )
- SELECT
- product_id,
- product_name,
- category,
- current_stock,
- unit_cost,
- current_stock * unit_cost AS inventory_value,
- avg_monthly_sales,
- days_of_inventory,
- safety_stock,
- CASE
- WHEN days_of_inventory > 90 THEN 'Overstocked'
- WHEN days_of_inventory < 14 THEN 'Understocked'
- ELSE 'Optimal'
- END AS inventory_status
- FROM inventory_metrics
- ORDER BY days_of_inventory DESC;
复制代码
七、学习资源与进阶路径
1. 推荐学习资源
• W3Schools SQL Tutorial:https://www.w3schools.com/sql/适合初学者的基础SQL教程,包含交互式示例
• 适合初学者的基础SQL教程,包含交互式示例
• SQLZOO:https://sqlzoo.net/提供交互式SQL练习,覆盖从基础到高级的各种主题
• 提供交互式SQL练习,覆盖从基础到高级的各种主题
• Mode Analytics SQL Tutorial:https://mode.com/sql-tutorial/面向数据分析的SQL教程,包含实际业务场景
• 面向数据分析的SQL教程,包含实际业务场景
• PostgreSQL官方文档:https://www.postgresql.org/docs/PostgreSQL数据库的完整官方文档,包含详细的SQL参考
• PostgreSQL数据库的完整官方文档,包含详细的SQL参考
• MySQL官方文档:https://dev.mysql.com/doc/MySQL数据库的完整官方文档
• MySQL数据库的完整官方文档
W3Schools SQL Tutorial:https://www.w3schools.com/sql/
• 适合初学者的基础SQL教程,包含交互式示例
SQLZOO:https://sqlzoo.net/
• 提供交互式SQL练习,覆盖从基础到高级的各种主题
Mode Analytics SQL Tutorial:https://mode.com/sql-tutorial/
• 面向数据分析的SQL教程,包含实际业务场景
PostgreSQL官方文档:https://www.postgresql.org/docs/
• PostgreSQL数据库的完整官方文档,包含详细的SQL参考
MySQL官方文档:https://dev.mysql.com/doc/
• MySQL数据库的完整官方文档
• 《SQL必知必会》by Ben Forta适合初学者的入门书籍,简明扼要地介绍了SQL的基础知识
• 适合初学者的入门书籍,简明扼要地介绍了SQL的基础知识
• 《SQL学习指南》by Alan Beaulieu深入浅出地介绍了SQL的各个方面,适合有一定基础的读者
• 深入浅出地介绍了SQL的各个方面,适合有一定基础的读者
• 《高性能MySQL》by Baron Schwartz等专注于MySQL性能优化的经典书籍
• 专注于MySQL性能优化的经典书籍
• 《SQL权威指南》by Allen G. Taylor全面的SQL参考书,涵盖了SQL的各个方面
• 全面的SQL参考书,涵盖了SQL的各个方面
《SQL必知必会》by Ben Forta
• 适合初学者的入门书籍,简明扼要地介绍了SQL的基础知识
《SQL学习指南》by Alan Beaulieu
• 深入浅出地介绍了SQL的各个方面,适合有一定基础的读者
《高性能MySQL》by Baron Schwartz等
• 专注于MySQL性能优化的经典书籍
《SQL权威指南》by Allen G. Taylor
• 全面的SQL参考书,涵盖了SQL的各个方面
• Coursera - “SQL for Data Science”by University of California, Davis面向数据科学的SQL课程
• 面向数据科学的SQL课程
• Udemy - “The Complete SQL Bootcamp”by Jose Portilla全面的SQL入门课程,包含大量实践练习
• 全面的SQL入门课程,包含大量实践练习
• edX - “Introduction to Databases”by Stanford University斯坦福大学的数据库入门课程,包含SQL基础
• 斯坦福大学的数据库入门课程,包含SQL基础
Coursera - “SQL for Data Science”by University of California, Davis
• 面向数据科学的SQL课程
Udemy - “The Complete SQL Bootcamp”by Jose Portilla
• 全面的SQL入门课程,包含大量实践练习
edX - “Introduction to Databases”by Stanford University
• 斯坦福大学的数据库入门课程,包含SQL基础
• LeetCode:https://leetcode.com/提供大量SQL编程题,适合提高SQL技能
• 提供大量SQL编程题,适合提高SQL技能
• HackerRank:https://www.hackerrank.com/domains/sql提供各种难度的SQL挑战
• 提供各种难度的SQL挑战
• StrataScratch:https://www.stratascratch.com/提供真实公司面试中的SQL问题
• 提供真实公司面试中的SQL问题
LeetCode:https://leetcode.com/
• 提供大量SQL编程题,适合提高SQL技能
HackerRank:https://www.hackerrank.com/domains/sql
• 提供各种难度的SQL挑战
StrataScratch:https://www.stratascratch.com/
• 提供真实公司面试中的SQL问题
2. SQL进阶学习路径
• 学习目标:掌握基本的SQL查询和操作
• 学习内容:基本SELECT语句WHERE条件过滤ORDER BY排序GROUP BY分组和聚合函数基本的INSERT、UPDATE、DELETE操作
• 基本SELECT语句
• WHERE条件过滤
• ORDER BY排序
• GROUP BY分组和聚合函数
• 基本的INSERT、UPDATE、DELETE操作
• 实践项目:创建一个简单的数据库(如图书管理系统)编写基本的查询和报表
• 创建一个简单的数据库(如图书管理系统)
• 编写基本的查询和报表
• 基本SELECT语句
• WHERE条件过滤
• ORDER BY排序
• GROUP BY分组和聚合函数
• 基本的INSERT、UPDATE、DELETE操作
• 创建一个简单的数据库(如图书管理系统)
• 编写基本的查询和报表
• 学习目标:掌握多表查询和高级操作
• 学习内容:各种JOIN操作子查询集合操作(UNION, INTERSECT, EXCEPT)CASE表达式日期和时间函数
• 各种JOIN操作
• 子查询
• 集合操作(UNION, INTERSECT, EXCEPT)
• CASE表达式
• 日期和时间函数
• 实践项目:设计和实现一个更复杂的数据库(如电商系统)编写复杂的多表查询和报表
• 设计和实现一个更复杂的数据库(如电商系统)
• 编写复杂的多表查询和报表
• 各种JOIN操作
• 子查询
• 集合操作(UNION, INTERSECT, EXCEPT)
• CASE表达式
• 日期和时间函数
• 设计和实现一个更复杂的数据库(如电商系统)
• 编写复杂的多表查询和报表
• 学习目标:掌握高级SQL特性和性能优化
• 学习内容:窗口函数公用表表达式(CTE)递归查询索引设计和优化查询性能调优执行计划分析
• 窗口函数
• 公用表表达式(CTE)
• 递归查询
• 索引设计和优化
• 查询性能调优
• 执行计划分析
• 实践项目:优化现有数据库查询性能设计和实现一个高性能的数据库系统
• 优化现有数据库查询性能
• 设计和实现一个高性能的数据库系统
• 窗口函数
• 公用表表达式(CTE)
• 递归查询
• 索引设计和优化
• 查询性能调优
• 执行计划分析
• 优化现有数据库查询性能
• 设计和实现一个高性能的数据库系统
• 学习目标:成为SQL专家,能够处理复杂业务场景
• 学习内容:特定数据库的高级特性(如MySQL的存储过程、PostgreSQL的JSON支持等)数据仓库和OLAP技术大数据SQL(如Hive、Spark SQL)NoSQL数据库的查询语言
• 特定数据库的高级特性(如MySQL的存储过程、PostgreSQL的JSON支持等)
• 数据仓库和OLAP技术
• 大数据SQL(如Hive、Spark SQL)
• NoSQL数据库的查询语言
• 实践项目:参与实际企业级数据库项目解决复杂的业务数据分析问题学习和分享SQL最佳实践
• 参与实际企业级数据库项目
• 解决复杂的业务数据分析问题
• 学习和分享SQL最佳实践
• 特定数据库的高级特性(如MySQL的存储过程、PostgreSQL的JSON支持等)
• 数据仓库和OLAP技术
• 大数据SQL(如Hive、Spark SQL)
• NoSQL数据库的查询语言
• 参与实际企业级数据库项目
• 解决复杂的业务数据分析问题
• 学习和分享SQL最佳实践
通过系统学习和不断实践,你将能够从SQL入门逐步成长为精通SQL的专家,能够高效地处理各种数据查询和分析任务。记住,学习SQL是一个持续的过程,随着技术的发展,新的功能和最佳实践不断涌现,保持学习的热情和好奇心是成为SQL专家的关键。 |
|