MySQL数据库语句完全讲解

 更新时间:2026年01月15日 10:10:24   作者:ᶞ_APPROPRIATE"ぁ.  
MySQL作为最流行的开源关系型数据库,其查询语句涵盖了从基础数据检索到复杂多表关联的全场景需求,这篇文章主要介绍了MySQL数据库语句的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

基础知识

  • 数据库(database) 是一个以某种有组织的方式存储的数据集合。理解数据库的一种最简单的办法是将其想象为一个文件柜。此文件柜是一个存放数据的物理位置,不管数据是什么以及如何组织的

  • 表(table) 是一种结构化的文件,可用来存储某种特定类型的数据(数据库中的每个表名都是唯一的)

  • 模式(schema) 是指数据库的结构和组织方式,描述了数据库中对象的布局、特性及它们之间的关系

  • 列(column) 是表中的一个字段。所有表都是由一个或多个列组成的。

  • 行(row) 是表中的一个记录。

  • 主键(primary key) 是一列(或一组列),其值能够唯一区分表中每个行。

    • 一列:主键列不允许NULL值和重复值
    • 一组列:所有列值的组合必须是唯一的(但单个列的值可以不唯一)

打开数据库

打开数据库:

mysql -u 用户名 -p

选择数据库:

USE 数据库名;

必须先使用 USE 打开数据库,才能读取其中的数据。

基础命令

命令输入在 mysql> 之后;

  • 命令用 ;\g 结束,换句话说,仅按Enter不执行命令;

  • 输入 help\h 获得帮助,也可以输入更多的文本获得特定命令的帮助(如,输入 help select; 获得使用SELECT语句的帮助);

  • 输入 quitexit 退出命令行实用程序。

显示信息

显示数据库信息:

SHOW DATABASES;

获得一个数据库内的表的列表:

SHOW TABLES;

显示表列:

SHOW COLUMNS FROM 表名; 
DESCRIBE 表名;  # 另一种快捷方式

显示广泛的服务器状态信息:

SHOW STATUS;

显示创建特定数据库:

SHOW CREATE DATABASE 数据库名;

显示创建特定表:

SHOW CREATE TABLE 表名;

显示表的列结构:

desc 表名;

显示各列数据:

select 列名1, 列名2, ... from 表名;  

select 命令还能用来显示与数据库无关的值;例如:

select '测试123123';  # 输出结果为:`测试123123`
select 2+3*4;  # 输出结果为:`14`

显示表格中全部列的数据:

select * from 表名;

显示授予用户的安全权限:

SHOW GRANTS;

显示服务器错误或者警告信息:

SHOW ERROES;
SHOW WARNINGS;

显示允许的 SHOW 语句:

HELP SHOW;

查看和显示数据库的编码方式:

show create database 数据库名;

显示当前使用的数据库:

select database();

显示索引

show insex from 表名;

增删改

创建数据库:

create database 数据库名;
# 举例:创建并使用数据库
create database phone;  # 创建数据库 phone
show databases;  # 查看是否成功创建 phone
use phone;  # 使用数据库

/* 在使用 use 选择数据库的状态下,也能够操作其他数据库中的表。(将数据库名和表名用 . 连接起来)*/
select * from db2.table1;

创建数据库并设置数据库的字符编码:

create database 数据库名 character set utf8;
# 另一种缩写方式
create database 数据库名 charset utf8;

创建表:

create table 表名(列名1 字段类型, 列名2 字段类型, 列名3 字段类型, …); 

为创建索引

create index 索引名 on 表名 (列名1, 列名2, ...);

复制表的列结构和记录:

create table 新表名 as select * from 旧表名;

仅复制表的列结构:

create table 新表名 like 原表名;

仅复制表的记录:

insert into 新表名 select * from 原表名;

选择某一列进行复制:(复制 列的数据结构必须一致,否则可能会复制失败)

insert into 新表名(新列名) select 原列名 from 原表名;

设置主键:

# 设置单个主键列
create table 表名 (主键列名 数据类型 primary key, 普通列名 数据类型);

# 设置复合主键
CREATE TABLE 表名 (主键列名1 数据类型, 主键列名2 数据类型, 普通列名 数据类型, PRIMARY KEY (主键列名1, 主键列名2));

设置唯一键:

create table 表名 (唯一键列名 数据类型 unique, 普通列名 数据类型);

主键和唯一键区别

特性主键约束 (PRIMARY KEY)唯一约束 (UNIQUE)
列的唯一性确保列值唯一,且不能为 NULL确保列值唯一,但可以包含 NULL(根据数据库的具体实现)。
NULL 值不允许有 NULL 值。可以有 NULL 值,但通常每个 NULL 只能出现一次(具体依赖数据库实现)。
索引自动创建唯一索引,且该索引被视为主索引。自动创建唯一索引,但它不是主索引。
表中的数量每个表只能有一个主键。一个表可以有多个唯一约束。
用途用于标识每行唯一数据。用于确保某列的值是唯一的,适用于不需要作为行标识符的列。

添加能自动连续编号的列,列要求:

  1. 数据类型为 int 等整数类型
  2. 加上关键字 auto_increment (每个表中只能有一个 AUTO_INCREMENT 列)
  3. 必须是 主键唯一键
create table 表名 (能自动编号的列名 整数数据类型 auto_increment primary key, 其他列名 数据类型);
create table 表名 (能自动编号的列名 整数数据类型 auto_increment unique, 其他列名 数据类型);

插入数据验证是否连续编号:

insert into 表名 (其他列名) values(插入的值);
# 举例
insert into phone_test (name) values('mike');

设置连续编号的初始值:

insert into 表名  values(连续编号值, 其他列值);
# 举例
insert into phone_test values(100, 'mike');

如果把表中数据都删除,然后重新输入,编号不会从头开始,而是从 最大值+1 开始分配

create table test1 (id1 int auto_increment primary key, name char(10));
insert into test1 (name) values('mmike');  # 1 mmike
insert into test1 values(100, 'mike');  # 1 mmike  和 100 mike
delete from test1;  # 删除上面两条数据
insert into test1 (name) values('moke');  # 101 moke

初始化 auto_increment 的值 (如果初始化的值小于现有表格中最大值,那么初始化会不起作用;如果想要重新从 1 开始,必须清空表中的数据。)

alter table 表名 auto_increment=200;

设置列的默认值

create table 表名 (列名 数据类型 default 默认值 ...);
# 修改已有列并为其添加默认值
alter table 表名 modify column 列名 数据类型 default 默认值;
# 添加默认值到新列
alter table 表名 add column 列名 数据类型 default 默认值;
# 添加默认值,不更改数据类型
alter table 表名 alter column 列名 set default 默认值;

更新数据:

UPDATE customers   # 更新 customers 表
SET Cust_name = 'The Fudds', cust_email='elmer@fudd.com'  # 将 Cust_name 列的值更新为 The Fudds,cust_email 列的值更新为 elmer@fudd.com
WHERE cust_id = 10005;  # 仅更新 Cust_id 等于 '10005' 的行

UPDATE IGNORE 表名
SET 列1 = 值1, 列2 = 值2, ...
WHERE 条件;  # 在执行 UPDATE 操作时,如果出现某些错误(如重复键错误),则忽略这些错误并继续更新其余记录

重命名表:

RENAME TABLE 旧表名1 TO 新表名1,旧表名2 TO 新表名2... ;

删除数据库:

drop database 数据库名;

删除表:

drop table 表名;
# 如果目标表不存在的情况下执行drop命令会报错,可以加个 if exists
drop table if exists 表名;

删除列:

alter table 表名 drop 列名; 

删除表中所有记录:

delete from 表名;
# 删除符合条件的那一行数据
delete from 表名 where 列名=1006;

# turncate table(速度比delect快)
# 如果表被其他表通过外键约束引用,通常无法执行 TRUNCATE 操作。你需要先删除外键约束,或使用 DELETE 操作。
# 通常,TRUNCATE 不会触发与表相关的触发器(Triggers),而 DELETE 可能会触发 BEFORE DELETE 或 AFTER DELETE 触发器。
# TRUNCATE 不支持条件WHERE,它会删除表中所有的记录,没有条件限制。
TRUNCATE TABLE 表名;  # 删除整个表的数据,表结构不变

修改数据库编码:

alter database 数据库名 character set utf8;

修改字段数据类型:

alter table 表名 modify 列名 数据类型;

修改字段的数据类型并且改名:

alter table 表名 change 原列名 新列名 数据类型;

修改列的顺序:

# 把某一列放在最前面
alter table 表名 modify 列名 数据类型 first;

向表中插入一列数据:

alter table 表名 add 列名 数据类型;
# 把列添加到最前面
alter table 表名 add 列名 数据类型 first;
# 把列插到某一列后面
alter table 表名 add 列名 数据类型 after 某一列列名;

删除默认值

alter table 表名 modify column 列名 数据类型 default null;

删除索引

drop index 索引名 on 表名;
create index my_ind on test1 (name);  # 在 表test1 的 列name 上创建名为 my_ind 的索引
show index from test1;  # 显示创建的索引
show index from test1 \G  # 纵向显示列值方便查看
drop index my_ind on test1;  # 删除索引

定义外键

ALTER TABLE 表名  # 指定要修改的表
ADD CONSTRAINT 外键名称  # 定义外键名称
FOREIGN KEY (外键列名)  # 当前表中哪个列将作为外键
REFERENCES 参照表名(主键列名);  # 引用目标表及其主键

# 假设我们有两个表:orders 和 customers。我们想要在 orders 表中添加一个外键,以引用 customers 表中的 customer_id 列。
CREATE TABLE customers (customer_id INT PRIMARY KEY, name VARCHAR(100));
CREATE TABLE orders (order_id INT PRIMARY KEY, order_date DATE, customer_id INT);
ALTER TABLE orders ADD CONSTRAINT fk_customer FOREIGN KEY (customer_id) REFERENCES customers(customer_id);

复杂的表结构更改一般需要手动删除过程,:

  1. 用新的列布局创建一个新表;
  2. 使用INSERT SELECT语句从旧表复制数据到新表。如果有必要,可使用转换函数和计算字段;
  3. 检验包含所需数据的新表;
  4. 重命名旧表或者删除旧表;
  5. 用旧表原来的名字重命名新表;
  6. 根据需要,重新创建触发器、存储过程、索引和外键。

向表中插入一行数据:

insert into 表名 values(数据1, 数据2, ...);  # 句高度依赖于表中列的定义次序

指定列名插入数据:

insert into 表名 (列名1, 列名2, ...) values(数据1, 数据2, ...);  
# 也可以一次性插入多条数据: 
insert into 表名 (列名1, 列名2, ...) values (数据1, 数据2, ...),(数据1, 数据2, ...),(数据1, 数据2, ...)...;

# 举例
insert into Phone (pid, name, color) values(456, 'marry', 'blue');
insert into Phone (pid, name, color) values(456, 'aaa', 'rrrr'),(789, 'bbb', 'ooo'),(012, 'ccc', 'yyy');

插入列往往比较耗时,可以使用LOW_PRIORITY降低insert语句的优先级(尤其是在数据库有大量的并发写操作时)

INSERT LOW_PRIORITY INTO 表名 (列名1, 列名2, ...) VALUES (值1, 值2, ...);

插入检索出的数据

INSERT INTO 新表名(列1, 列2, ...) SELECT 列1, 列2, ... FROM 原表名 WHERE 条件;

检索

检索不同的列:

# 从表中检索一列
select 列名 from 表名;
# 从表中检索多列
select 列名, 列名, 列名 from 表名;
# 检索所有列
select * from 表名;

检索不同的行:

# 返回每列的唯一值 (DISTINCT 会作用于查询中的所有列的组合,而不是单独某一列。)
select distinct 列名, 列名 from 表名;
# 如果只去除某一列的重复,应该只选择该列,而不是整个组合。
select distinct 列名 from 表名;

限制结果:

# 显示前m行
select * from 表名 limit m;
# 如果要得出m行后的n行,可指定要检索的开始行和行数
select * from 表名 limit m,n;  # m:跳过前m行,即从第m+1行开始;  n:从第m+1行开始,返回后n行数据

使用完全限定的表名:

select 表名.列名 from 数据库名.表名;

按顺序检索:

# 按顺序检索某一列
select 列名1 from 表名 order by 列名2;  # 按列名2的顺序给列名1排序(order by后面的排序列和select的选择列可以不一样)
# 按多个列排序
select 列名1, 列名2, 列名3...  from 表名 order by 列名1, 列名2...;  # 先按 order by 中列1的顺序排序,如果列1有相同值,相同部分按列2排序
# 降序排序
select 列名1, 列名2, 列名3... from 表名 order by 列名1 desc; 
# 也可以指定某一列为降序
select 列名1, 列名2, 列名3... from 表名 order by 列名1 desc, 列名2... ;  # 列1降序,列2升序,如果每列都想降序;必须对每列都指定desc关键字

找到一列中最高或最低值:

# 结合order by + limit
select 列名 from 表名 order by 列名 desc limit 1;  # 找到最高值

按指定搜索条件过滤检索:

select 列名1, 列名2 from 表名 where 列名1 = 'a';  # 找到列名1中值等于a的 列1列2数据
select 列名1, 列名2 from 表名 where 列名1 between A and B;  # 找到列名1中值在`A<=值<=B`范围内的 列1列2数据
# where 子句可以组合使用
select 列名1, 列名2, 列名3 from 表名 where 列名1=100 and 列名2 <=10;  # 找到 列名1中值=100 并且 列2数据<=10 的 列1列2列3数据
select 列名1, 列名2, 列名3 from 表名 where 列名1=100 or 列名2 =200;  # 找到 列名1中值=100 或者 列2数据=200 的 列1列2列3数据
# where子句的计算次序(默认 AND 的优先级高于 OR)
select 列名1, 列名2, 列名3 from 表名 where 列名1=100 or 列名2 =200 and 列名3>=10;  # 等价于WHERE (列名1 = 100) OR (列名2 = 200 AND 列名3 >= 10);找到 列名1中值=100 或者 (列2数据=200并且列名3>=10) 的 列1列2列3数据
select 列名1, 列名2, 列名3 from 表名 where (列名1=100 or 列名2 =200) and 列名3>=10;  # 找到 (列名1中值=100或者列2数据=200)并且 列名3>=10 的 列1列2列3数据
# where 子句的 in 操作符:in 操作符等价于多个 or 条件组合。它的作用是检查 列名1 的值是否匹配括号中的任意一个值
select 列名1, 列名2, 列名3 from 表名 where 列名1 in (值1, 值2, 值3) order by 列名2;
# where 子句的 not 操作符:not 操作符否定它之后所跟的任何条件
select 列名1, 列名2, 列名3 from 表名 where 列名1 not in (值1, 值2, 值3) order by 列名2;

在同时使用order bywhere子句时,应该让order by位于where之后,否则将会产生错误

where 子句操作符

操作符说明
=等于
<>不等于
!=不等于
<小于
<=小于等于
>大于
>=大于等于
between在指定的两个值之间
(包括边界值)

空值检索:

select 列名 from 表名 where 列名 is null;

用通配符过滤检索:

# %通配符:%表示任何字符出现任意次数。(%会区分大小写;%可以匹配0个字符)
select 列名 from 表名 where 列名 like 'aaa' order by 列名;  # 检索字符串 完全等于 'aaa' 的字符串
select 列名1 from 表名 where 列名1 like 'aaa%';  # 检索任意以aaa开头的字符串(字符串:aaa也会被检索)
select 列名1 from 表名 where 列名1 like '%aaa%';  # 检索任何包含aaa的字符串
select 列名1 from 表名 where 列名1 like 'a%b';  # 检索任何以a开头b结尾的字符串

# %通配符不能匹配null
select 列名1 from 表名 where 列名1 like '%';  # 这样也检索不到 null 值
# _通配符:和%通配符用途一样,但只匹配单个字符
select 列名1 from 表名 where 列名1 like 'aaa_';  # 检索任意以aaa开头且后面只跟一个字符的字符串 (字符串:aaa不会被检索;aaall也不会被检索,只能检索到aaal)

用正则表达式进行搜索

# 基本字符匹配(正则表达式不会区分大小写,区分大小写的话需要在 regexp 后面添加 binary 关键字,)
select 列名 from 表名 where 列名 regexp 'aaa' order by 列名;  # 检索字符串所有包含aaa的字符串
select 列名 from 表名 where 列名 regexp '.aaa' order by 列名;  # 检索字符串所有包含aaa结且前面跟有一个字符 的 字符串(.表示匹配任意一个字符,例如:22aaa,2aaa,2aaab)

# or 匹配 (|)
select 列名 from 表名 where 列名 regexp 'aaa|bbb|ccc' order by 列名;  # 匹配包含 aaa、bbb 或 ccc 任意一个的字符串

# 匹配几个字符之一 ([])
select 列名 from 表名 where 列名 regexp '[123]aaa' order by 列名;  # 它要求该字符串必须以 1、2 或 3 之一开始,并紧接着是 aaa。换句话说,它会匹配 1aaa、2aaa 或 3aaa 开头的任何字符串。

# 匹配范围
select 列名 from 表名 where 列名 regexp '[1-5]aaa' order by 列名;  # 匹配 列名 中以数字 1 到 5 之间的任何一个数字开头,并紧接着是 aaa 的字符串

# 匹配特殊字符(例如:.[]|_等):用\\为前导
select 列名 from 表名 where 列名 regexp '\\.' order by 列名;  # 匹配包含 .(点号)的字符串

空白元字符

元 字 符说 明
\\f换页
\\n换行
\\r回车
\\t制表
\\v纵向制表

字符类:放在 方括号内部 ,例如 [[:alnim:]]

说 明
[:alnum:]任意字母和数字(同[a-z A-Z 0-9])
[:alpha:]任意字符(同[a-z A-Z])
[:blank:]空格和制表(同[\\t])
[:cntrl:]ASCII控制字符(ASCII 0到31和127)
[:digit:]任意数字(同[0-9])
[:graph:]与[:print:]相同,但不包括空格
[:lower:]任意小写字母(同[a-z])
[:print:]任意可打印字符
[:punct:]既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:]包括空格在内的任意空白字符(同[\\f \\n \\r \\t \\v])
[:upper:]任意大写字母(同[A-Z])
[:xdigit:]任意十六进制数字(同[a-fA-F0-9])

重复元字符

元 字 符说明
*0个或多个匹配
+1个或多个匹配(等于{1,})
?0个或1个匹配(等于{0,1})
{n}指定数目的匹配
{n,}不少于指定数目的匹配
{n,m}匹配数目的范围(m不超过255)
# 举例
select 列名 from 表名 where 列名 regexp '[[:digit:]]{4}'  # 匹配任何包含 4个连续数字 的字符串
select 列名 from 表名 where 列名 regexp '[0-9][0-9][0-9][0-9]'  # 和上面一致:匹配任何包含 4个连续数字 的字符串
select 列名 from 表名 where 列名 regexp '\\([0-9]aas?\\)'  # 匹配任何包含 以(开头,后跟一个数字,后跟aas或者aa(aaa? 只匹配 aas 或 aa) 最后跟一个) 的字符串

定位元字符

元 字 符说明
^文本的开始
$文本的结尾
[[:<:]]词的开始
[[:>:]]词的结尾
# 举例
select 列名 from 表名 where 列名 regexp '^[0-9\\.]'  # 匹配任何 以一个数字(0-9)或一个点(.)开始 的字符串
select 列名 from 表名 where 列名 regexp '[0-9\\.]'  # 匹配任何 包含至少一个数字(0-9)或一个点号(.)的字符串。

创建计算字段

拼接字段:Concat()需要一个或多个指定的串,各个串之间用逗号分隔。

select concat(列名1, '(', 列名2, ')') from 表名 order by 列名1;  # 返回结果:列名1(列名2)

删除数据右侧多余的空格:RTrim()

select concat(rtrim(列名1), '(', 列名2, ')') from 表名 order by 列名1;  # rtrim():去掉右边所有空格;  ltrim():去掉左边所有空格;  trim():去掉两边所有空格

使用别名:as

select concat(rtrim(列名1), '(', 列名2, ')') as 新列名 from 表名 order by 列名1;

执行算数计算:

select 列名3+列名4 as 新列名 from 表名;

算术操作符

操作符说明
+
-
*
/

使用数据处理函数

文本处理函数

函数说明
upper(string)将文本转换为大写
trim(string)去掉两边所有空格
left(string, length)返回串左边的字符
length(string)返回串的长度
locate(substring, string, [start_position])返回一个子字符串在另一个字符串中首次出现的位置
lower(string)将串转换为小写
right(string, length)返回串右边的字符
soundex(string)将字符串转换为一个表示其发音的编码值(用于模糊匹配和声音相似度比较)
subString(string, start, length)从一个字符串中提取指定位置开始的子字符串
select left(列名1, 3) as 新列名 from 表名;  # 返回列名1的前3个字符
select locate('Pro', product_name, 3) from 表名;  # 从 列product_name 第3个字符开始 找到 Pro 首次出现的位置(找不到返回 0 )
select right(列名1, 3) as 新列名 from 表名;  # 返回列名1的后3个字符
select soundex(列名) from 表名;  # 返回每个数据发音的编码值
select 列名 from 表名 where soundex(列名) = soundex('Smith');  # 想找出所有发音与 "Smith" 相似的数据
select subString(列名, 1, 3) FROM 表名;  # 提取前 3 个字符
select subString(列名, 4) FROM 表名;  # 从第 4 个字符开始提取,提取到字符串的末尾

日期和时间处理函数

函数说明
AddDate()增加一个日期(天、周等)
AddTime()增加一个时间(时、分等)
CurDate()返回当前日期
CurTime()返回当前时间
Date()返回日期时间的日期部分
DateDiff()计算两个日期之差
Date_Add()高度灵活的日期运算函数
Date_Format()返回一个格式化的日期或时间串
Day()返回一个日期的天数部分
DayOfWeek()对于一个日期,返回对应的星期几
Hour()返回一个时间的小时部分
Minute()返回一个时间的分钟部分
Month()返回一个日期的月份部分
Now()返回当前日期和时间
Second()返回一个时间的秒部分
Time()返回一个日期时间的时间部分
Year()返回一个日期的年份部分

数值处理函数

函数说明
Abs()返回一个数的绝对值
Cos()返回一个角度的余弦
Exp ()返回一个数的指数值
Mod()返回除操作的余数
Pi()返回圆周率
Rand()返回一个随机数
Sin()返回一个角度的正弦
Sqrt()返回一个数的平方根
Tan()返回一个角度的正切
select abs(列名) from 表名;  # 返回绝对值

汇总数据

聚合函数 (MySQL返回结果一般比你在自己的客户机应用程序中计算要快得多。)

函数说 明
AVG()返回某列的平均值, 忽略列值为NUL的行。
COUNT()返回某列的行数() COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值;COUNT(column) 对特定列中具有值的行进行计数,忽略NULL
MAX()返回某列的最大值
MIN()返回某列的最小值
SUM()返回某列值之和

以上5个聚集函数都可以如下使用:

  • 对所有的行执行计算,指定ALL参数或不给参数(因为ALL是默认行为);
  • 只包含不同的值,指定DISTINCT参数。(如果指定列名,则DISTINCT只能用于COUNT()DISTINCT不能用于COUNT(*),因此不允许使用COUNT(DISTINCT))
select avg(数值列名) from 表名;
select count(*) from 表名;
select avg(distinct prod_price) as acg_price from prducts where vend_id = 1003;
select count(*) as num_items, min(prod_price) as price_min, max(prod_price) as price_max, avg(prod_price) as price_avg from products; 

数据分组

GROUP BY子句

  • 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。
  • GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。
  • 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
  • GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
  • 使用WITH ROLLUP关键字,可以得到每个分组以及每个分组汇总级别(针对每个分组)的值
select vend_id, count(*) as num_prods from products group by vend_id;  # 对每个vend_id而不是整个表计算num_prods

SELECT vend_id, COUNT(*) AS num_prods FROM products GROUP BY vend_id WITH ROLLUP;  # WITH ROLLUP 是一个用于生成汇总数据的特殊选项。它在原本分组的基础上,额外生成一个“总计”行,该行显示所有vend_id的总产品数量。

HAVING子句

  • WHERE过滤行,HAVING过滤分组。
SELECT cust_id,COUNT(*) AS orders FROM orders GROUP BY cust_id HAVING COUNT(*) >= 2;  # 过滤掉 聚合后cust_id数量 小于2 的 cust_id

SELECT vend_id,COUNT(*) AS num_prods FROM products WHERE prod_price >=10 GROUP BY vend_id HAVING COUNT(*) >= 2;  # 过滤掉 聚合后vend_id数量小于2 且 prod_price大于或等于10的 vend_id

ORDER BY 子句

  • 一般在使用GROUP BY子句时,应该也给出ORDER BY子句
SELECT order_num, SUM(quantity*item_price) AS ordertotal FROM orderitems GROUP BY order_num HAVING SUM(quantity*item_price) >= 50 ORDER BY ordertotal;  # 查询返回了所有ordertotal大于或等于 50 的order_num,并且按照ordertotal从小到大排序。

select 子句顺序

子句说明是否必须使用
select要返回的列或表达式
from从中检索数据的表仅在从表选择数据时使用
where行级过滤
group by分组说明仅在按组计算聚集时使用
having组级过滤
order by输出排序顺序
limit要检索的行数

使用子查询

  • 子查询:嵌套在其他查询中的查询
  • 子查询从内向外处理
  • WHERE子句中使用子查询,应该保证SELECT语句具有与WHERE子句中相同数目的列。
select cust_nume,cust_contact from customers where cust_id in (select cust_id from orders where order_num in (select order_num from orderitems where prod_id = 'tnt2'));  # 先在表orderitems中查询prod_id='tnt2'的order_num,再在orders表中找 order_num=子句中查询结果 的cust_id,最后在表customers中找到 cust_id=子句中查询结果 的cust_nume和cust_contact

# 修改格式
select cust_nume,cust_contact 
from customers 
where cust_id in (select cust_id 
                  from orders 
                  where order_num in (select order_num 
                                      from orderitems 
                                      where prod_id = 'tnt2'));
                                      
# 等同于
SELECT cust_name,cust_contact
FROM customers,orders,orderitems
wHERE customers.cust_id = orders.cust_id
AND orderitems.order_num = orders.order_num
AND prod_id = 'TNT2';

相关子查询:涉及外部查询的子查询

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM orders
       	WHERE orders.cust_id = customers.cust_id) AS orders
FROM customers
ORDER BY cust_name;

联结表

使用表别名

  • 例如:customers AS c
  • 表别名只在查询执行中使用
SELECT Concat(RTrim(vend_name),'(',RTrim(vend_country),')') AS vend_title
FROM vendors
ORDER BY vend_name;

SELECT cust_name,cust_contact
FROM customers AS c,orders AS o,orderitems AS oi
WHERE c.Cust_id = o.Cust_id
AND oi.order_num = o.order_num
AND prod_id = 'TNT2';
  • 等值联结(内部联结)
    • 例如:vendors.vend_id = products.vend_id

    • 外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。

    • 联结是一种机制,用来在一条SELECT语句中关联表,因此称之为联结。

    • 完全限定列名:在引用的列可能出现二义性时,必须使用完全限定列名(用一个点分隔的表名和列名)。

    • 笛卡儿积:由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数

# 联结(很少用,基本都用下面的内联结方式)
SELECT vend_name,prod_name,prod_price
FROM vendors,products
WHERE vendors.vend_id = products.vend_id
ORDER BY vend_name, prod_name;

# 笛卡尔积
SELECT vend_name,prod_name,prod_price
FROM vendorS,products
ORDER BY vend_name,prod_name;
  • 联结多个表
SELECT prod_name, vend_name, prod_price, quantity
FROM orderitems,products,vendors
WHERE products.vend_id = vendors.vend_id
AND orderitems.prod_id = products.prod_id
AND order_num = 20005;
  • 内联结
    • 例如:vendors INNER JOIN products ON vendors.vend_id = products.vend_id
# 用内联结实现上面等值联结的查询
SELECT vend_name, prod_name, prod_price
FROM vendors INNER JOIN products
ON vendors.vend_id = products.vend_id;  # INNER JOIN 表示将 vendors 表与 products 表按照 vend_id 进行连接,连接条件是 vendors.vend_id 与 products.vend_id 相等。这样能获取所有与供应商相关的产品信息。
  • 自联结
    • 例如: pl.vend_id = p2.vend_id
    • p1和p2是同一个表
SELECT prod_id, prod_name
FROM products
WHERE vend_id = (SELECT vend_id
                 FROM products
                 WHERE prod_id = 'DTNTR');
                 
# 自联结实现上述查询
SELECT pl.prod_id, pl.prod_name
FROM products AS pl, products AS p2
WHERE pl.vend_id = p2.vend_id
  AND p2.prod_id = 'DTNTR';

  • 自然联结

    • 无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。标准的联结返回所有数据,甚至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次。

    • 自然联结是这样一种联结,其中你只能选择那些唯一的列。这一般是通过对表使用通配符(SELECT *),对所有其他表的列使用明确的子集来完成的

SELECT c.*, o.order_num, o.order_date,
oi.prod_id, oi.quantity, oi.item_price
FROM customers AS c, orders AS o, orderitems AS oi
WHERE c.cust_id = o.cust_id
AND oi.order_num = o.order_num
AND oi.prod_id = 'FB';
  • 外部联结
    • 联结包含了那些在相关表中没有关联行的行。这种类型的联结称为外部联结
      • 在使用OUTER JOIN语法时,必须使用RIGHTLEFT关键字指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表)。上面的例子使用LEFT OUTER JOINFROM子句的左边表(customers表)中选择所有行。
SELECT customers.cust_id, orders.order_num
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id = orders.cust_id;  # 返回 左表(第一个表) 中的所有记录,对于没有匹配的右表记录,查询结果中的相关列会显示为 NULL

  • 使用带聚集函数的联结
SELECT customers.cust_name, customers.cust_id,
	   COUNT(orders.order_num) AS num_ord
FROM customers INNER JOIN orders
ON customers.cust_id = orders.cust_id
GROUP BY customers.cust_id;

SELECT customers.cust_name,
customers.cust_id,
COUNT(orders.order_num) AS num_ord
FROM customers LEFT OUTER JOIN orders
ON customers.cust_id= orders.cust_id
GROUP BY customers.cust_id;

组合查询

有两种基本情况,其中需要使用组合查询:

  • 在单个查询中从不同的表返回类似结构的数据;

  • 对单个表执行多个查询,按单个查询返回数据。

UNION规则:

  • UNION必须由两条或两条以上的SELECT语句组成,语句之间用关键字UNION分隔。
  • UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。
  • 列数据类型必须兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型(例如,不同的数值类型或不同的日期类型)。
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5;

SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id in (1001,1002);

# 组合上面两条语句
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id in (1001,1002);  # 会自动去除重复的行

# 等同于
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
OR vend_id IN (1001,1002);

# 包含重复的行
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION ALL
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id in (1001,1002);  

# 对组合查询结果排序
SELECT vend_id, prod_id, prod_price
FROM products
WHERE prod_price <= 5
UNION
SELECT vend_id, prod_id, prod_price
FROM products
WHERE vend_id in (1001,1002)
ORDER BY vend_id, prod_price;   # 对返回最终结果进行排序,不是只对第二条select语句进行排序 

全文本搜索

  • 全文索引的默认行为是忽略长度小于一定字符数的词。这个长度阈值可以通过系统变量 ft_min_word_len 来配置,默认值是 4 字符
  • MySQL规定了一条50%规则,如果一个词出现在50%以上的行中,则将它作为一个非用词忽略。50%规则不用于IN BOOLEAN MODE
  • 如果表中的行数少于3行,则全文本搜索不返回结果
  • 忽略词中的单引号。例如,don’t索引为dont
  • 不具有词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果。
CREATE TABLE productnotes
(
note_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)  # 为 note_text 字段创建全文索引
)ENGINE=MyISAM;
  • 如果正在导入数据到一个新表,应该首先导入所有数据,然后再修改表,定义FULLTEXT
  • 必须先创建了FULLTEXT索引,才能使用match()against()进行全文检索查询
  • Match()指定被搜索的列,Against()指定要使用的搜索表达式
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit');

SELECT note_text,
	Match(note_text) Against('rabbit') AS rank  # 计算每条记录与搜索词的相关性
FROM productnotes;  # 查询结果返回note_text,rank两列

查询扩展

  1. 进行一个基本的全文本搜索,找出与搜索条件匹配的所有行
  2. MySQL检查这些匹配行并选择所有有用的词
  3. MySQL再次进行全文本搜索,这次不仅使用原来的条件,而且还使用所有有用的词。
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('anvils' WITH QUERY EXPANSION);  # 在原始查询基础上,自动找到与 'anvils' 相关的其他词汇(这些词是基于 FULLTEXT 索引的相关文档生成的)。

布尔文本搜索

  • 即使没有FULLTEXT索引也可以使用
  • 在布尔方式中,不按等级值降序排序返回的行
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('heavy -rope*'IN BOOLEAN MODE);  # 匹配包含heavy但不包含任意以rope开始的词的行

全文本布尔操作符

布尔操作符说明
+包含,词必须存在
-排除,词必须不出现
>包含,而且增加等级值
<包含,且减少等级值
()把词组成子表达式(允许这些子表达式作为一个组被包含、排除、排列等)
~取消一个词的排序值
*词尾的通配符
“”定义一个短语(与单个词的列表不一样,它匹配整个短语以便包含或排除这个短语)
SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+rabbit +bait' IN BOOLEAN MODE);  # 匹配包含词rabbit和bait的行

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('rabbit bait' IN BOOLEAN MODE);  # 匹配包含rabbit和bait中的至少一个词的行

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('"rabbit bait"' IN BOOLEAN MODE);  # 匹配短语rabbit bait而不是匹配两个词rabbit和 bait

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('>rabbit <carrot' IN BOOLEAN MODE);  # 匹配rabbit和carrot,增加前者的等级,降低后者的等级

SELECT note_text
FROM productnotes
WHERE Match(note_text) Against('+safe +(<combination)' IN BOOLEAN MODE);  # 匹配词safe和combination,降低后者的等级。

总结 

到此这篇关于MySQL数据库语句的文章就介绍到这了,更多相关MySQL语句详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Ubuntu移除mysql后重新安装的方法

    Ubuntu移除mysql后重新安装的方法

    这篇文章主要介绍了Ubuntu移除mysql后重新安装的方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • Mysql命令大全(完整版)

    Mysql命令大全(完整版)

    这篇文章主要介绍了Mysql命令大全,分享的命令都是最基本的,推荐给大家,感兴趣的小伙伴们可以参考一下
    2015-11-11
  • MySQL互为主从(双向同步)部署超详细教程

    MySQL互为主从(双向同步)部署超详细教程

    MySQL互为主从是一种特殊的复制架构,其中两个MySQL服务器互为主从,彼此之间互相同步数据,这篇文章主要介绍了MySQL互为主从(双向同步)部署的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-11-11
  • MYSQL数据库导入数据时出现乱码的解决办法

    MYSQL数据库导入数据时出现乱码的解决办法

    我是用的最后一种方法,前面三种解决MYSQL导入数据乱码的方法没试过,东莞SEO推荐大家直接使用第四种方法处理MYSQL导入中文数据时的乱码问题。
    2011-01-01
  • window下mysql 8.0.15 winx64安装配置方法图文教程

    window下mysql 8.0.15 winx64安装配置方法图文教程

    这篇文章主要为大家详细介绍了window下mysql 8.0.15 winx64安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-03-03
  • MySQL的order by如何避免"未命中索引"(推荐)

    MySQL的order by如何避免"未命中索引"(推荐)

    本文详细解析了在使用MySQL的OrderBy语句时,如何通过Explain查看执行计划以及如何有效利用索引,介绍了常见的索引未命中情况,提供了多个示例来解释如何根据索引的不同使用情况调整SQL语句,以确保最优的查询性能
    2024-11-11
  • MySQL中的LOCATE和POSITION函数使用方法

    MySQL中的LOCATE和POSITION函数使用方法

    不常用:MySQL中的LOCATE和POSITION函数
    2010-02-02
  • MySQL忘记密码恢复密码的实现方法

    MySQL忘记密码恢复密码的实现方法

    流传较广的方法,mysql中文参考手册上的,各位vps主机租用客户和服务器托管用户忘记mysql5.1管理员密码时,可以使用这种方法破解下
    2008-07-07
  • mysql如何定时自动新增分区

    mysql如何定时自动新增分区

    这篇文章主要介绍了mysql如何定时自动新增分区问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-09-09
  • CentOS7.4手动安装MySQL5.7的方法

    CentOS7.4手动安装MySQL5.7的方法

    这篇文章主要介绍了CentOS7.4手动安装MySQL5.7的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09

最新评论