一文掌握 SQL:数据定义、操作与查询完整教程

文章目录

结构化查询语言:SQL

SQL(Structured Query Language,结构化查询语言)是一种用于管理关系数据库系统的特定语言。通过 SQL 可以定义、操作和管理数据库中的数据,执行各种数据库操作。SQL 主要由数据定义语言(DDL)、数据操纵语言(DML)、数据控制语言(DCL)和事务控制语言(TCL)组成,用于定义数据库结构、操纵数据、控制访问权限以及管理事务。

SQL 适用于所有关系型数据库。MySQL、Oracle、SQLServer 是一个数据库软件,这些数据库软件支持标准 SQL,不过每一个数据库系统会在标准 SQL 的基础上扩展自己的 SQL 语法。大部分的 NoSQL 数据库有自己的操作语言,对 SQL 支持的并不好。

SQL 语法关键字大小写不敏感、通过 -- 写法可以添加注释信息。目前,SQL-92 是被广泛接受和应用的一个基本 SQL 标准版本。SQL 常见版本有:

SQL 版本 发布年份 主要特性
SQL-86 1986 年 基本的 SQL 标准
SQL-89/92 1989/1992 年 在 SQL-86 基础上扩展,增加额外功能
SQL-92 1992 年 连接操作、子查询、触发器等重要功能
SQL:1999 1999 年 窗口函数、递归查询等新功能
SQL:2003 2003 年 XML 支持、标量数据类型、增强连接操作等功能
SQL:2006 2006 年 根据 SQL:2003 进行修订和改进
SQL:2011 2011 年 时间区域、分析函数等新增功能
SQL:2016 2016 年 JSON 支持和其他改进

SQL 注入的原理是用户输入的内容作为了 SQL 语句语法的一部分,改变了原有 SQL 真正的意义,如:

sql 复制代码
select * from 表名 where username=用户传递的数据1 and password = 用户传递的数据2

此时,用户传入账号和密码。但是如果用户进行 sql 注入,用户传递的数据 2 为:

sql 复制代码
用户传递的数据2 or 1=1

通过拼接 SQL 语句会变成:

sql 复制代码
select * from 表名 where username=用户传递的数据1 and password = 用户传递的数据2 or 1=1

此时,不论用户传递的数据是否正确,都能查询出结果。

数据定义语言:DDL

DDL(Data Definition Language)即数据定义语言,是被用于定义数据库对象(包含数据库、表、字段)的语言。

数据库 DDL

关于 MySQL 数据库,常用的 DDL 操作命令有:

命令 说明
show databases; 展示所有库
create database [if not exists] 数据库名 [charset=utf8] 创建库
use 数据库名 使用库
drop database [if exists] 数据库名; 删除库
alter database 数据库名 character set utf8; 设置库编码
select database(); 查看当前库

数据表 DDL

创建数据表模板:

sql 复制代码
-- 创建数据表模板
create table [if not exists] `表名`(
  `字段名1` `类型[(宽度)]` `[约束条件]` [comment `字段说明`],
  `字段名2` `类型[(宽度)]` `[约束条件]` [comment `字段说明`],
  `字段名3` `类型[(宽度)]` `[约束条件]` [comment `字段说明`]
)[表的一些设置];

数据表操作命令:

数据表操作命令 说明
show tables; 查看当前库所有表
show create table 表名 查看指定表的建表SQL
desc 表名 查看表结构
drop table 表名 删除表
alter table 表名 add 列名 类型(长度) [约束]; 添加列
alter table 表名 change 旧列名 新列名 类型(长度) 约束; 修改列名与类型
alter table 表名 drop 列名; 修改表删除列
rename table 表名 to 新表名; 修改表名

表复制操作:

  • insert into select 语句复制表(要求目标表 table2 必须存在):

    sql 复制代码
    insert into table2(field1,field2,...) select value1,value2,... from table1;
    insert into table2 select * from table1;
  • select into from 语句复制表(要求目标表 table2 必须不存在):

    sql 复制代码
    select value1, value2 into table2 from table1;

数据操作语言:DML

DML(Data Manipulation Language)即数据操作语言,用于对数据表中的数据进行增删改。

SQL 说明
insert into 表名 [(列名1,列名2,列名3...)] values (值1,值2,值3...); 向表中某些列插入(不加列名则插入所有列)数据
load data infile "文件路径" into table 表名 fields terminated by '分隔符' 向表中导入文本文档数据
update 表名 set 列名1=值1,列名2=值2... [where 条件]; 向表中更新数据
delete from 表名 [where 条件]; 根据条件删除数据(不加 where 条件则删除整张表)
truncate table 表名 truncate 表名

数据查询语言:DQL

DQL(Data Query Language)即数据查询语言,用于对数据库表中的数据进行查询。DQL 语法格式:

sql 复制代码
select 
  [all|distinct] 
  `<目标列的表达式1>` `[别名]`,`<目标列的表达式2>` `[别名]`,...
from `<表名|视图名>` `[别名]`,`<表名 | 视图名>` `[别名]`,...
[where `<条件表达式>`]
[group by `<列名>`
[having `<条件表达式>`]
[order by `<列名>` [asc|desc]
[limit `<数字或者列表>`];

DQL 的执行顺序与 DQL 的编写顺序并不相同,DQL 的执行顺序为:

html 复制代码
from -> where -> group by -> having -> select -> order by -> limit

条件查询

条件查询通过 WHERE 关键字后加入具体条件来实现。条件查询与运算符密切相关,比较运算符与逻辑运算符是两大常用运算符。

常用的比较运算符:

比较运算符关键字 描述
= 等于
<> 或 != 不等于
< 小于
> 大于
<= 小于等于
>= 大于等于
like 模糊匹配
in(...) 判断某个字符串是否在给定的集合中
is null 判断值是否为空(NULL)
is not null 判断值是否不为空
between ... and ... 判断值是否在指定范围之间
not between ... and ... 判断值是否不在指定范围之间

在通过 LIKE 关键字进行模糊查询时,需要结合模糊匹配规则共同使用,从而达到模糊查询的目的。模糊匹配的规则有:

  1. %:放在具体条件值前后,匹配任意字符序列(包括空字符串)
  2. _:放在具体条件值前后,匹配任意单个字符。

常用的逻辑运算符:

逻辑运算符关键字 描述
and 或 && 与运算,表示所有条件都必须为真
or 或 || 或运算,表示其中至少一个条件为真
not 或 ! 非运算,表示条件为假

排序查询

排序查询语法:

sql 复制代码
select 字段名,... from 表名 order by 字段1 [asc|desc], 字段2 [asc|desc], ...;

ascdesc 分别表示排序规则为升序、降序。如果排序为多字段排序,那么当第一个字段值相同时,才会根据第二个字段进行排序。

聚合查询

聚合查询的本质是通过聚合函数将一列数据作为一个整理,从而进行纵向计算。常用的聚合函数:

聚合函数 说明
COUNT 求列非空值行数
SUM 求列值总和
AVG 求列平均值
MAX 求列最大值
MIN 求列最小值

count(*)count(1)count(column) 的区别:

  • COUNT(*):统计表中所有行的数量,包括 NULL 值与重复值。当使用 count(*) 时,数据库会遍历表中的每一行,对每一行都进行计数,不管该行的值是否为空。这意味着数据库需要考虑表中的所有列,因为 * 代表所有列。因此,这种方式可能会略微慢一些,因为需要考虑所有列的情况。
  • COUNT(1):统计表中所有行的数量,包括 NULL 值与重复值。当使用 count(1) 时,实际上并不会涉及对表中的列进行操作。这是因为 count(1) 会简单地检查每一行是否存在,不关心具体的列值是多少,只要存在就加一。因此,它的计算方式比较简单,性能相对更高一些。
  • COUNT(column_name):会统计指定列中非 NULL 值的数量。

分组查询

WHEREHAVING 的区别主要有两点:

  1. WHERE 在分组之前进行过滤,不满足 WHERE 条件的数据将不参与分组,而 HAVING 是对分组后的结果进行过滤;
  2. WHERE 不能对聚合函数进行判断,而 HAVING 可以。

分组后查询的字段一般为聚合函数与分组字段,查询其他字段无任何意义。

分组查询语法:

sql 复制代码
select 字段名 from 表名 [where 条件] group by 分组字段名 having 分组后过滤条件;

分组查询的使用案例:

sql 复制代码
-- 根据性别分组,统计男性员工与女性员工的数量:
select gender,count(*) from emp group by gender;
-- 根据性别分组,统计男性员工与女性员工的平均年龄:
select gender,avg(age) from emp group by gender;
-- 查询年龄小于45的员工,并根据工作地址分组,获取员工数量大于等于3的工作地址
select workaddress,count(*) address_count from emp where age<45 group by workaddress having address_count >= 3;

分页查询

分页查询语法:

sql 复制代码
select 字段名, ... from 表名 [where 条件] order by 排序字段名 [asc|desc], ... limit 起始索引, 查询记录数;

起始索引从 0 开始,起始索引的计算规则为:

html 复制代码
起始索引=(查询页码-1)*每页记录数

分页查询是数据库方言,不同数据库有不同实现,在 MySQL 中为 Limit。如果分页查询的是第一页数据,起始索引可忽略(简写为 Limit 查询记录数)。

连接查询

表与表之间的关系主要分为一对一、一对多、多对多关系。除了基于上述三种关系下的多表查询,还存在一种交叉连接查询(也被称为笛卡尔积查询)的查询方式。

笛卡尔积(交叉连接)查询的定义与理解

笛卡尔积(交叉连接)查询是将两表间的每一行都进行组合,生成一个新表,新表的行数等于两个表的行数的乘积。但是交叉连接查询在实际应用中使用很少,因为它会生成非常大的结果集,并且没有连接条件,难于筛选出需要的数据。所以通常情况下,会使用内连接、外连接或子查询等方式进行多表间的数据查询。

内连接查询

内连接查询两张表交集部分的数据,分为隐式内连接与显式内连接。

sql 复制代码
select 字段名,... from 表1 [inner] join 表2 on 连接条件...; -- 显式内连接
select 字段名,... from 表1,表2 where 条件...; -- 隐式内连接

外连接查询

外连接查询以一张表所有数据为基础,与另一张交集部分的数据,分为左外连接与右外连接。

  1. 左外连接:查询左表所有数据,包含左表与右表交集部分数据。

    sql 复制代码
    select 字段名,... from 表1 left [outer] join 表2 on 条件...;
  2. 右外连接:查询右表所有数据,包含左表与右表交集部分数据。

    sql 复制代码
    select 字段名,... from 表1 right [outer] join 表2 on 条件...;

自连接查询

自连接查询是指在同一张表中进行连接操作,自连接可以是内连接,也可以是外连接。

比如通过内连接方式的自连接,查询员工及其领导名称:

sql 复制代码
select e.employee_id, e.employee_name, m.employee_name as manager_name
from employees e
join employees m on e.manager_id = m.employee_id;

上例中,对于 manager_idNULL 的数据,并不会查询出来,因为内连接查询的是两表的交集。为解决该问题可以通过外连接方式的自连接。

联合查询

联合查询将多次查询的结果合并起来,形成一个新结果集。联合查询语法:

sql 复制代码
select 字段名,... from 表A ...
union [all]
select 字段名,... from 表B ...

UNIONUNION ALL 的区别在于,UNION 会将结果进行去重后再进行合并,而 UNION ALL 会直接将查询结果合并(不会进行去重)。

对于联合查询的多张表,要求列数与字段类型必须都要一致。

子查询

子查询是指在一个查询语句中嵌套另一个查询语句。子查询语法:

sql 复制代码
select 字段名,... from 表1 where 字段名 in (select 字段名 from 表2 where 条件);

子查询外部的语句可以是 INSERT/UPDATE/DELETE/SELECT 中的任何一个。

根据子查询的结果不同,可以将子查询分为 4 类:

子查询类型 说明 常用操作符
标量子查询 子查询结果为单个值(数字、字符串、日期等) =、<>、>、>=、<、<=
列子查询 子查询结果为一列 IN、NOT IN、ANY、SOME、ALL
行子查询 子查询结果为一行 =、<>、IN、NOT IN
表子查询 子查询结果为多行多列
操作符 说明
IN 在指定集合范围内
NOT IN 不在指定集合范围内
ANY、SOME 满足集合范围内任意一个元素即可
ALL 必须满足集合范围内所有元素

标量子查询案例(查询晚于 "东方白" 入职的员工信息):

sql 复制代码
select * from emp where entrydate > (select entrydate from emp where name = '东方白');

列子查询案例(查询高于 "财务部" 所有人员工资的员工信息):

sql 复制代码
select * from emp where salary > all(select salary from emp where dept_id = (select id from dept where name = '财务部'));

行子查询案例(查询与 "张无忌" 薪资和直属领导相同的员工信息):

sql 复制代码
select * from emp where (salary,manageid) = (select salary,manageid from emp where name = '张无忌');

表子查询案例(查询入职日期是 "2024-03-16" 之后的员工信息与部门信息):

sql 复制代码
select * from (select * from emp where entrydate > '2024-03-16') e left join dept d on e.dept_id = d.id;
相关推荐
番茄去哪了1 小时前
在Java中操作Redis
java·开发语言·数据库·redis
白太岁2 小时前
Redis:(3) Lua 与 Redis、基于连接池的 Facade 模式封装
数据库·c++·redis·lua·外观模式
zlp19922 小时前
Flink DataStream API 消费binlog kafka实践
数据库·flink·kafka
l1t2 小时前
利用DeepSeek和qwen 3.5辅助生成SQL优化方法幻灯片视频
数据库·sql·音视频
_千思_2 小时前
【小白说】数据库系统概念 4
数据库
专注&突破2 小时前
DeepAgents 的 Backend详解
数据库
星火开发设计2 小时前
序列式容器:list 双向链表的特性与用法
开发语言·前端·数据结构·数据库·c++·链表·list
Zzz 小生3 小时前
LangChain Messages:消息使用完全指南
数据库·windows·microsoft
寂寞旅行11 小时前
向量数据库Milvus的使用
数据库·milvus