参考 :SQL 常用语句大全【SQL】_常用sql-优快云博客
mysql安装地址:
【mysql】mysql安装使用教程(非常详细),零基础入门到精通,看这一篇就够了_mysql安装教程-优快云博客
基础查询
1.创建数据库
CREATE DATABASE myDatabase;
列出所有可用的数据库:
SHOW DATABASES;
选择要使用的数据库:
USE your_database;
列出所选数据库中的所有表:
SHOW TABLES;
2. 创建表
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INT,
grade VARCHAR(50)
);
3.基础的查询数据 select , where ,and , or
SELECT Name,Age,Sex
FROM UserInfo
WHERE Sex='男' AND Age=26
SELECT Name,Age,Sex
FROM UserInfo
WHERE Sex='男' or Age=26
4. not
SELECT Name,Age,Sex
FROM UserInfo
WHERE NOT Sex ='男' --注意是WHERE NOT不要写成WHERE Sex NOT
5. in , not in 的用法
6.exists
SQL语句中exists用法_sql exists-优快云博客
select origin_num from pupu_oms.billsource
where exists (select origin_num from pupu_oms.billsource
where origin_num = "71050071124")
含义解析:exists 的意思是用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False
7.between, not between
注意是 是包含边界值的
SQL 基础 | BETWEEN 的常见用法_sql between-优快云博客
8. like 操作符
not like
某个字段同时满足多个条件
9.regexp
SQL语言之正则表达式regexp的用法_sql regexp-优快云博客
-- 查找符合格式的邮箱
SELECT * FROM users
WHERE email REGEXP '^[a-zA-Z][a-zA-Z0-9_.-]*\\@leetcode\\.com$'
-
转义规则:
-
SQL字符串本身使用反斜杠转义
-
正则表达式也需要转义
-
因此
\@
和\.
需要写成\\@
和\\.
-
10. null
null 和 ‘’ 的区别
null 表示未知 或者不存在
空字符串‘’是有效的字符串值,长度为0
1)null在聚合函数(sum,avg,min,max)中会被直接过滤掉,而''不会被过滤掉
数据库:
COUNT()函数:
-
COUNT(*)
:计算所有行,包括NULL -
COUNT(column)
:只计算该列非NULL的行 -
COUNT('')
:会计算空字符串
2)对于null的判断需要is null或is not null, 而''则需要= 或者 !=, <>
3)null占用存储空间,''不占用存储空间
11. AS
12. insert into ...values...
指定列:
-- 假设有students表(id, name, age, gender, score)
INSERT INTO students (name, age, score)
VALUES ('张三', 20, 89.5);则其他值将使用默认值或NULL
不指定列
INSERT INTO students
VALUES (NULL, '张三', 20, '男', 89.5);
插入多行数据:
INSERT INTO students (name, age, gender)
VALUES
('王五', 22, '男'),
('赵六', 20, '女'),
('钱七', 21, '男');
13. update ... set ...
14. delete from ... where...
15.order by
MySQL order by关键字详解,order by排序-优快云博客
16. contact
select concat("'", id, "',")
from table
where condition
可以对搜索结果 加上 ' '
17. drop
1. 删除表 (DROP TABLE)
-- 基本语法 DROP TABLE table_name; -- 安全写法(避免表不存在时报错) DROP TABLE IF EXISTS employees; -- 示例 DROP TABLE temp_users;
2. 删除数据库 (DROP DATABASE)
-- 基本语法 DROP DATABASE database_name; -- 安全写法 DROP DATABASE IF EXISTS old_inventory; -- 示例(谨慎使用!会删除所有数据) DROP DATABASE test_db;
3. 删除视图 (DROP VIEW)
DROP VIEW view_name; -- 示例 DROP VIEW customer_summary;
4. 删除索引 (DROP INDEX)
-- MySQL语法 DROP INDEX index_name ON table_name; -- 示例 DROP INDEX idx_customer_name ON customers;
18. alter
ALTER 是 SQL 中用于修改现有数据库对象结构的数据定义语言(DDL)命令。它允许您在不删除和重建对象的情况下更改表、视图、索引等数据库对象的结构
1. 添加列
ALTER TABLE 表名 ADD COLUMN 列名 数据类型 [约束条件]; -- 示例 ALTER TABLE employees ADD COLUMN email VARCHAR(100) NOT NULL;
2. 删除列
ALTER TABLE 表名 DROP COLUMN 列名; -- 示例 ALTER TABLE employees DROP COLUMN home_phone;
3. 修改列定义
-- 修改数据类型 ALTER TABLE 表名 MODIFY COLUMN 列名 新数据类型; -- 示例 ALTER TABLE products MODIFY COLUMN price DECIMAL(10,2); -- 重命名列 (MySQL语法) ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 数据类型; -- 示例 ALTER TABLE customers CHANGE COLUMN cust_name customer_name VARCHAR(50);
4. 添加约束
-- 添加主键
ALTER TABLE 表名
ADD PRIMARY KEY (列名);
-- 添加外键
ALTER TABLE 子表
ADD CONSTRAINT 约束名
FOREIGN KEY (列名) REFERENCES 父表(列名);
-- 添加唯一约束
ALTER TABLE 表名
ADD UNIQUE (列名);
-- 示例
ALTER TABLE orders
ADD CONSTRAINT fk_customer
FOREIGN KEY (customer_id) REFERENCES customers(id);
6. 重命名表
ALTER TABLE 旧表名
RENAME TO 新表名;
-- 示例
ALTER TABLE emp
RENAME TO employees;
5. 删除约束
ALTER TABLE 表名 DROP 约束名; -- MySQL删除主键 ALTER TABLE 表名 DROP PRIMARY KEY;
19. increment
20.视图
SQL CREATE VIEW、REPLACE VIEW、 DROP VIEW 语句 | 菜鸟教程
视图: 基于一个或者多个表的查询结果集构建的虚拟表,它不实际存储数据,只存储定义,每次访问视图的时候,都会执行其定义的查询
优点:
1.数据安全和权限控制
2.简化复杂的查询
3.进行数据整合,统一分散在不同表的相关的数据
1. 创建视图
CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table1
JOIN table2 ON condition
WHERE condition
GROUP BY column
HAVING condition;
2. 修改视图
CREATE OR REPLACE VIEW view_name AS SELECT ...; -- 新查询语句
3. 删除视图
DROP VIEW [IF EXISTS] view_name;
21. distinct
DISTINCT
是 SQL 中用于返回唯一(不重复)值的关键字,它可以应用于单个列或多个列的组合
数据库
单列去重 :
多列去重: 此时返回的是 addressId 和City的唯一组合
和聚合函数一起使用
常用语句
1. group by
group by与order by的区别_group by和order by-优快云博客
数据库:
使用: group by
SELECT子句中非聚合列必须出现在GROUP BY子句中
GROUP BY通常出现在WHERE之后,ORDER BY之前
结合having使用,having是对分组后的结果进行过滤
结合order by 使用
2.having
零基础自学SQL课程 | HAVING子句_51CTO博客_sql零基础教程
举例: 在students表中,找出学生编号sid小于8的记录,并查找每个班主任带的男女学生数量,最后输出梳理大于2的记录
select Tid , Ssex, count(*) as num
from students
where Sid<8
group by Tid, Ssex
having num > 2
group by 后未出现的列,则不能出现在select 中,select 中没有出现的列,则不能出现在having中
where 与 having的区别
where是在group by分组前进行条件筛选,后面不可以跟聚合函数
having是在group by分组之后进行条件筛选,后面可以直接跟聚合函数
3.rolloup
注意只能在mysql中使用
数据库:
使用with rollup , 必须跟在group by后面
场景: 汇总整个结果集的数据
场景:汇总每个组以及整个结果集的数据
联表查询
1. inner join
它的主要作用是从两个或多个表中返回满足连接条件的记录
2.left join
-
返回左表(表A)的所有行
-
对于左表的每一行,如果在右表(表B)中找到匹配行,则合并这两行
-
如果在右表中没有匹配行,则右表的所有列将显示为NULL
3. right join
4. full outer join
mysql不支持 full outer join
5. union , union all
union用户合并两个或多个 SELECT 语句的结果集,使用 UNION 时,每个 SELECT 语句必须具有相同数量的列,且对应列的数据类型必须相似
特点:
-
合并结果集:将多个查询结果合并为一个结果集
-
去除重复行:自动删除重复的行(与
UNION ALL
不同) -
列数必须相同:所有 SELECT 语句必须有相同数量的列
-
数据类型兼容:对应列的数据类型必须兼容或可隐式转换
注意事项:
-
列名规则:最终结果集的列名取自第一个 SELECT 语句
-
排序处理:ORDER BY 子句只能出现在最后一个 SELECT 语句后
-
性能考虑:UNION 会执行去重操作,大数据量时可能影响性能
sql约束
约束是用于限制表中数据类型的规则,保证数据完整性
约束可以在创建表时规定(通过 CREATE TABLE 语句),或者在表创建之后规定(通过 ALTER TABLE 语句)
1. PRIMARY KEY (主键约束)
作用:唯一标识表中的每一行记录
特点:
-
不允许NULL值
-
不允许重复值
-
一个表只能有一个主键
-- 建表时创建
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50)
);-- 已有表添加
ALTER TABLE users
ADD PRIMARY KEY (user_id);-- 复合主键
CREATE TABLE orders (
order_id INT,
product_id INT,
PRIMARY KEY (order_id, product_id)
);
2. FOREIGN KEY (外键约束)
作用:维护两个表之间的关系
特点:
-
确保引用完整性
-
被引用列必须是主键或唯一键
CREATE TABLE orders (
order_id INT PRIMARY KEY,
user_id INT,
FOREIGN KEY (user_id) REFERENCES users(user_id)
);-- 添加级联操作
ALTER TABLE orders
ADD CONSTRAINT fk_user
FOREIGN KEY (user_id) REFERENCES users(user_id)
ON DELETE CASCADE;
3. NOT NULL (非空约束)
作用:强制列不接受NULL值
使用方式:
CREATE TABLE employees ( emp_id INT PRIMARY KEY, emp_name VARCHAR(100) NOT NULL, hire_date DATE NOT NULL );
4.UNIQUE (唯一约束)
作用:确保列中的所有值都不同
特点:
-
允许NULL值(但只能有一个NULL)
-
一个表可以有多个唯一约束
使用方式:
CREATE TABLE products ( product_id INT PRIMARY KEY, product_code VARCHAR(20) UNIQUE, product_name VARCHAR(100) ); -- 添加复合唯一约束 ALTER TABLE product_suppliers ADD CONSTRAINT uc_product_supplier UNIQUE (product_id, supplier_id);
5.CHECK (检查约束)
作用:限制列中值的范围
使用方式:
CREATE TABLE employees ( emp_id INT PRIMARY KEY, emp_name VARCHAR(100) NOT NULL, salary DECIMAL(10,2) CHECK (salary > 0), age INT CHECK (age >= 18 AND age <= 65) ); -- 表级检查约束 ALTER TABLE orders ADD CONSTRAINT chk_order_amount CHECK (amount >= 100 OR priority = 'HIGH');
6. DEFAULT (默认约束)
作用:当插入数据未指定值时提供默认值
使用方式:
CREATE TABLE orders ( order_id INT PRIMARY KEY, order_date DATE DEFAULT CURRENT_DATE, status VARCHAR(20) DEFAULT 'PENDING' );
7.INDEX (索引约束)
作用:加速数据检索(虽然严格来说不是约束,但常与约束配合使用)
使用方式:
CREATE INDEX idx_customer_name ON customers(last_name, first_name);
函数
1.时间函数
SQL Server 和 MySQL 中的 Date 函数 | 菜鸟教程
2.聚合函数: avg
AVG() 函数返回数值列的平均值
3.聚合函数: count
4.聚合函数: max , min
返回指定列的最大值 , 最小值
5.聚合函数: sum
返回指定列的和
6.upper ,lower
将字段的值转换为大写, 转为小写
7. mid
MID
函数在 SQL 中用于从字符串中提取子字符串(部分字符串)
基本语法
MID(string, start, length)
string
:要提取子字符串的原始字符串
start
:开始位置(从1开始计数)
length
:要提取的字符长度(可选,如果不指定则提取到字符串末尾)
-- 从第3个字符开始提取5个字符 SELECT MID('Hello World', 3, 5); -- 结果: 'llo W'-- 查找所有以'A'开头第3个字符的产品 SELECT * FROM products WHERE MID(product_name, 3, 1) = 'A';
8.length
9.round
-- 四舍五入到2位小数 SELECT ROUND(123.4567, 2); -- 结果: 123.46 -- 舍入到十位 SELECT ROUND(123.4567, -1); -- 结果: 120.0 -- 舍入到整数 SELECT ROUND(123.4567); -- 结果: 123
10. format
1. 数值格式化
FORMAT(number, decimal_places, [locale])
功能:将数字格式化为带千位分隔符和指定小数位的字符串
示例:
SELECT FORMAT(1234567.8912, 2); -- 结果: '1,234,567.89' SELECT FORMAT(1234567.8912, 3, 'de_DE'); -- 德国格式: '1.234.567,891'
2. 日期格式化(MySQL 8.0+)
DATE_FORMAT(date, format_string)
常用格式符:
%Y
:4位年份
%m
:月份(01-12)
%d
:日(01-31)
%H
:小时(00-23)
%i
:分钟(00-59)
%s
:秒(00-59)示例:
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'); -- 结果: '2023-04-15 14:30:45'
面试题总结
1. sql ,mysql的区别
2.sql语法的特征
3.数据库事务的特性
事务的概念: 事务(Transaction)是数据库操作的基本单位
事务的特性:
-
原子性(Atomicity):事务是不可分割的工作单位,要么全部执行,要么全部不执行
-
一致性(Consistency):事务执行前后,数据库从一个一致状态变到另一个一致状态
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务
-
持久性(Durability):事务一旦提交,其结果就是永久性的
4. 主键,外键,唯一性约束的区别
主键(Primary Key):
- 定义:主键是一个数据库字段,它的值唯一标识每一条数据库记录
- 确保每条记录在数据库中是独一无二的,防止数据重复
外键(Foreign Key):
- 定义:外键是数据库字段,它引用了另一个表中的字段,用于建立表与表之间的关系。
- 作用:确保表之间的数据关联,保持数据的一致性。例如,学生表的“老师ID”字段作为外键,引用教师表中的“教师ID”字段
唯一性约束(Unique Constraint):
- 定义:唯一性约束确保数据库中某一列中的数据不会重复。
- 作用:防止数据重复,确保数据的准确性和完整性。
- 应用场景:可以应用在任何字段上,不仅限于主键字段。例如,客户表中的“客户编号”字段可以设置唯一性约束。
- 特点:与主键不同,唯一性约束可以应用在非主键字段上,但主键通常也会设置唯一性约束
5. 用sql语句,判断出某列是否存在重复的值
用group by, having
select column , count(* ) as repeat_count from table group by column having repeat_count >1
实例:
6.死锁
死锁的概念
记忆方式:
-
破坏任意一个条件即可避免死锁:
-
破坏"互斥":用乐观锁代替悲观锁
-
破坏"占有且等待":事务开始时一次性申请所有资源
-
破坏"非抢占":设置锁超时(如MySQL的
innodb_lock_wait_timeout
) -
破坏"循环等待":按固定顺序访问表和行
-
数据库如何处理死锁
1. 死锁检测机制
-
大多数RDBMS使用**等待图(wait-for graph)**算法检测循环等待
-
检测周期从几毫秒到几秒不等
2. 死锁解决策略
检测到死锁后,数据库会:
-
选择一个事务作为牺牲者(victim)
-
回滚该事务并释放其所有锁
-
返回1213错误(MySQL)或类似的死锁错误码
-
其他事务可以继续执行
如何避免死锁
1. 应用层最佳实践
-
统一访问顺序:确保所有事务按相同顺序访问表和行
-
减少事务大小:缩短事务持续时间,尽快提交
-
合理设置隔离级别:避免不必要的锁
-
添加重试机制:捕获死锁异常后自动重试
2. 数据库设计优化
-
添加适当的索引:减少锁的范围
-
避免热点更新:如顺序ID计数器可考虑使用UUID
-
合理设计表结构:减少跨表事务
3. 数据库配置调整
-
设置锁等待超时:
SET innodb_lock_wait_timeout=50;
(MySQL) -
调整死锁检测频率:部分数据库支持配置
乐观锁和悲观锁的概念
乐观锁和悲观锁是两种不同的并发控制策略,用于解决多事务/多线程环境下的数据一致性问题
悲观锁
基本思想: "先加锁,后操作" - 假设冲突经常发生,操作数据前先加锁,确保独占访问
特点
-
适用于写多读少的高冲突场景
-
由数据库原生支持,实现简单
-
会阻塞其他事务,可能引发死锁
-
降低系统吞吐量
1. SQL语句显式加锁
-- MySQL/SQL Server/Oracle等通用语法 SELECT * FROM accounts WHERE id = 1 FOR UPDATE; -- 排他锁
2. 事务隔离级别控制
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -- 最高隔离级别(最悲观
乐观锁
基本思想: "先操作,后检查" - 假设冲突很少发生,操作时不加锁,提交时检查是否冲突
特点
-
适用于读多写少的低冲突场景
-
无阻塞,系统吞吐量高
-
需要应用层实现冲突检测
-
可能产生更多重试操作
1. 版本号机制 (最常用)
-- 表添加version字段 UPDATE products SET stock = stock - 1, version = version + 1 WHERE id = 100 AND version = 5; -- 如果version已被修改则更新失败
7.索引
索引是对数据库表中一列或多列的值进行排序的结构,它能够显著提高查询效率
为什么索引能加快查询速度:
数据库的索引能加快查询速度的核心原因在于其通过特定的数据结构(如 B 树、哈希表等)对数据进行预处理,避免全表扫描,减少磁盘 I/O 次数,从而提升查询效率
索引的类型
按功能分类:
-
普通索引:最基本的索引类型,无约束
-
唯一索引:确保索引列的值唯一
-
主键索引:特殊的唯一索引,不允许NULL值
-
复合索引:基于多个列的索引
-
全文索引:用于全文搜索
-
空间索引:用于地理空间数据
索引的创建与管理
创建索引:
-- 基本语法 CREATE [UNIQUE] INDEX index_name ON table_name (column1 [ASC|DESC], ...);-- 单列索引 CREATE INDEX idx_employee_name ON employees(last_name);-- 示例 多列复合索引 CREATE INDEX idx_customer_name ON customers(last_name, first_name);
查看索引:
-- MySQL
SHOW INDEX FROM table_name;
删除索引:
DROP INDEX index_name ON table_name;
自动使用索引的情况
当查询满足以下条件时,数据库通常会使用索引:
-
WHERE子句中的条件列有索引
-
JOIN操作的关联列有索引
-
ORDER BY/GROUP BY的列有索引
索引的具体应用场景
1. 等值查询
-- 使用name列的索引 SELECT * FROM customers WHERE name = '张三';
2. 范围查询
-- 使用date列的索引 SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';
3. 排序优化
-- 使用hire_date索引避免全表排序 SELECT * FROM employees ORDER BY hire_date DESC;
4. 连接查询优化
-- 在department_id上建立索引可加速连接 SELECT e.name, d.department_name FROM employees e JOIN departments d ON e.department_id = d.department_id;
索引失效的常见情况
-
对索引列使用函数或计算:
-- 索引失效 SELECT * FROM users WHERE YEAR(create_time) = 2023;
-
使用不等于操作符(!= 或 <>)
-
使用LIKE以通配符开头:
-- 索引失效 SELECT * FROM users WHERE username LIKE '%son';
-
类型转换(如字符串列用数字查询)
-
OR条件未全部使用索引
复合索引的使用
最左前缀原则
复合索引遵循"最左前缀"匹配原则,即查询必须使用索引的最左列才能利用索引。
有效使用索引的查询:
-- 使用索引列1 SELECT * FROM employees WHERE last_name = 'Smith'; -- 使用索引列1和列2 SELECT * FROM employees WHERE last_name = 'Smith' AND age = 30;
无法使用索引的查询:
-- 未使用最左列(last_name) SELECT * FROM employees WHERE age = 30; -- 跳过了中间列 SELECT * FROM employees WHERE last_name = 'Smith' AND salary > 5000;
8. sql注入
sql注入简单例子(非常详细),零基础入门到精通,看这一篇就够了-优快云博客
SQL注入是一种常见的网络安全攻击技术,攻击者通过在应用程序的输入字段中插入恶意的SQL代码,从而欺骗数据库执行非预期的命令
步骤一 : 判断注入点
判断输入值是数字型 还是 字符型 : 可直接看页面功能,或者是:
如果id=n和id=(n+1)-1产生的结果一致,则可能是数字型,再尝试添加闭合符号时sql执行出错,就能证明注入点的数据类型为数字型
若返回的接口不一致,则为字符型
若:
判断字符型(先是报错再闭合),如果有原始数据库报错信息,就一一枚举可能得闭合符号 :
' " ` ') ") `) ')) ")) ```))通过输入各种引号和括号,观察是否报错,如果系统返回数据库错误(如MySQL、SQL Server等错误信息),证明用户输入被直接拼接到SQL中
判断注入点是否存在: 在疑似注入点后面加上: and 1=1 , 和and 1=2 ,如果两次执行的页面发生了变化,则说明拼接的语句在数据库中执行的时候出了问题,页面会有所改变
可以看到,当使用and 1=2时,界面发生了明显的变化(此时sql语句被拼接再到数据库中执行时,由于条件 and 1=2 不成立,sql没有出错,但语句查询不出结果,也就无法再界面中显示什么内容。到这里我们大概知道:
当我们输入的内容经过后端文件拼接,带到数据库中执行后,如果sql语句语法正确且查询有结果,那前端界面中就会显示 “You are in…………”,
如果sql语句出现了语法错误,前端界面中就会将错误信息打印出来
如果sql语句语法没问题,但给出的条件不成立,sql语句查询不到任何内容,界面就会“空空如也”
页面发生了改变,说明存在注入点
步骤二: 判断表中的列数
利用order by 结合折半查找的方式确定表中的列数
步骤三判断:字段回显的位置
利用union并将原始查询置空(置空的目的,是让union前面的select查询语句查不到结果,union前面的select语句就不会输出内容,使整个sql语句只输出union后面select语句的查询内容(也就是我们想要看到的内容))来判断数据回显的位置
步骤四 : 判断数据库信息
利用内置函数暴数据库信息
version()版本;database()数据库;user()用户;
不用猜解可用字段暴数据库信息(有些网站不适用):
and 1=2 union all select version()
and 1=2 union all select database()
and 1=2 union all select user()
操作系统信息:and 1=2 union all select @@global.version_compile_os from mysql.user
数据库权限:
and ord(mid(user(),1,1))=114 返回正常说明为root
步骤五:查找数据库名
步骤六:查找数据库表名
步骤七:查找列名
http://127.0.0.1/sqli-labs-master/Less-3/?id=-1%27)%20union%20select%201,2,group_concat(column_name)%20from%20information_schema.columns%20where%20table_schema%20=%20%27security%27%20and%20table_name%20=%20%27users%27--+
步骤八: 知道表名知道列名,获取数据
http://127.0.0.1/sqli-labs-master/Less-3/?id=-1%27)%20union%20select%201,2,group_concat(id,username,password)%20from%20users--+
以下是错误了,可以忽略
SQL注入的简单示例
假设有一个登录表单,后端SQL查询如下:
-- 不安全的方式(直接拼接用户输入) SELECT * FROM users WHERE username = '$username' AND password = '$password'攻击者可以输入:
用户名:
admin' --
密码:任意值
最终SQL变为:
SELECT * FROM users WHERE username = 'admin' --' AND password = '任意值'
--
是SQL注释符号,使得密码检查被忽略,攻击者无需密码即可登录admin账户。
基础探测语句
搜索场景: 检测是否存在注入漏洞
' " ` ') ") `) ')) ")) ```))通过输入各种引号和括号,观察是否报错,如果系统返回数据库错误(如MySQL、SQL Server等错误信息),证明用户输入被直接拼接到SQL中
注释掉后续SQL
搜索场景: test' -- test' # test' /*这些符号在SQL中表示注释,可以截断原查询
登录场景:
用户名: admin' --
密码: [任意或不填]成功登录admin账户
提取用户数据
product.php?id=1 UNION SELECT 1,username,password,4 FROM users --分解为:
' - 闭合原查询中的字符串引号 , 需要看前面的字段是否未字符串,还是数字
UNION SELECT
- 添加联合查询
1,username,password,4
- 选择4列数据
FROM users
- 从users表获取数据
--
- 注释掉原查询剩余部分
如果攻击成功,网站可能会显示:
正确的产品搜索结果 后面跟着user表中 的所有用户名和密码
提取用户数据
正常请求:
/product.php?id=1 → 显示产品1的详情测试请求1:
/product.php?id=1 AND 1=1 → 仍然显示产品1测试请求2:
/product.php?id=1 AND 1=2 → 不显示任何产品则存在SQL注入漏洞
9.常用sql语句练习题
-- 员工表
CREATE TABLE Employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
salary DECIMAL(10, 2) NOT NULL,
hire_date DATE NOT NULL,
dept_id INT,
manager_id INT,
FOREIGN KEY (dept_id) REFERENCES Departments(dept_id),
FOREIGN KEY (manager_id) REFERENCES Employees(emp_id)
);
-- 部门表
CREATE TABLE Departments (
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL,
location VARCHAR(50)
);
-- 项目表
CREATE TABLE Projects (
project_id INT PRIMARY KEY AUTO_INCREMENT,
project_name VARCHAR(50) NOT NULL,
start_date DATE,
end_date DATE,
leader_id INT,
FOREIGN KEY (leader_id) REFERENCES Employees(emp_id)
);
-- 订单表
CREATE TABLE Orders (
order_id INT PRIMARY KEY AUTO_INCREMENT,
order_date DATE NOT NULL,
customer_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (product_id) REFERENCES Products(product_id)
);
-- 产品表
CREATE TABLE Products (
product_id INT PRIMARY KEY AUTO_INCREMENT,
product_name VARCHAR(50) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL,
category VARCHAR(50)
);
题目:查询工资高于本公司平均工资的员工。
思路: 先得到本公司的平均工资,再用用员工工资比较大小
SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
题目:查询每个部门工资最高的员工信息。
思路:先得到每个部门最高的工资, 再用部门id,员工薪资去做匹配
SELECT e.* FROM employees e JOIN ( SELECT dept_id, MAX(salary) AS max_salary FROM employees GROUP BY dept_id ) m ON e.dept_id = m.dept_id AND e.salary = m.max_salary;
查询没有分配到项目的员工
SELECT *
FROM Employees
WHERE emp_id NOT IN (SELECT DISTINCT leader_id FROM Projects);
查询订单数量最多的客户
select o.custom_id , count(o.order_id) as order_count
from orders o
group by o.custom_id
order by order_count desc
limit 1 ;
查询每个部门的平均薪资
SELECT
d.dept_name,
AVG(e.salary) AS avg_salary
FROM Departments d
JOIN Employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_name;
查询薪资第2高的员工
SELECT * FROM Employees WHERE salary = ( SELECT DISTINCT salary FROM Employees ORDER BY salary DESC LIMIT 1 OFFSET 1 );
查询订单日期在 2023 年的订单
SELECT * FROM Orders WHERE YEAR(order_date) = 2023;
查询薪资高于部门平均薪资的员工
select e.name, e.salary, d.depart_name
from Employees e
inner join Department d
on e.dept_id = d.dept_id
where e.salary >
(
select avg(salary)
from Empoyees
where dept_id =e.dept_id -- 这里用来限定当前员工所在部门,若不限定则为全公司的平均薪资
)
10. 什么是慢查询?
慢查询是指执行时间超过预设阈值的数据库查询操作
这类查询通常会消耗大量系统资源(如CPU、内存、磁盘I/O),导致数据库性能下降,影响整体应用响应速度
慢查询的常见原因
原因 | 示例 |
---|---|
缺少索引 | SELECT * FROM users WHERE name LIKE '%张%' (模糊查询未用索引) |
索引失效 | 对字段使用函数(如 WHERE YEAR(create_time) = 2023 ) |
大表全表扫描 | 未加条件查询百万级表:SELECT * FROM orders |
复杂连接或子查询 | 多层嵌套子查询或笛卡尔积连接 |
锁竞争 | 长事务持有锁,导致其他查询等待 |
数据量增长 | 初期性能正常的SQL,随数据量增加变慢 |
如何识别慢查询?
-
数据库日志
-
MySQL:开启慢查询日志(配置
slow_query_log=ON
,long_query_time=2
)。 -
PostgreSQL:设置
log_min_duration_statement=2000
(单位:毫秒)。
-
-
监控工具
-
如:Percona PMM、Datadog、Prometheus + Grafana。
-
-
执行计划分析
-
使用
EXPLAIN
命令查看SQL的执行计划,定位性能瓶颈(如全表扫描type=ALL
)
-
如何优化慢查询?
-
优化SQL语句
-
避免
SELECT *
,只查询必要字段。 -
用
JOIN
替代子查询,减少临时表生成。
-
-
合理使用索引
-
为高频查询条件添加索引(如
WHERE
、ORDER BY
字段)。 -
注意复合索引的最左匹配原则。
-
-
分库分表
-
对大数据表按时间或ID拆分(如按月分表)。
-
-
缓存层
-
使用Redis缓存热点查询结果。
-
-
数据库调优
-
调整缓冲区大小(如
innodb_buffer_pool_size
)、并发连接数等参数
-
11.数据库常见数据类型
一、数值类型
1. 整数类型
-
TINYINT:1字节,范围(-128~127)或(0~255)
-
SMALLINT:2字节,范围(-32,768~32,767)或(0~65,535)
-
INT/INTEGER:4字节,范围(-2³¹~2³¹-1)或(0~2³²-1)
-
BIGINT:8字节,大范围整数
-
BOOLEAN:布尔值(TRUE/FALSE),通常用TINYINT(1)实现
2. 浮点数类型
-
FLOAT:4字节,单精度浮点数
-
DOUBLE:8字节,双精度浮点数
-
DECIMAL(p,s)/NUMERIC:精确小数,p为总位数,s为小数位数
二、字符串类型
1. 定长字符串
-
CHAR(n):固定长度n的字符串,适合存储长度已知的数据(如身份证号)
2. 变长字符串
-
VARCHAR(n):最大长度n的可变长度字符串
-
TEXT:长文本数据(通常可达65,535字节)
-
LONGTEXT:更长的文本数据(通常可达4GB)
3. 二进制数据
-
BLOB:二进制大对象(如图片、PDF等)
-
LONGBLOB:更大的二进制对象
三、日期时间类型
-
DATE:日期值(YYYY-MM-DD)
-
TIME:时间值(HH:MM:SS)
-
DATETIME:日期时间(YYYY-MM-DD HH:MM:SS)
-
TIMESTAMP:时间戳(自动记录数据修改时间)
-
YEAR:年份值
12. 联表查询后,删除某条信息,其他表会怎么显示?
13.简述一下内连接和外连接?
内连接指的inner join: 返回的是两个表中满足连接条件的匹配行
外连接包含: 左外连接(返回左表的全部行,以及满足连接条件的右表匹配行,未匹配部分则用null填充),右外连接,全外连接
14.delete 语句,drop 语句
特性 | DELETE 语句 | DROP 语句 |
---|---|---|
操作对象 | 表中的数据行(记录) | 整个数据库、表、视图、索引等数据库对象 |
数据影响 | 仅删除数据,保留表结构 | 彻底删除对象,包括数据和结构 |
语法示例 | DELETE FROM users WHERE id = 1; | DROP TABLE users; 或 DROP DATABASE db_name; |
事务性 | 支持事务(可回滚) | 不支持事务(立即生效,不可回滚) |
执行速度 | 较慢(逐行删除,记录日志) | 极快(直接删除对象定义) |
TRIGGER 触发 | 会触发表上的 AFTER DELETE 触发器 | 不会触发触发器 |