这是个人学习时整理记录的关于mysql的学习笔记
作为速查手册使用。
0.SQL基本概念
0.1关于sql语言的分类
DDL:数据定义语句,用来维护存储数据的结构,如create,drop,alter
DML:数据操纵语句,用来对数据进行操作,如:insert,delete,update;
DML中又单独分了一个DQL,数据查询语言,代表指令:delect。
DCL:数据控制语句,主要负责权限管理和事务,如:grant,revoke,commit
0.2数据类型
数值类型
-
整数:有1、2、3、4、8字节的多个类型
-
浮点数:有4、8两个类型
字符串类型
- 字符串:
- char:定长类型
- varchar:变长类型
- 文本
- text:长文本
- tinytext:短文本
- mediumtext:中等文本
- longtext:极大文本
- 二进制文本:
- blob:二进制字符串
- tinyblob:短
- mediumblob:中等
- longblob:极大
- 二进制文本与一般文本 的区别:
时间日期类型
- timestamp:时间戳
- datetime:YYYY-MM-DD hh:mm:ss,包括年月日时分秒
- year:年
- date:日期,包括年月日
- time:hh:mm:ss,时间,到秒
枚举集合类型
- enum:枚举
- set:集合
1操作命令:
首先,需要注意,mysql中,语句用 ; 作为结尾。
- 如果没有输入;,即使换行,也不会执行
1.1数据库操作
-
查看当中服务端管理多少个数据库:
show databases;
-
修改数据库属性:
alter database [数据库名称] [属性] = [新属性];
创建-cteate
创建数据库(相当于创建文件夹):
create database [数据库名称]
CREATE DATABASE [IF NOT EXISTS] database_name
[CHARACTER SET charset_name]
[COLLATE collation_name];
- IF NOT EXISTS:如果数据库不存在,才会创建。
- 如果创建一个存在的数据库将会导致错误
- CHARACTER SET:指定字符集
- COLLATE:可以用于指定排序规则
删除-drop
DROP DATABASE [IF EXISTS] <database_name>;
选中-use
USE database_name
导出数据
导出数据 - select into outfile
使用方法和一般的select语句一样,只是把结果输出到外部文件
- 必须拥有FILE权限,才能使用此语法。
- 输出不能是一个已存在的文件。防止文件数据被篡改。
- 你需要有一个登陆服务器的账号来检索文件。否则 SELECT … INTO OUTFILE 不会起任何作用。
SELECT column1, column2, ... INTO OUTFILE 'file_path' FROM your_table WHERE your_conditions;
'file_path'
: 指定输出文件的路径和名称。
导出数据 - mysqldump
mysqldump 是 MySQL 提供的用于备份和导出数据库的命令行工具。
实例:
# 导出整个数据库
mysqldump -u root -p mydatabase > mydatabase_backup.sql
# 导出指定表
mysqldump -u username -p password -h hostname database_name table_name > output_file.sql
或
mysqldump -u root -p mydatabase mytable > mytable_backup.sql
# 导出数据库结构
mysqldump -u username -p password -h hostname --no-data database_name > output_file.sql
# 导出数据库数据
$ mysqldump -u root -p RUNOOB > database_dump.txt
password ******
# 导出所有数据库
$ mysqldump -u root -p --all-databases > database_dump.txt
password ******
# 导出为压缩文件
mysqldump -u username -p password -h hostname database_name | gzip > output_file.sql.gz
# 导出为sql格式???
$ mysqldump -u root -p RUNOOB runoob_tbl > dump.txt
password ******
-
password可以再 -p 后面直接给出,也可以等待命令行提示之后再输入。
-
导入数据
导入数据 - load data in file
可以将sql数据库中导出的数据导入回去。
格式:
mysqldump -u username -p password -h hostname database_name > output_file.sql
-u
: 指定 MySQL 用户名。-p
: 提示输入密码。-h
: 指定 MySQL 主机名。database_name
: 要导出的数据库名称。output_file.sql
: 导出数据保存到的文件。
导入数据 - sourse
可以再mysql终端中执行
mysql> create database abc; # 创建数据库
mysql> use abc; # 使用已创建的数据库
mysql> set names utf8; # 设置编码
mysql> source /home/abc/abc.sql # 导入备份数据库
导入数据 - 命令行
mysql -u your_username -p -h your_host -P your_port -D your_database < 'file.sql'
- your_username、your_host、your_port、your_database 分别为你的 MySQL 用户名、主机、端口和数据库。
- MySQL 将执行 SQL 文件中的语句,将数据导入到指定的数据库中。
- 请注意,如果 SQL 文件包含创建数据库的语句,确保在执行导入之前数据库已经存在。
- 如果文件包含创建表的语句,确保表不存在或者是空的,以免导入数据时发生冲突。
导入数据 - mysqlimport
mysqlimport 客户端提供了 LOAD DATA INFILEQL 语句的一个命令行接口。mysqlimport 的大多数选项直接对应 LOAD DATA INFILE 子句。
# 从文件 dump.txt 中将数据导入到 mytbl 数据表
$ mysqlimport -u root -p --local mytbl dump.txt
# 设置指定格式
$ mysqlimport -u root -p --local --fields-terminated-by=":" \
--lines-terminated-by="\r\n" mytbl dump.txt
# 使用 --columns 选项来设置列的顺序:
$ mysqlimport -u root -p --local --columns=b,c,a \
mytbl dump.txt
-
上述语句最后都要输入密码
-
具体可用选项,可见:MySQL 导入数据 | 菜鸟教程 (runoob.com)
1.2表操作
创建删除
# 创建
CREATE TABLE table_name (
column1 datatype,
column2 datatype,
...
);
# 删除
DROP TABLE [IF EXISTS] table_name;
table_name
是你要创建的表的名称。column1
,column2
, … 是表中的列名。datatype
是每个列的数据类型。这里的数据类型是一个规定,并没有实际创建内容。
实例:其中用到了一些参数:
CREATE TABLE IF NOT EXISTS `runoob_tbl`(
`runoob_id` INT UNSIGNED AUTO_INCREMENT,
`runoob_title` VARCHAR(100) NOT NULL,
`runoob_author` VARCHAR(40) NOT NULL,
`submission_date` DATE,
PRIMARY KEY ( `runoob_id` )
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 如果你不想字段为空可以设置字段的属性为 NOT NULL,
- 如上实例中的 runoob_title , 在操作数据库时如果输入该字段的数据为空,就会报错。
- AUTO_INCREMENT 定义列为自增的属性,一般用于主键,数值会自动加 1。
- PRIMARY KEY 关键字用于定义列为主键。
- 您可以使用多列来定义主键,列间以逗号 , 分隔。
- ENGINE 设置存储引擎,CHARSET 设置编码。
自增序列 - auto_increment
MySQL 本身并没有内建的序列类型,但可以使用 AUTO_INCREMENT 属性来模拟序列的行为,通常 AUTO_INCREMENT 属性用于指定表中某一列的自增性。
CREATE TABLE example_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50)
);
- 每次插入一行数据时,id 列的值会自动增加。
- 主键约束保证了 id 列的唯一性。
- 使用 AUTO_INCREMENT 属性的列只能是整数类型(通常是 INT 或 BIGINT)。
- 如果你删除表中的某一行,其自增值不会被重新使用,而是会继续递增
# 不指定 id 列的值,数据库会自动为其分配一个唯一的、自增的值
INSERT INTO table_name (column_name) VALUES ('John');# 插入的数据会包含id和column_name两行内容
# 获取刚刚插入的行的自增值:
SELECT LAST_INSERT_ID();
# 获取表的当前自增值
SHOW TABLE STATUS LIKE 'example_table';
设置起点 - AUTO_INCREMENT = start_number
# 在创建表时设置
mysql> CREATE TABLE insect(
-> id INT UNSIGNED NOT NULL AUTO_INCREMENT,
-> PRIMARY KEY (id),
-> ...)engine=innodb auto_increment=100 charset=utf8;
# alter语句实现
ALTER TABLE t AUTO_INCREMENT = 100;
重置序列编号
在删除了数据表中的多条记录,并希望对剩下数据的 AUTO_INCREMENT 列进行重新排列时:
- 可以通过删除自增的列,然后重新添加来实现。 使用alter语句来实现
- 不过该操作要非常小心,如果在删除的同时又有新记录添加,有可能会出现数据混乱
ALTER TABLE table_name DROP id;
ALTER TABLE table_name ADD id INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (id);
- INT UNSIGNED:表示无符号整型
临时表 - temporary
临时表只在当前会话可见,当关闭连接时,MySQL 会自动删除表并释放所有空间。
当然你也可以手动销毁。
临时表对于需要在某个会话中存储中间结果集或进行复杂查询时非常有用。
创建
# 创建 - temporary
CREATE TEMPORARY TABLE temp_table_name (
column1 datatype,
column2 datatype,
...
);
或
CREATE TEMPORARY TABLE temp_table_name AS
SELECT column1, column2, ...
FROM source_table
WHERE condition;
# 还可以用查询操作来直接创建临时表
CREATE TEMPORARY TABLE 临时表名 AS(
SELECT * FROM 旧的表名 LIMIT 0,10000
);
其他操作
# 其他操作方式和一般表相同
INSERT INTO temp_table_name (column1, column2, ...) VALUES (value1, value2, ...); # 插入
SELECT * FROM temp_table_name; # 查询
ALTER TABLE temp_table_name ADD COLUMN new_column datatype; # 修改
DROP TEMPORARY TABLE IF EXISTS temp_table_name; # 删除
-视图 - view
此功能属于高级用法,详细使用,暂略
-
视图是一种虚拟表 ,本身是不具有数据 的,占用很少的内存空间
- 建立在已有表的基础上, 视图赖以建立的这些表称为基表.
-
视图的创建和删除只影响视图本身,不影响对应的基表。
- 但是当对视图中的数据进行增加、删除和修改操作时,数据表中的数据会相应地发生变化,反之亦然。
在大型项目中,以及数据表比较复杂的情况下,使用视图可以帮助我们把经常查询的结果集放到虚拟表中,提升使用效率。
索引 - index
MySQL 索引是一种数据结构,用于加快数据库查询的速度和性能。
实际上,索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录。
- 单列索引,即一个索引只包含单个列,一个表可以有多个单列索引。
- 组合索引,即一个索引包含多个列。
索引虽然能够提高查询性能,但也需要注意以下几点:
- 索引需要占用额外的存储空间。
- 对表进行插入、更新和删除操作时,索引需要维护,可能会影响性能。
- 过多或不合理的索引可能会导致性能下降,因此需要谨慎选择和规划索引。
创建索引 - create index
CREATE INDEX index_name ON table_name (column1 [ASC|DESC], column2 [ASC|DESC], ...);
(column1, column2, ...)
: 指定要索引的表列名。- 可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。
# 在已有的表中创建索引。
ALTER TABLE table_name ADD INDEX index_name (column1 [ASC|DESC], column2 [ASC|DESC], ...);
# 直接指定索引,同时创建表和索引
CREATE TABLE table_name (
column1 data_type,
column2 data_type,
...,
INDEX index_name (column1 [ASC|DESC], column2 [ASC|DESC], ...)
);
删除索引 - drop index
DROP INDEX index_name ON table_name;
或
ALTER TABLE table_name DROP INDEX index_name;
- 如果该索引不存在,执行命令时会产生错误。
展示索引 - show index
SHOW INDEX FROM table_name
唯一索引 - unique
# 创建
CREATE UNIQUE INDEX index_name ON table_name (column1 [ASC|DESC], column2 [ASC|DESC], ...);
# 或使用 alter语句
ALTER table mytable ADD CONSTRAINT unique_constraint_name UNIQUE (column1, column2, ...);
# 或在表创建同时指定
CREATE TABLE table_name (
column1 data_type,
column2 data_type,
...,
CONSTRAINT index_name UNIQUE (column1 [ASC|DESC], column2 [ASC|DESC], ...)
);
ADD CONSTRAINT
: 这是用于添加约束(包括唯一索引)的关键字。unique_constraint_name
: 指定要创建的唯一索引的名称,约束名称在表中必须是唯一的。UNIQUE (column1, column2, ...)
: 指定要索引的表列名。你可以指定一个或多个列作为索引的组合。这些列的数据类型通常是数值、文本或日期。- 如果表中已经有重复的值,那么添加唯一索引将会失败
实例:email 列被定义为唯一索引
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
email VARCHAR(100) UNIQUE
);
常用技巧
复制表 - show create table
完全的复制 MySQL 的数据表,包括表的结构,索引,默认值等。
- 仅仅使用 CREATE TABLE … SELECT 命令,是无法实现的。
步骤:
- 使用 SHOW CREATE TABLE 命令获取创建数据表(CREATE TABLE) 语句,该语句包含了原数据表的结构,索引等。
- 复制得到的 SQL 语句,修改数据表名,并执行SQL语句,
- 如果你想复制表的内容,你就可以使用 INSERT INTO … SELECT 语句来实现。
实例:
# 1.获取原表结构
mysql> SHOW CREATE TABLE runoob_tbl \G;
*************************** 1. row ***************************
Table: runoob_tbl
Create Table: CREATE TABLE `runoob_tbl` (
`runoob_id` int(11) NOT NULL auto_increment,
`runoob_title` varchar(100) NOT NULL default '',
`runoob_author` varchar(40) NOT NULL default '',
`submission_date` date default NULL,
PRIMARY KEY (`runoob_id`),
UNIQUE KEY `AUTHOR_INDEX` (`runoob_author`) ) ENGINE=InnoDB
1 row in set (0.00 sec)
# 2.创建相同结构的新表
mysql> CREATE TABLE `clone_tbl` (
-> `runoob_id` int(11) NOT NULL auto_increment,
-> `runoob_title` varchar(100) NOT NULL default '',
-> `runoob_author` varchar(40) NOT NULL default '',
-> `submission_date` date default NULL,
-> PRIMARY KEY (`runoob_id`),
-> UNIQUE KEY `AUTHOR_INDEX` (`runoob_author`) ) ENGINE=InnoDB;
Query OK, 0 rows affected (1.80 sec)
# 3.复制内容
mysql> INSERT INTO clone_tbl (runoob_id,runoob_title,runoob_author,submission_date)
-> SELECT runoob_id,runoob_title,runoob_author,submission_date FROM runoob_tbl;
Query OK, 3 rows affected (0.07 sec)
Records: 3 Duplicates: 0 Warnings: 0
简单方法
CREATE TABLE targetTable LIKE sourceTable;
INSERT INTO targetTable SELECT * FROM sourceTable;
- 使用like语句直接复制表结构
1.3数据操作
列的表示
- 使用列名称:column1
- 使用数字(序号):第k列
插入数据-insert into + value
INSERT INTO table_name (column1, column2, column3, ...) VALUES (value1, value2, value3, ...);
column1
,column2
,column3
, … 是表中的列名。- 如果你要插入所有列的数据,可以省略列名
value1
,value2
,value3
, … 是要插入的具体数值。
多行插入- values
INSERT INTO users
VALUES
(NULL,'test1', 'test1@runoob.com', '1985-07-10', true),
(NULL,'test2', 'test2@runoob.com', '1988-11-25', false),
(NULL,'test3', 'test3@runoob.com', '1993-05-03', true);
- NULL 是用于自增长列的占位符,表示系统将为 id 列生成一个唯一的值。
更新-update
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
column1
,column2
, … 是你要更新的列的名称。value1
,value2
, … 是新的值,用于替换旧的值。- SET:指出需要更新的列
- where:对列中的每一行作条件判断。通过则更新
实例:更新多列单行:
UPDATE orders
SET status = 'Shipped', ship_date = '2023-03-01'
WHERE order_id = 1001;
删除 - delete
DELETE FROM table_name WHERE condition;
- delete语句将会删除行中的记录,但是不改变数据表的结构
实例:
DELETE FROM students WHERE graduation_year = 2021;# 删除指定行
1.4SQL约束
约束用于指定表中数据的规则。
- 限制可以进入表的数据类型。这 确保表中数据的准确性和可靠性。如果约束和数据操作之间存在任何冲突, 操作将中止。
- 约束可以是列级或表级。
- 列级约束 应用于列,
- 表级约束应用于整个表。
- 列级约束 应用于列,
常用约束包括:
NOT NULL
- 确保列不能具有 NULL 值UNIQUE
- 确保列中的所有值都 不同PRIMARY KEY
- not null 和 unique 的组合。 唯一标识表中的每一行FOREIGN KEY
- 防止会破坏表之间链接的操作CHECK
- 确保 列中的值满足特定条件DEFAULT
- 设置列的默认值 如果没有值 被指定CREATE INDEX
- 创建索引用于从数据库创建和检索数据,提高效率- 关于索引的操作,见[index](# 索引 - index)
CREATE TABLE table_name (
column1 datatype constraint,
column2 datatype constraint,
column3 datatype constraint,
....
);
- 约束通常在创建表格的时候指定。
- 但也可以通过alter语句进行修改
主键 - primary key
-
不能重复,不能为null,
- 可以使用unique约束和主键叠加
-
一张表中最多只能有一个主键;
-
主键所在的列通常是整数类型。
CREATE TABLE Persons (
ID int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int,
PRIMARY KEY (ID)
);
或
ALTER TABLE Persons ADD PRIMARY KEY (ID);
# 删除主键
ALTER TABLE Persons DROP PRIMARY KEY;
- 可以使用
CONSTRAINT UC_Person PRIMARY KEY(ID,LastName)
的格式替换PRIMARY KEY(ID,LastName)
实现在添加多列约束的同时对约束进行命名
唯一 - unique
- 该约束可确保列中的所有值都不同,效果和主键类似
- 但一个表中可以有多列unique约束
- 可以为null???
# 添加约束
CREATE TABLE Persons (
ID int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int,
UNIQUE (ID)
);constraint
或
ALTER TABLE Persons ADD UNIQUE (ID);
# 删除约束
ALTER TABLE Persons DROP INDEX UC_Person;
- 可以使用
CONSTRAINT UC_Person UNIQUE (I,LastNameD)
的格式替换UNIQUE (ID,LastName)
实现在添加多列约束的同时对约束进行命名
自动递增 - auto
详见[auto](# 自增序列 - auto_increment)
外键 - foreing key references
用于防止会破坏表之间链接的操作
- 带有外键的表称为子表
- 与主键称为引用表或父表
CREATE TABLE Orders (
OrderID int NOT NULL,
OrderNumber int NOT NULL,
PersonID int,
PRIMARY KEY (OrderID),
FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
);
或
ALTER TABLE Orders ADD FOREIGN KEY (PersonID) REFERENCES Persons(PersonID);
# 删除外键
ALTER TABLE Orders DROP FOREIGN KEY FK_PersonOrder;
- “Orders”表中的“PersonID”列是“Orders”表中的列。
条件检查 - check
只允许满足条件的值被放入
- 如果对列定义约束,则检查条件只能涉及这一列
- 如果对表定义约束,则可以根据行中其他列中的值限制某些列中的值。``
CREATE TABLE Persons (
ID int NOT NULL,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int,
CHECK (Age>=18)
);
或
ALTER TABLE Persons ADD CHECK (Age>=18);
# 删除检查
ALTER TABLE Persons DROP CHECK CHK_PersonAge;
默认值 - default
在该列中,默认值将取代null值发挥作用。
- 默认值可以设置为数值、字符串、或者系统函数
CREATE TABLE Orders (
ID int NOT NULL,
OrderNumber int NOT NULL,
OrderDate date DEFAULT GETDATE()
);
或
ALTER TABLE Persons ALTER City SET DEFAULT 'Sandnes';
# 删除默认值
ALTER TABLE Persons ALTER City DROP DEFAULT;
- 这里的两个alter语句没问题吗???
修改结构 - alter
ALTER 命令用于修改数据库、表和索引等对象的结构。
ALTER 命令允许你添加、修改或删除数据库对象,并且可以用于更改表的列定义、添加约束、创建和删除索引等操作。
ALTER 命令非常强大,可以在数据库结构发生变化时进行灵活的修改和调整。
但在使用 ALTER 命令时要格外小心,因为一些操作可能需要重建表或索引,这可能会影响数据库的性能和运行时间。
在进行重要的结构修改时,建议先备份数据,并在生产环境中谨慎操作。
可以实现的操作包括:
- add
- drop
- modify
- change
- rename
# 添加列 - add column
ALTER TABLE employees ADD COLUMN birth_date DATE;
# 删除列 - drop column
ALTER TABLE table_name DROP COLUMN column_name;
# 修改列数据类型 - modify column
ALTER TABLE TABLE_NAME MODIFY COLUMN column_name new_datatype;
# 修改列名 - change column
ALTER TABLE table_name CHANGE COLUMN old_column_name new_column_name datatype;
# 修改表名 - rename to
ALTER TABLE old_table_name RENAME TO new_table_name;
# 添加主键 - add primary key
ALTER TABLE table_name ADD PRIMARY KEY (column_name);
# 添加外键 - add constraint [] foreing key [] references
ALTER TABLE child_table ADD CONSTRAINT fk_name FOREIGN KEY (column_name) REFERENCES parent_table (column_name);
#
- 注意,格式中要求:table+table_name , column+column_name
- 除此以外还有很多.
修改索引
# 添加
ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): #该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): #这条语句创建索引的值必须是一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): #添加普通索引,索引值可出现多次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):#该语句指定了索引为 FULLTEXT ,用于全文索引。
# 删除
修改主键
# 修改
ALTER TABLE testalter_tbl MODIFY i INT NOT NULL;# 首先确保当前列没有null值
ALTER TABLE testalter_tbl ADD PRIMARY KEY (i);# 设定i为主键,可以有多个
# 删除
ALTER TABLE testalter_tbl DROP PRIMARY KEY;
1.5其他操作
别名-as
# 对列使用
SELECT column_name AS alias_name FROM table_name;
# 对表使用
SELECT column_name(s) FROM table_name AS alias_name;
元数据
元数据:关于数据库和其对象(如表、列、索引等)的信息。
-
存储在系统表中,位于 MySQL 的 information_schema 数据库中,
-
通过查询这些系统表,可以获取关于数据库结构、对象和其他相关信息的详细信息。
具体来说,可以得到的信息包括:
- 查询结果信息: SELECT, UPDATE 或 DELETE语句影响的记录数。
- 数据库和数据表的信息: 包含了数据库及数据表的结构信息。
- MySQL 服务器信息: 包含了数据库服务器的当前状态,版本号等。
基础数据库信息查询
这个不是元数据的操作,只是可以得到相似的信息。
SHOW DATABASES;# 查看所有数据库
USE database_name;# 选择数据库
SHOW TABLES;# 查看当前库中所有表
DESC table_name;# 查看表结构
SHOW INDEX FROM table_name;# 查看表的索引
SHOW CREATE TABLE table_name;# 查看表的创建语句
SELECT COUNT(*) FROM table_name;# 查看表的行数
information_schema 数据库信息查询
# 查看列的信息:列名,数据类型等
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_KEY FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
# 查看外键信息
SELECT TABLE_NAME, COLUMN_NAME, CONSTRAINT_NAME, REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name'
AND REFERENCED_TABLE_NAME IS NOT NULL;
information_schema 数据库
information_schema 是 MySQL 数据库中的一个系统数据库,它包含有关数据库服务器的元数据信息,这些信息以表的形式存储在 information_schema 数据库中。
SCHEMATA 表
存储有关数据库的信息,如数据库名、字符集、排序规则等。
SELECT * FROM information_schema.SCHEMATA;
TABLES 表
包含有关数据库中所有表的信息,如表名、数据库名、引擎、行数等。
SELECT * FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_database_name';
COLUMNS 表
包含有关表中列的信息,如列名、数据类型、是否允许 NULL 等。
SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
STATISTICS 表
提供有关表索引的统计信息,如索引名、列名、唯一性等。
SELECT * FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
KEY_COLUMN_USAGE 表
包含有关表中外键的信息,如外键名、列名、关联表等。
SELECT * FROM information_schema.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
REFERENTIAL_CONSTRAINTS 表
存储有关外键约束的信息,如约束名、关联表等。
SELECT * FROM information_schema.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_SCHEMA = 'your_database_name' AND TABLE_NAME = 'your_table_name';
这些表提供了丰富的元数据信息,可以用于查询数据库结构、表信息、列信息、索引信息等。
请注意,你需要将查询中的 ‘your_database_name’ 和 ‘your_table_name’ 替换为实际的数据库名和表名。
1.6查询 - select
SELECT column1, column2, ...
FROM table_name
[WHERE condition]
[ORDER BY column_name [ASC | DESC]]
[LIMIT number];
column1
,column2
, … 是你想要选择的列的名称,- 如果使用
*
表示选择所有列。
- 如果使用
WHERE condition
是一个可选的子句,用于指定过滤条件,只返回符合条件的行。ORDER BY column_name [ASC | DESC]
是一个可选的子句,用于指定结果集的排序顺序- 默认是升序(ASC)。
LIMIT number
是一个可选的子句,用于限制返回的行数。
实例:
-- 选择所有列的所有行
SELECT * FROM users;
-- 选择特定列的所有行
SELECT username, email FROM users;
-- 添加 WHERE 子句,选择满足条件的行
SELECT * FROM users WHERE is_active = TRUE;
-- 添加 ORDER BY 子句,按照某列的升序排序
SELECT * FROM users ORDER BY birthdate;
-- 添加 ORDER BY 子句,按照某列的降序排序
SELECT * FROM users ORDER BY birthdate DESC;
-- 添加 LIMIT 子句,限制返回的行数
SELECT * FROM users LIMIT 10;
# WHERE 添加筛选条件
-- 使用 AND 运算符和通配符
SELECT * FROM users WHERE username LIKE 'j%' AND is_active = TRUE;
-- 使用 OR 运算符
SELECT * FROM users WHERE is_active = TRUE OR birthdate < '1990-01-01';
-- 使用 IN 子句
SELECT * FROM users WHERE birthdate IN ('1990-01-01', '1992-03-15', '1993-05-03');
限制数量 - limit ,top
sql语句支持top,而mysql数据库只支持limit
- 两者的功能是一样的
- limit和top在语句执行中的优先级最低。
SELECT column_name FROM table_name WHERE condition LIMIT number;
或
SELECT TOP number PERCENT column_name FROM table_name WHERE condition;# PERCENT表示需要展示的列
SELECT TOP 3 * FROM table_name;
或
SELECT * FROM Customers
LIMIT 3;
查询条件 - where
- 查询语句中你可以使用一个或者多个表,表之间使用逗号**,** 分割,并使用WHERE语句来设定查询条件。
- WHERE 子句也可以运用于 SQL 的 DELETE 或者 UPDATE 命令。
- WHERE 子句类似于程序语言中的 if
结果合并 - union (all)
用于连接两个以上的 SELECT 语句的结果组合到一个结果集合,并去除重复的行。
- 可以使用 union all实现不去除重复行。
UNION 操作符必须由两个或多个 SELECT 语句组成,每个 SELECT 语句的列数和对应位置的数据类型必须相同。
SELECT column1, column2, ... FROM table1 WHERE condition1
UNION
SELECT column1, column2, ... FROM table2 WHERE condition2 [ORDER BY column1, column2, ...];
ORDER BY
子句是一个可选的子句,用于指定合并后的结果集的排序顺序。
实例:选择电子产品和服装类别的产品名称,并按产品名称升序排序。
SELECT product_name FROM products WHERE category = 'Electronics'
UNION
SELECT product_name FROM products WHERE category = 'Clothing'
ORDER BY product_name;
排序 - order by
按照一个或多个列的值进行升序(ASC)或降序(DESC)排序。
SELECT column1, column2, ...
FROM table_name
ORDER BY column1 [ASC | DESC], column2 [ASC | DESC], ...;
-
ASC
表示升序(默认),DESC
表示降序。 -
可以用NULLS LAST和 NULLS LAST 来处理null
-
DESC NULLS LAST# 降序 DESC 排序,将 NULL 值排在最后
-
-
会先按照column1排序,在column1的相同值中,再按照column2排序
实例:选择产品表 products 中的产品名称和根据折扣率计算的折扣后价格,并按折扣后价格降序 DESC 排序。
SELECT product_name, price * discount_rate AS discounted_price
FROM products
ORDER BY discounted_price DESC;
分组 - group by
GROUP BY
子句通常与聚合函数一起使用,因为分组后需要对每个组进行聚合操作。SELECT
子句中的列通常要么是分组列,要么是聚合函数的参数。
SELECT column1, aggregate_function(column2) FROM table_name WHERE condition
GROUP BY column1;
aggregate_function(column2)
:对分组后的每个组执行的聚合函数。
实例:按照名字进行分组并统计每个名字下有多少条记录
SELECT name, COUNT(*) FROM employee_tbl GROUP BY name;
with rollup
以实现在分组统计数据基础上再进行相同的统计(SUM,AVG,COUNT…)。
实例:在得到每个名字下有多少条记录的同时,对这些统计数据在执行一次累加,得到总记录数量。
SELECT name, SUM(signin) as signin_count FROM employee_tbl GROUP BY name WITH ROLLUP;
- 会多出一行name=null的数据,用于存放总数。
分组过滤 - having
由于group by不能用where作过滤,所以使用having作为一个专用的替代。
SELECT column_name FROM table_name WHERE condition
GROUP BY column_name HAVING condition ORDER BY column_name;
- having会按照分组**,对每一个分组执行条件判断。**
- 符合条件的分组才会被返回
- 注意,having是按照分组一次性执行的,所以基本都需要用到聚合函数,
实例:列出员工“Davolio”或“Fuller”是否已注册 超过 25 个订单:
SELECT Employees.LastName, COUNT(Orders.OrderID) AS NumberOfOrders FROM Orders
INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
WHERE LastName = 'Davolio' OR LastName = 'Fuller'
GROUP BY LastName HAVING COUNT(Orders.OrderID) > 25;
消除重复 - distinct
去除查询得到的返回数据中重复的内容
SELECT DISTINCT columns FROM table_name WHERE where_conditions;
- 如果列具有
NULL
值,并且对该列使用DISTINCT
子句,MySQL将保留一个NULL
值,并删除其它的NULL
值 - distinct也可以针对其中的某一列数据经行去重
实例:对于每一个 date_id
和 make_name
,找出 不同 的 lead_id
以及 不同 的 partner_id
的数量。
select date_id,make_name,
count( distinct lead_id)as unique_leads,
count( distinct partner_id) as unique_partners
from DailySales group by date_id,make_name
与group by的比较
如果在SELECT
语句中使用GROUP BY
子句,而不使用聚合函数,则GROUP BY
子句的行为与DISTINCT
子句类似。
聚合函数
从数据表中得到一定的聚合信息:
函数 | 说明 |
---|---|
count([distinct] expr) | 返回查询到的数据的数量 |
sum([distinct] expr) | 返回查询到的数据的总和,不是数字没有意义 |
avg([distinct] expr) | 返回查询到的数据的平均值,不是数字没有意义 |
max([distinct] expr) | 返回查询到的数据的最大值,不是数字没有意义 |
min([ditinct] expr) | 返回查询到的数据的最小值,不是数字没有意义 |
例如: select sum(math) from exam,计算exam表中math列的总和并显示出来
- 可以在函数的输入参数中,添加筛选条件,即,用计算式作为输入参数。
- 本质上,是用计算式的返回结果作为输入,
- 但是注意,count(*)函数是计算数据条数,会计算null值。详见[null值处理](# null值处理)
- 所以,在count中添加条件筛选,例如只计算大于10 的数据,无法得到希望的值。
- 可以用sum(if(条件,1,0))代替。
-复合语句
-数据写入 - select into
将数据从一个表复制到一个新表中
SELECT column1, column2, column3, ...
INTO newtable [IN externaldb]
FROM oldtable
WHERE condition;
- 从oldtable中查询得到数据列,并将他们直接写入到newtable中
- in:用于指定数据库,可以直接将数据写入到其他数据库的表中
应用技巧:
# 创建相同格式的空表
SELECT * INTO newtable FROM oldtable WHERE 1 = 0;
# 数据表备份
SELECT * INTO CustomersBackup2017 FROM Customers;
# 将数据表写入到其他数据库
SELECT * INTO CustomersBackup2017 IN 'Backup.mdb' FROM Customers;
-数据写入 - insert into select
这是一种语句的组合应用。
- 用select的查询结果作为insert的插入值。
- 并且查询结果中自动包含了列和值两个信息。
INSERT INTO table2
SELECT column1, column2... FROM table1 WHERE condition;
1.7条件操作符
条件操作符 - 与或非,大小等,in,between,is
- 操作符:=,>,<,<=,>=,!=,<>
- 逻辑符:and,or,not
- 包含条件:in,between
- 模糊匹配:like,详细见like语句部分
- is条件:is
符号 | 描述 | 备注 |
---|---|---|
BETWEEN | 在两值之间 | >=min&&<=max |
NOT BETWEEN | 不在两值之间 | |
IN | 在集合中 | |
NOT IN | 不在集合中 | |
null值判定 | ||
IS NULL | 为空 | |
IS NOT NULL | 不为空 | |
逻辑符 | ||
NOT 或 ! | 逻辑非 | |
AND | 逻辑与 | |
OR | 逻辑或 | |
XOR | 逻辑异或 | |
位运算 | ||
& | 按位与 | |
| | 按位或 | |
^ | 按位异或 | |
! | 取反 | |
<< | 左移 | |
>> | 右移 | |
SELECT * FROM students WHERE age <= 21;
SELECT * FROM countries WHERE country_code IN ('US', 'CA', 'MX');
SELECT * FROM orders WHERE order_date BETWEEN '2023-01-01' AND '2023-12-31';
SELECT * FROM customers WHERE first_name LIKE 'J%';
SELECT * FROM employees WHERE department IS NULL;
存在判断 - exists
测试子查询中是否存在任何记录
SELECT column_name(s) FROM table_name
WHERE EXISTS (
SELECT column_name FROM table_name WHERE condition
);
- 如果子查询返回一条或多条记录,则运算符返回 TRUE。
任意匹配 - any
- 如果任何子查询值满足条件,则返回 TRUE
SELECT column_name(s) FROM table_name
WHERE column_name operator ANY(
SELECT column_name FROM table_name WHERE condition
);
x = ANY (…) | c列中的值必须与集合中的一个或多个值匹配,以评估为true。 |
---|---|
x != ANY (…) | c列中的值不能与集合中的一个或多个值匹配以评估为true。 |
x > ANY (…) | c列中的值必须大于要评估为true的集合中的最小值。 |
x < ANY (…) | c列中的值必须小于要评估为true的集合中的最大值。 |
x >= ANY (…) | c列中的值必须大于或等于要评估为true的集合中的最小值。 |
x <= ANY (…) | c列中的值必须小于或等于要评估为true的集合中的最大值。 |
实例:列出了 ProductName,如果它发现 OrderDetails 表中的任何记录的数量大于 99
SELECT ProductName FROM Products
WHERE ProductID = ANY (
SELECT ProductID FROM OrderDetails WHERE Quantity > 99
);
全匹配 - all
ALL
means that the condition will be true only if the operation is true for all values in the range.
列值必须对所有返回的值都满足条件,才能判定通过。
SELECT column_name(s) FROM table_name
WHERE column_name operator ALL(
SELECT column_name FROM table_name WHERE condition
);
c > ALL(…) | c列中的值必须大于要评估为true的集合中的最大值。 |
---|---|
c >= ALL(…) | c列中的值必须大于或等于要评估为true的集合中的最大值。 |
c < ALL(…) | c列中的值必须小于要评估为true的集合中的最小值。 |
c <= ALL(…) | c列中的值必须小于或等于要评估为true的集合中的最小值。 |
c <> ALL(…) | c列中的值不得等于要评估为true的集合中的任何值。 |
c = ALL(…) | c列中的值必须等于要评估为true的集合中的任何值。 |
实例:
SELECT ProductNameFROM Products
WHERE ProductID = ALL(
SELECT ProductID FROM OrderDetails WHERE Quantity = 10
);
模糊匹配-like
与通配符一起使用,用于搜索符合某种模式的字符串。
SELECT column1, column2, ...
FROM table_name
WHERE column_name LIKE pattern;
- 查找column_name列中符合like条件的行,并返回对应行的 column1, column2
通配符
- % 通配符表示零个或多个字符。例如,‘a%’ 匹配以字母 ‘a’ 开头的任何字符串。
- 如果没有使用百分号 %, LIKE 子句与等号 = 的效果是一样的。
- _ 通配符表示一个字符。例如,‘_r%’ 匹配第二个字母为 ‘r’ 的任何字符串。
- []:表示括号内所列字符中的一个(类似正则表达式)。
- 指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个。
- [^] :表示不在括号所列之内的单个字符。
- 其取值和 [] 相同,但它要求所匹配对象为指定字符以外的任一个字符。
- 对于需要匹配特殊字符,把特殊字符用 “[ ]” 括起便可正常查询。
实例:
SELECT * FROM employees WHERE last_name LIKE 'smi%' COLLATE utf8mb4_general_ci;
# 其中的COLLATE utf8mb4_general_ci 表示匹配不区分大小写。
SELECT * FROM users WHERE username LIKE 'a%o_';# 匹配如 'aaron'、'apolo'。
'%a' //以a结尾的数据
'a%' //以a开头的数据
'%a%' //含有a的数据
'_a_' //三位且中间字母是a的
'_a' //两位且结尾字母是a的
'a_' //两位且开头字母是a的
正则匹配-regexp,rlike
SELECT column1, column2, ... FROM table_name
WHERE column_name REGEXP [BINARY] 'pattern';
或
SELECT column1, column2, ...
FROM table_name
WHERE column_name RLIKE [BINARY] 'pattern';
- rlike与repexp的使用没有区别
- 使用 BINARY 关键字,使得匹配区分大小写:
正则符号
.
:匹配除 “\n” 之外的任何单个字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像 ‘[.\n]’ 的模式。*
:匹配零个或多个前面的元素。-
- 等价于{0,}。
-
+
:匹配一个或多个前面的元素。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。-
- 等价于 {1,}。
-
?
:匹配零个或一个前面的元素。^
:匹配字符串的开始。$
:匹配字符串的结束。[abc]
:匹配字符集中的任意一个字符。[^abc]
:匹配除了字符集中的任意一个字符以外的字符。例如, [^abc] 可以匹配 “plain” 中的’p’。[a-z]
:匹配范围内的任意一个小写字母。也可以写成数字范围\d
:匹配一个数字字符。\w
:匹配一个字母数字字符(包括下划线)。\s
:匹配一个空白字符。
模式 | 描述 |
---|---|
^ | 匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。 |
$ | 匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置 |
p1|p2|p3 | 匹配 p1 或 p2 或 p3。例如,‘z|food’ 能匹配 “z” 或 “food”。‘(z|f)ood’ 则匹配 “zood” 或 “food”。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。 |
实例:
# 查找 name 字段中以 **'st'** 为开头的所有数据:
mysql> SELECT name FROM person_tbl WHERE name REGEXP '^st';
# 查找 name 字段中以元音字符开头或以 **'ok'** 字符串结尾的所有数据:
mysql> SELECT name FROM person_tbl WHERE name REGEXP '^[aeiou]|ok$';
# 使用 **BINARY** 关键字,使得匹配区分大小写:
SELECT * FROM products WHERE product_name REGEXP BINARY 'apple';
# 查找 name 字段中包含 **'mar'** 字符串的所有数据:
mysql> SELECT name FROM person_tbl WHERE name REGEXP 'mar';
# 选择订单表中描述中包含 "item" 后跟一个或多个数字的记录。
SELECT * FROM orders WHERE order_description REGEXP 'item[0-9]+';
1.8语句
条件判断
case-when-then-else
CASE 表示函数开始,END 表示函数结束。
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
WHEN conditionN THEN resultN
ELSE result
END;
- 一旦条件为真,它就会停止 读取并返回结果。
- 如果没有条件为真,则返回 else子句中的值
-窗口函数 - over
over是窗口函数
- 能够在同一行中同时返回基础行的列和聚合列。
- 通常都是在select等语句的返回的查询列的位置使用。
- 用于对查询得到的列数据作进一步的处理。
需要和开窗函数结合使用
- 开窗函数可以是各种其他的函数。
- 聚合函数:SUM(),MAX(),MIN,COUNT(),AVG()
- 排序函数:RANK(),ROW_NUMBER(),DENSE_RANK(),NTILE()
- 窗口函数OVER()指定一组行,开窗函数计算从窗口函数输出的结果集中各行的值。
OVER(partition by 列名 order by列名) 。
- partition: 需要分区的列(可不使用)
- 开窗函数会根据分区分别执行。
- 只使用partition时相当于group by
- order by: 对分区内部的数据进行排序。语法上和[查询排序](# 排序 - order by)一样,
实例:
SUM(Salary) OVER (PARTITION BY Groupname)#只对PARTITION BY后面的列Groupname进行分组,分组后求解Salary的和。
SUM(Salary) OVER (PARTITION BY Groupname ORDER BY ID)#对PARTITION BY后面的列Groupname进行分组,然后按ORDER BY 后的ID进行排序,然后在组内对Salary进行累加处理。
SUM(Salary) OVER (ORDER BY ID)#只对ORDER BY 后的ID内容进行排序,对排完序后的Salary进行累加处理。
SUM(Salary) OVER ()#对Salary进行汇总处理
聚合型窗口
使用聚合函数。
- 只有partition:会对分区执行聚合,相当于group by
- 只有order by:会按照顺序,对所有行逐次执行聚合并累加。
- 如果使用sum(),就相当于逐次累加。
- 如果使用avg(),就相当于累进平均值。
- 如果使用count(),则相当于一个自增序列。
- 两者都有:开窗函数会在分区内根据顺序依次处理并累积处理结果
排序型窗口
使用排序函数。
-
这些排序函数都需要和over一起才能使用。无法单独使用
-
必须要有order by:根据顺序给出需要
-
两者都有:会按照分区,分别排序。
-行偏移函数 - lag,lead
这是少有的可以对数据行作独立处理的函数。
lag:
- 查询当前行向上偏移n行后的结果,即在当前行,就可以使用向上第n行的参数。
lead:
- 查询当前行向下偏移n行后的结果
三个参数:
- 待查询的列,
- 向上(下)偏移的行数,
- 超出最上(下)边界的默认值
这两个函数需要和over函数一起使用,
- lag和lead属于排序函数,必须依靠over明确指出顺序,才能做到偏移。
实例:从一个包含自增序列id和int序列num的数据表中,找出连续出现三次及以上的num值
SELECT DISTINCT(Num) ConsecutiveNums FROM(
SELECT *,
LAG(Num,1,0) OVER(ORDER BY Id) Num1,
LAG(Num,2,0) OVER(ORDER BY Id) Num2
FROM logs
)
WHERE Num = Num1 AND Num1 = Num2
注释
-- 单行注释
# 部分地方也支持
/*
多行注释
*/
1.9多表操作
- join:用于将多个数据表的不同列合并到一起来处理。
- 要求不同数据表中需要有可以用于匹配的列。
- union:用于将多个数据表的不同行合并到一起。
- 要求不同数据表之间的列尽可能的相近。
连接 - join
可以在 SELECT, UPDATE 和 DELETE 语句中使用 MySQL 的 JOIN 来联合多表查询。
JOIN 按照功能大致分为如下三类:
- INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录。
- **LEFT JOIN(左连接):**获取左表所有记录,即使右表没有对应匹配的记录。
- RIGHT JOIN(右连接): 与 LEFT JOIN 相反,用于获取右表所有记录,即使左表没有对应匹配的记录。
注意:
- 使用了连接之后的两个表,并不可以作为一个表来看待,去赋予别名
- 并且,想要提取其中的列也必须明确指出是哪一个表
inner join
SELECT column1, column2, ... FROM table1
INNER JOIN table2 ON table1.column_name = table2.column_name;
- 返回两个表中满足连接条件的匹配行
table1
,table2
是要连接的两个表的名称。table1.column_name = table2.column_name
是连接条件,指定了两个表中用于匹配的列。
实例:多表inner join
SELECT orders.order_id, customers.customer_name, products.product_name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.customer_id
INNER JOIN order_items ON orders.order_id = order_items.order_id
INNER JOIN products ON order_items.product_id = products.product_id
WHERE orders.order_date >= '2023-01-01';
- 涉及了 orders、customers、order_items 和 products 四个表的连接。它选择了订单 ID、客户名称和产品名称,连接了这些表的关联列。
- 并在join之后使用了where语句,筛选出在指定日期之后的数据。
left join 与 right join
返回左表的所有行,并包括右表中匹配的行,如果右表中没有匹配的行,将返回 NULL 值
- 即不对左表作筛选,只是单纯的将右表加入到坐标
SELECT column1, column2, ... FROM table1
LEFT JOIN table2 ON table1.column_name = table2.column_name;
实例:
SELECT customers.customer_id, customers.customer_name, orders.order_id, products.product_name
FROM customers
LEFT JOIN orders ON customers.customer_id = orders.customer_id
LEFT JOIN order_items ON orders.order_id = order_items.order_id
LEFT JOIN products ON order_items.product_id = products.product_id;
- 左连接保证了即使在 order_items 或 products 中没有匹配的行,仍然会返回客户和订单的信息。
在开发过程中中,RIGHT JOIN 并不经常使用,因为它可以用 LEFT JOIN 和表的顺序交换来实现相同的效果
全连接 - full outer join
- 如图所示,C代表两个数据表中符合匹配条件的部分,C包含两个表中的所有相应列
- 内连接:得到C
- 左连接:得到A+C
- 右连接:得到B+C
- 全连接:得到A+B+C
- 所以全连接得到的结果会很大,且其中可能会包含大量的null值。
SELECT column_name(s) FROM table1
FULL OUTER JOIN table2 ON table1.column_name = table2.column_name
WHERE condition;
自连接 - self_join
将一个数据表内的不同行作为连接的依据
实际上并不需要用到join关键字。
SELECT column_name(s) FROM table1 T1, table1 T2 WHERE condition;
- T1 和 T2 是同一表的不同表别名。
- 再后续条件判定中,就使用这两个表别名来实现。
实例:
SELECT A.CustomerName AS CustomerName1, B.CustomerName AS CustomerName2, A.City
FROM Customers A, Customers B
WHERE A.CustomerID <> B.CustomerID AND A.City = B.City
ORDER BY A.City;
合并 - union
详见查询部分。[union](# 结果合并 - union)
查询字段为表达式
select 列名1,计算式… from 表名
例如,计算式可以为:列1+列2*列3,最终会得到一列的计算结果
为查询结果指定别名
select 列名1,计算式 别名,… from 表名
最终显示的计算结果列的名称会被改为别名
结果去重
select 列名1,distinct 列名2… from 表名
会根据被标记 dixtinct的列,取出所有重复的行。
1.10事务
(搞不清楚这是个什么东西,是不是和下面的语句时间一样???)
在 MySQL 中,事务是一组SQL语句的执行,它们被视为一个单独的工作单元。
-
比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务
-
在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务。
-
事务处理可以用来维护数据库的完整性,保证成批的 SQL 语句要么全部执行,要么全部不执行。
-
事务用来管理 insert、update、delete 语句
事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。
- **原子性:**一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
- 事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态。
- **一致性:**在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
- **隔离性:**数据库允许多个并发事务同时对其数据进行读写和修改的能力,多个事务并发执行时不会由于交叉执行而导致数据的不一致。
- 事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- **持久性:**事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务控制语句:
自动提交:在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。
- 因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
直接用 SET 来改变 MySQL 的自动提交模式:
-
SET AUTOCOMMIT=0 禁止自动提交
-
SET AUTOCOMMIT=1 开启自动提交
-
BEGIN 或 START TRANSACTION 显式地开启一个事务;
-
COMMIT 、 COMMIT WORK:
- 提交事务,并使已对数据库进行的所有修改成为永久性的;
-
SET TRANSACTION :用来设置事务的隔离级别。
- InnoDB 存储引擎提供事务的隔离级别有:
- 读未提交(Read uncommitted)、读提交(read committed)、
- 可重复读(repeatable read)和串行化(Serializable)
- InnoDB 存储引擎提供事务的隔离级别有:
-
ROLLBACK 、 ROLLBACK WORK:
- 回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
标记相关语句:
- SAVEPOINT identifier,SAVEPOINT :
- 允许在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
- RELEASE SAVEPOINT identifier:
- 删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
- ROLLBACK TO identifier 把事务回滚到标记点;
实例:
-- 开始事务
START TRANSACTION;
-- 执行一些SQL语句
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;
-- 判断是否要提交还是回滚
IF (条件) THEN
COMMIT; -- 提交事务
ELSE
ROLLBACK; -- 回滚事务
END IF;
语句事件 - procedures
??????
# 创建
CREATE PROCEDURE procedure_name
AS
sql_statement# 要执行的sql语句
GO;
# 执行
EXEC procedure_name;
- 其中可以使用参数,增加事件的适用性,详见实例
实例:从“客户”表中选择具有特定邮政编码的特定城市的客户
CREATE PROCEDURE SelectAllCustomers @City nvarchar(30), @PostalCode nvarchar(10)
AS
SELECT * FROM Customers WHERE City = @City AND PostalCode = @PostalCode
GO;
1.11函数
MySQL 字符串函数
函数 | 描述 | 实例 |
---|---|---|
字符串对比 | ||
STRCMP(s1,s2) | 比较字符串 s1 和 s2,如果 s1 与 s2 相等返回 0 , 如果 s1>s2 返回 1,如果 s1<s2 返回 -1 | |
CHAR_LENGTH(s)、CHARACTER_LENGTH(s) | 返回字符串 s 的字符数 | |
字符串变换 | ||
ASCII(s) | 返回字符串 s 的第一个字母的 ASCII 码。 | |
LCASE(s)、LOWER(s) | 所有字母变成小写 | |
UCASE(s)、UPPER(s) | 将字符串转换为大写 | |
LTRIM(s) | 去掉开始处的空格 | |
RTRIM(s) | 去掉结尾处的空格 | |
TRIM(s) | 去掉字符串 s 开始和结尾处的空格 | |
FORMAT(x,n) | 数字格式化,保留n位小数。最后一位四舍五入。 | |
REVERSE(s) | 字符串倒序 | |
字符串查找 | ||
LEFT(s,n) | 返回字符串 s 的前 n 个字符 | |
RIGHT(s,n) | 返回字符串 s 的后 n 个字符 | |
FIELD(s,s1,s2…) | 返回第一个字符串 s 在字符串列表(s1,s2…)中的位置 | SELECT FIELD("c", "a", "b", "c", "d", "e"); |
FIND_IN_SET(s1,s2) | 返回字符串 c 在指定字符串中的位置 | |
LOCATE(s1,s) | 从字符串 s 中获取 s1 的开始位置 | |
POSITION(s1 IN s) | 从字符串 s 中获取 s1 的开始位置 | 返回字符串 abc 中 b 的位置:SELECT POSITION('b' in 'abc') -- 2 |
MID(s,n,len)、SUBSTRING(s,n,len)、SUBSTRING(s, start, length) | 从字符串 s 的 n 位置截取长度为 len 的子字符串 | |
SUBSTRING_INDEX(s, delimiter, number) | 返回从字符串 s 的第 number 个出现的分隔符 delimiter 之后的子串。 | 如果 number 是正数,返回第 number 个字符左边的字符串。 如果 number 是负数,返回第(number 的绝对值(从右边数)个字符右边的字符串。 |
字符串生成 | ||
SPACE(n) | 返回 n 个空格 | |
REPEAT(s,n) | 将字符串 s 重复 n 次 | |
合并 | ||
CONCAT(s1,s2…sn) | 合并多个字符串 | |
CONCAT_WS(x, s1,s2…sn) | 合并多个字符串,并添加分隔符 | |
替换 | ||
INSERT(s1,x,len,s2) | 从s1的第x位开始替换长度位len的字符为s2 | |
REPLACE(s,s1,s2) | 将字符串 s2 替代字符串 s 中的字符串 s1 | |
填充 | ||
LPAD(s1,len,s2) | 在 s1 的开始处填充字符串 s2,使字符串长度达到 len | SELECT LPAD('abc',5,'xx') -- xxabc |
RPAD(s1,len,s2) | 在字符串 s1 的结尾处添加字符串 s2,使字符串的长度达到 len |
MySQL 数字函数
函数名 | 描述 | 实例 |
---|---|---|
ABS(x) | 绝对值 | |
n DIV m,/ | 整除,n 为被除数,m 为除数 | 计算 10 除于 5:SELECT 10 DIV 5; -- 2 |
MOD(x,y),% | 返回 x 除以 y 以后的余数 | 5 除于 2 的余数:SELECT MOD(5,2) -- 1 |
幂次与根号 | ||
SQRT(x) | 返回x的平方根 | |
POW(x,y)、POWER(x,y) | 返回 x 的 y 次方 | 2 的 3 次方:SELECT POW(2,3) -- 8 |
EXP(x) | 返回 e 的 x 次方 | 计算 e 的三次方:SELECT EXP(3) -- 20.085536923188 |
LN | 返回数字的自然对数,以 e 为底。 | |
LOG(x) 或 LOG(base, x) | 返回自然对数(以 e 为底的对数),如果带有 base 参数,则 base 为指定带底数。 | SELECT LOG(20.085536923188) -- 3 SELECT LOG(2, 4); -- 2 |
LOG10(x) | 返回以 10 为底的对数 | SELECT LOG10(100) -- 2 |
LOG2(x) | 返回以 2 为底的对数 | 返回以 2 为底 6 的对数:SELECT LOG2(6); -- 2.584962500721156 |
随机数 | ||
RAND() | 返回 0 到 1 的随机数 | SELECT RAND() --0.93099315644334 |
符号判定 | ||
SIGN(x) | 返回 x 的符号,x 是负数、0、正数分别返回 -1、0 和 1 | SELECT SIGN(-10) -- (-1) |
三角函数 | 以下X为弧度值 | |
ACOS(x) | 求 x 的反余弦值(单位为弧度) | |
ASIN(x) | 求反正弦值(单位为弧度) | |
ATAN(x) | 求反正切值(单位为弧度) | |
ATAN2(n, m) | 求反正切值(单位为弧度) | SELECT ATAN2(-0.8, 2); |
COS(x) | 求余弦值(参数是弧度) | |
COT(x) | 求余切值(参数是弧度) | |
SIN(x) | 求正弦值(参数是弧度) | SELECT SIN(RADIANS(30)) -- 0.5 |
TAN(x) | 求正切值(参数是弧度) | |
DEGREES(x) | 将弧度转换为角度 | SELECT DEGREES(3.1415926535898) -- 180 |
RADIANS(x) | 将角度转换为弧度 | |
取整 | ||
CEIL(x) | 返回大于或等于 x 的最小整数 | SELECT CEIL(1.5) -- 返回2 |
CEILING(x) | 返回大于或等于 x 的最小整数 | SELECT CEILING(1.5); -- 返回2 |
FLOOR(x) | 返回小于或等于 x 的最大整数 | SELECT FLOOR(1.5) -- 返回1 |
ROUND(x [,y]) | 返回x四舍五入的值,可选参数 y 表示要保留的小数位数, | ROUND(345.156, 2) -- 345.16 |
TRUNCATE(x,y) | 返回数值 x 保留到小数点后 y 位的值,直接舍弃其余小数。不会进行四舍五入 | SELECT TRUNCATE(1.23456,3) -- 1.234 |
聚合函数 | ||
AVG(expression) | 返回一个表达式的平均值,expression 是一个字段 | |
COUNT(expression) | 返回查询的记录总条数 | |
SUM(expression) | 返回指定字段的总和 | |
GREATEST(expr1, expr2, expr3, …) | 返回列表中的最大值 | SELECT GREATEST("Google", "Runoob", "Apple"); -- Runoob |
LEAST(expr1, expr2, expr3, …) | 返回列表中的最小值 | SELECT LEAST("Google", "Runoob", "Apple"); -- Apple |
MAX(expression) | 返回字段 expression 中的最大值 | 返回数据表 Products 中字段 Price 的最大值:SELECT MAX(Price) AS LargestPrice FROM Products; |
MIN(expression) | 返回字段 expression 中的最小值 | 返回数据表 Products 中字段 Price 的最小值:SELECT MIN(Price) AS MinPrice FROM Products; |
常量 | ||
PI() | 返回圆周率(3.141593) | SELECT PI() --3.141593 |
MySQL 日期函数
以下,
- t:表示时间参数,时分秒
- d:表示日期参数,年月日
- data:表示完整的日期时间,
函数名 | 描述 | 实例 |
---|---|---|
获取时间 | ||
CURDATE()、CURRENT_DATE() | 返回当前日期 | SELECT CURDATE(); -> 2018-09-19 |
CURTIME()、CURRENT_TIME() | 返回当前时间 | SELECT CURRENT_TIME(); -> 19:59:02 |
CURRENT_TIMESTAMP()、LOCALTIME()、LOCALTIMESTAMP()、NOW()、SYSDATE() | 返回当前日期和时间 | SELECT CURRENT_TIMESTAMP() -> 2018-09-19 20:57:43 |
LAST_DAY(d) | 返回给给定日期的那一月份的最后一天 | SELECT LAST_DAY("2017-06-20"); -> 2017-06-30 |
TIMESTAMP(expression, interval) | 单个参数时,函数返回日期或日期时间表达式;有2个参数时,将参数加和 | |
提取时间 | 从一个时间表达式中提取需要的信息。 | |
DATE() | 从日期或日期时间表达式中提取日期值 | SELECT DATE("2017-06-15"); -> 2017-06-15 |
DAY(d) | 返回日期值 d 的日期部分 | SELECT DAY("2017-06-15"); -> 15 |
YEAR(d) | 返回年份 | SELECT YEAR("2017-06-15"); -> 2017 |
MONTH(d) | 返回日期d中的月份值 | SELECT MONTH('2011-11-11 11:11:11') ->11 |
HOUR(t) | 返回 t 中的小时值 | `SELECT HOUR(‘1:2:3’) -> 1 |
MINUTE(t) | 返回 t 中的分钟值 | SELECT MINUTE('1:2:3') -> 2 |
SECOND(t) | 返回 t 中的秒钟值 | SELECT SECOND('1:2:3') -> 3 |
MICROSECOND(date) | 返回日期参数中的微秒数 | SELECT MICROSECOND("2017-06-20 09:34:00.000023"); -> 23 |
TIME(expression) | 提取传入表达式的时间部分 | SELECT TIME("19:30:10"); -> 19:30:10 |
时间范围计数 | 计算给定时间在某一个范围中属于第几 | |
DAYOFMONTH(d) | 计算日期 d 是本月的第几天 | SELECT DAYOFMONTH('2011-11-11 11:11:11') ->11 |
MAKEDATE(year, day-of-year) | 基于年份 year 和天数序号返回一个日期 | SELECT MAKEDATE(2017, 3); -> 2017-01-03 |
DAYOFYEAR(d) | 计算日期 d 是本年的第几天 | SELECT DAYOFYEAR('2011-11-11 11:11:11') ->315 |
WEEKDAY(d) | 日期 d 是星期几,0 表示星期一,1 表示星期二 | `SELECT WEEKDAY(“2017-06-15”); -> 3 |
DAYOFWEEK(d) | 日期 d 是星期几,数字表示,1-7 | SELECT DAYOFWEEK('2011-11-11 11:11:11') ->6 |
DAYNAME(d) | 返回日期 d 是星期几,英文表示 | SELECT DAYNAME('2011-11-11 11:11:11') ->Friday |
MONTHNAME(d) | 返回日期当中的月份名称,如 November | SELECT MONTHNAME('2011-11-11 11:11:11') -> November |
WEEKOFYEAR(d)、WEEK(d) | 计算日期 d 是本年的第几个星期, 0 到 53 | SELECT WEEKOFYEAR('2011-11-11 11:11:11') -> 45 |
TO_DAYS(d) | 计算日期 d 距离 0000 年 1 月 1 日的天数 | SELECT TO_DAYS('0001-01-01 01:01:01') -> 366 |
FROM_DAYS(n) | 计算从 0000 年 1 月 1 日开始 n 天后的日期 | SELECT FROM_DAYS(1111) -> 0003-01-16 |
YEARWEEK(date, mode) | 返回年份及第几周,mode 中 0-6表一周 | SELECT YEARWEEK("2017-06-15"); -> 201724 |
QUARTER(d) | 返回日期d是第几季节,返回 1 到 4 | SELECT QUARTER('2011-11-11 11:11:11') -> 4 |
EXTRACT(type FROM d) | 从日期 d 中获取指定的值,type 指定返回的值,可以为hour,year,month. | SELECT EXTRACT(MINUTE FROM '2011-11-11 11:11:11') -> 11 |
时间表达格式化 | ||
DATE_FORMAT(d,f) | 按表达式 f的要求显示日期 d | SELECT DATE_FORMAT('2011-11-11 11:11:11','%Y-%m-%d %r') -> 2011-11-11 11:11:11 AM |
SEC_TO_TIME(s) | 将以秒为单位的时间 s 转换为时分秒的格式 | SELECT SEC_TO_TIME(4320) -> 01:12:00 |
TIME_TO_SEC(t) | 将时间 t 转换为秒 | SELECT TIME_TO_SEC('1:12:00') -> 4320 |
STR_TO_DATE(string, format_mask) | 将字符串转变为日期 | SELECT STR_TO_DATE("August 10 2017", "%M %d %Y"); -> 2017-08-10 |
MAKETIME(hour, minute, second) | 组合时间,参数分别为小时、分钟、秒 | SELECT MAKETIME(11, 35, 4); -> 11:35:04 |
TIME_FORMAT(t,f) | 按表达式 f 的要求显示时间 t | SELECT TIME_FORMAT('11:11:11','%r') 11:11:11 AM |
时间计算 | ||
DATEDIFF(d1,d2) | 计算日期 d1->d2 之间相隔的天数 | SELECT DATEDIFF('2001-01-01','2001-02-02') -> -32 |
SUBDATE(d,n) | 日期 d 减去 n 天后的日期 | SELECT SUBDATE('2011-11-11 11:11:11', 1) ->2011-11-10 11:11:11 (默认是天) |
SUBTIME(t,n) | 时间 t 减去 n 秒的时间 | SELECT SUBTIME('2011-11-11 11:11:11', 5) ->2011-11-11 11:11:06 (秒) |
ADDDATE(d,n) | 计算起始日期 d 加上 n 天的日期 | SELECT ADDDATE("2017-06-15", INTERVAL 10 DAY); ->2017-06-25 |
ADDTIME(t,n) | n 是一个时间表达式,时间 t 加上时间表达式 n | 添加 2 小时, 10 分钟, 5 秒:SELECT ADDTIME("2020-06-15 09:34:21", "2:10:5"); -> 2020-06-15 11:44:26 |
DATE_ADD(d,INTERVAL expr type) | 计算起始日期 d 加上一个时间段后的日期, | 见下例,基本相似。 |
DATE_SUB(date,INTERVAL expr type) | 函数从日期减去指定的时间间隔。 | OrderDate 字段减去 2 天:SELECT OrderId,DATE_SUB(OrderDate,INTERVAL 2 DAY) AS PayDate FROM Orders |
TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) | 计算时间差,返回 datetime_expr2 − datetime_expr1 的时间差。unit可以用day,month,year,minute等 | SELECT TIMESTAMPDIFF(DAY,'2003-02-01','2003-05-01'); // 计算两个时间相隔多少天 -> 89 |
TIMEDIFF(time1, time2) | 计算时间差值,计算结果按照两个时间中的最高精度返回。 | SELECT TIMEDIFF(‘2000:01:01 00:00:00’, ‘2000:01:01 00:00:00.000001’); -> ‘-00:00:00.000001’ |
PERIOD_ADD(period, number) | 为 年-月 组合日期添加一个时段 | SELECT PERIOD_ADD(201703, 5); -> 201708 |
PERIOD_DIFF(period1, period2) | 返回两个时段之间的月份差值 | SELECT PERIOD_DIFF(201710, 201703); -> 7 |
MySQL 高级函数
函数名 | 描述 | 实例 |
---|---|---|
格式转化 | ||
BIN(x) | 返回 x 的二进制编码,x 为十进制数 | 15 的 2 进制编码:SELECT BIN(15); -- 1111 |
BINARY(s) | 将字符串 s 转换为二进制字符串 | SELECT BINARY "RUNOOB"; -> RUNOOB |
CAST(x AS type) | 转换数据类型 | 字符串日期转换为日期:SELECT CAST("2017-08-29" AS DATE); -> 2017-08-29 |
CONV(x,f1,f2) | 返回 f1 进制数变成 f2 进制数 | SELECT CONV(15, 10, 2); -> 1111 |
CONVERT(s USING cs) | 函数将字符串 s 的字符集变成 cs | SELECT CHARSET('ABC') ->utf-8 SELECT CHARSET(CONVERT('ABC' USING gbk)) ->gbk |
信息读取 | ||
COALESCE(expr1, expr2, …, expr_n) | 返回参数中的第一个非空表达式(从左向右) | SELECT COALESCE(NULL, NULL, NULL, 'runoob.com', NULL, 'google.com'); -> runoob.com |
CONNECTION_ID() | 返回唯一的连接 ID | SELECT CONNECTION_ID(); -> 4292835 |
LAST_INSERT_ID() | 返回最近生成的 AUTO_INCREMENT 值 | SELECT LAST_INSERT_ID(); ->6 |
CURRENT_USER()、SESSION_USER()、USER()、SYSTEM_USER() | 返回当前用户 | SELECT CURRENT_USER(); -> guest@% |
DATABASE() | 返回当前数据库名 | SELECT DATABASE(); -> runoob |
VERSION() | 返回数据库的版本号 | SELECT VERSION() -> 5.6.34 |
条件判断与null值处理 | ||
IF(expr,v1,v2) | 如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2。 | SELECT IF(1 > 0,'正确','错误') ->正确 |
IFNULL(v1,v2) | 如果 v1 的值不为 NULL,则返回 v1,否则返回 v2。 | SELECT IFNULL(null,'Hello Word') ->Hello Word |
ISNULL(expression) | 判断表达式是否为 NULL | SELECT ISNULL(NULL); ->1 |
NULLIF(expr1, expr2) | 比较两个字符串,如果字符串 expr1 与 expr2 相等 返回 NULL,否则返回 expr1 | SELECT NULLIF(25, 25); -> |
以下是 MySQL 8.0 版本新增的一些常用函数:
函数 | 描述 | 实例 |
---|---|---|
JSON_OBJECT() | 将键值对转换为 JSON 对象 | SELECT JSON_OBJECT('key1', 'value1', 'key2', 'value2') |
JSON_ARRAY() | 将值转换为 JSON 数组 | SELECT JSON_ARRAY(1, 2, 'three') |
JSON_EXTRACT() | 从 JSON 字符串中提取指定的值 | SELECT JSON_EXTRACT('{"name": "John", "age": 30}', '$.name') |
JSON_CONTAINS() | 检查一个 JSON 字符串是否包含指定的值 | SELECT JSON_CONTAINS('{"name": "John", "age": 30}', 'John', '$.name') |
排序函数 | 需要和over一起使用。详见[over](# -窗口函数 - over) | |
ROW_NUMBER() | 为查询结果中的每一行分配一个唯一的数字 | SELECT ROW_NUMBER() OVER(ORDER BY id) AS row_number, name FROM users |
RANK() | 为查询结果中的每一行分配一个排名 | SELECT RANK() OVER(ORDER BY score DESC) AS rank, name, score FROM students |
2补充
delete,drop,truncate-删除表
delete,drop,truncate 都有删除表的作用,区别在于:
- 1、delete 和 truncate 仅仅删除表数据,drop 连表数据和表结构一起删除,
- 2、delete 是 DML 语句,操作完以后如果没有不想提交事务还可以回滚,truncate 和 drop 是 DDL 语句,操作完马上生效,不能回滚,
- 3、执行的速度上,drop>truncate>delete
null值处理
NULL 用于表示缺失的或未知的数据
MySQL提供了三大运算符:
- IS NULL: 当列的值是 NULL,此运算符返回 true。
- IS NOT NULL: 当列的值不为 NULL, 运算符返回 true。
- <=>: 比较操作符(不同于 = 运算符),当比较的的两个值相等或者都为 NULL 时返回 true。
不能使用 = NULL 或 != NULL 在列中查找 NULL 值 。
- 在 MySQL 中,NULL 值与任何其它值的比较(即使是 NULL)永远返回 NULL,即 NULL = NULL 返回 NULL 。
还有函数:ifnull()、isnull()、coalesce()、nvl(),四者功能一样,但适用于不同数据库
-
ifnull():如果表达式为null,则返回替代值,适用于mysql
-
IFNULL(UnitsOnOrder, 0)
-
-
isnull():适用于sql service
-
coalesce():适用于mysql和sql service
-
nvl():只适用于oracle
MySQL 中处理 NULL 值的常见注意事项和技巧
- 检查是否为 NULL:
SELECT * FROM employees WHERE department_id IS NULL;
SELECT * FROM employees WHERE department_id IS NOT NULL;
- 使用 COALESCE 函数处理 NULL:
COALESCE 函数接受多个参数,返回参数列表中的第一个非 NULL 值:
SELECT product_name, COALESCE(stock_quantity, 0) AS actual_quantity
FROM products;
- 如果 stock_quantity 列为 NULL,则 COALESCE 将返回 0。
- NULL 排序:
在使用 ORDER BY 子句进行排序时,NULL 值默认会被放在排序的最后。
-
如果希望将 NULL 值放在最前面,可以使用 ORDER BY column_name ASC NULLS FIRST,
-
反之使用 ORDER BY column_name DESC NULLS LAST。
SELECT product_name, price FROM products ORDER BY price ASC NULLS FIRST;
- 使用 <=> 操作符进行 NULL 比较:
<=> 操作符是 MySQL 中用于比较两个表达式是否相等的特殊操作符,对于 NULL 值的比较也会返回 TRUE。
SELECT * FROM employees WHERE commission <=> NULL;
- 注意聚合函数对 NULL 的处理:
- count
- count(*)时,输出的是所有记录行数,包括列全为null的行。
- count具体某个字段时,会统计空字符而不会统计null。
- sum
- null和空字符不会对sum产生影响,可以视为忽略null值
- avg
- avg(value)可以视为sum(value)/count(value),
- 也就是说对某个字段使用avg时,其处理空值和空字符时方式是和count一样的,
- 即忽略null不忽略空字符。
重复值处理
防止出现重复值 - key,unique - 唯一性约束
数据表中设置指定的字段为 PRIMARY KEY(主键) 或者 UNIQUE(唯一) 索引来保证数据的唯一性。
-
如果你设置了双主键,那么那个键的默认值不能为 NULL,可设置为 NOT NULL。
-
如果我们设置了唯一索引,那么在插入重复数据时,SQL 语句将无法执行成功,并抛出错。
防止插入重复值 - insert ignore into,insert replace into
- INSERT IGNORE INTO :会忽略插入数据中,与数据库内重复的数据
- 如果数据库没有相同数据,就插入;如果有相同数据,就跳过
- 这样就可以保留数据库中已经存在数据,达到在间隙中插入数据的目的。
- 在数据库中存在唯一性约束的时候,如果插入重复数据:
- IGNORE INTO:将不返回错误,只以警告形式返回。
- REPLACE INTO :则先删除掉原来的记录。再插入新记录。
过滤重复值 - distinct,group by
详见[distinct](# 消除重复 - distinct)
实例:
SELECT DISTINCT last_name, first_name FROM person_tbl;
SELECT last_name, first_name FROM person_tbl GROUP BY (last_name, first_name);
删除重复值
方法一:先通过过滤重复值的方法,创建新的数据表,再删除原来的数据表。
CREATE TABLE tmp SELECT last_name, first_name, sex FROM person_tbl GROUP BY (last_name, first_name, sex)
DROP TABLE person_tbl;
ALTER TABLE tmp RENAME TO person_tbl;
方法二:向表中添加主键,此时会自动删除重复。但是此方法灵活性不强。
ALTER IGNORE TABLE person_tbl ADD PRIMARY KEY (last_name, first_name);
索引与主键???
sql注入
这里只做大致介绍。
这是一种利用网站对用户输入的疏忽处理而攻击数据库的方法
MySQL 注入是指攻击者通过恶意构造的输入,成功地执行恶意的 SQL 查询,这通常发生在用户输入未经适当验证或转义的情况下,攻击者试图在输入中插入 SQL 代码,以执行意外的查询或破坏数据库。
例如:
# 这是一个用户登录系统中的身份验证。
SELECT * FROM users WHERE username = 'input_username' AND password = 'input_password';
# 如果输入' OR '1'='1'; -- 这样的用户名
SELECT * FROM users WHERE username = '' OR '1'='1'; --' AND password = 'input_password';
# 这就变成了查询返回所有用户,因为 1=1 总是为真,注释符号 -- 用于注释掉原始查询的其余部分,以确保语法正确。
常用数据库操作技巧
行列转换
行转列
将一行中的数据转化为多行的数据。
一般使用select加union,通过将多次查询的结果合并来实现。
列转行
将一列中的数据转化为多行来显示。
一般可以使用 条件加group by的方式来整合。
- 条件可以是带条件的函数,when-case语句等。