一、简介
MySQL 是最流行的关系型数据库管理系统之一, 在 Web 应用方面,MySQL 是最好的 RDBMS (Relational Database Management System) 关系数据库管理系统应用软件。
二、主要特性:
速度:运行速度快。
价格: MySQL 对多数个人用户来说是免费的。
容易使用:与其他大型数据库的设置和管理相比,其复杂程度较低,易于学习。
可移植性:能够工作在众多不同的系统平台.上,例如 Windows、Linux、 UNIX、Mac OS 等。
丰富的接口:提供了用于 C、C++、Eiffel、 Java、 Perl、 PHP、Python、 Ruby 和 Tcl 的 API。
支持查询语言:MySQL 可以利用标准 SQL 语法编写支持 ODBC (开放式数据库连接)的应用程序。
安全性和连接性:十分灵活和安全的权限和密码系统,允许基于主机的验证。当连接到服务器时,所有的密码传输均采用加密形式。
三、常用命令
数据库操作语句:
1.显示数据库:
SHOW DATABASES;
SHOW DATABASES [LIKE '数据库名'];
2.显示数据库创建语句 :
SHOW CREATE DATABASE DBNAME
3.创建数据库:
CREATE DATABASE [IF NOT EXISTS] <数据库名>
[[DEFAULT] CHARACTER SET <字符集名>]
[[DEFAULT] COLLATE <校对规则名>];
例:
mysql> CREATE DATABASE IF NOT EXISTS test_db_char -> DEFAULT CHARACTER SET utf8 -> DEFAULT COLLATE utf8_chinese_ci;
4.展示该db的所有表:
SHOW TABLES
5.查看以film_开头的表:
SHOW TABLES LIKE ‘film_%’
6.使用数据库 :
USE DBNAME
7.删除数据库:
DROP DATABASE [IF EXISTS] DBNAME
8.修改数据库:
ALTER DATABASE [数据库名] {
[ DEFAULT ] CHARACTER SET <字符集名> |
[ DEFAULT ] COLLATE <校对规则名>};
例: mysql> ALTER DATABASE test_db -> DEFAULT CHARACTER SET gb2312 -> DEFAULT COLLATE gb2312_chinese_ci;
数据表的基本操作语句:
1.查询表结构:
DESC TABLENAME 或 DESC DATABASES. TABLENAME
2.查看建表语句:
SHOW CREATE TABLE TABLENAME
3.创建表:
CREATE TABLE <表名> ([表定义选项])[表选项][分区选项];
#[表定义选项]的格式为:<列名1> <类型1> [,…] <列名n> <类型n>
mysql> USE test_db;
Database changed
mysql> CREATE TABLE tb_emp1
-> (
-> id INT(11),
-> name VARCHAR(25),
-> deptId INT(11),
-> salary FLOAT
-> );
Query OK, 0 rows affected (0.37 sec)
CREATE TABLE tb_emp4
(
id INT(11) PRIMARY KEY,
name VARCHAR(22),
location VARCHAR (50)
);
4.修改数据表:
ALTER TABLE <表名> [修改选项];
/*
修改选项的语法格式如下:
{ ADD COLUMN <列名> <类型>
| CHANGE COLUMN <旧列名> <新列名> <新列类型>
| ALTER COLUMN <列名> { SET DEFAULT <默认值> | DROP DEFAULT }
| MODIFY COLUMN <列名> <类型>
| DROP COLUMN <列名>
| RENAME TO <新表名>
| CHARACTER SET <字符集名>
| COLLATE <校对规则名> }
*/
新增列到db:
alter table [table name] add column [new column name] varchar (20);
更改列名:
alter table [table name] change [old column name] [new column name] varchar (50);
5.数据表添加字段:
MySQL数据表是由行和列构成的,通常把表的“列”称为字段(Field),把表的“行”称为记录(Record)。
MySQL 允许在开头、中间和结尾处添加字段。
#在末尾添加字段
ALTER TABLE <表名> ADD <新字段名><数据类型>[约束条件];
#在开头添加字段
ALTER TABLE <表名> ADD <新字段名> <数据类型> [约束条件] FIRST;
#在中间添加字段
ALTER TABLE <表名> ADD <新字段名> <数据类型> [约束条件] AFTER <已经存在的字段名>;
ALTER TABLE student ADD age INT(4);
ALTER TABLE student ADD stuId INT(4) FIRST;
ALTER TABLE student ADD stuno INT(11) AFTER name;
6.删除数据表:
DROP TABLE [IF EXISTS] 表名1 [ ,表名2, 表名3 ...];
7.删除被其他表关联的表:
数据表之间经常存在外键关联的情况,这时如果直接删除父表,会破坏数据表的完整性,也会删除失败。
删除父表有以下两种方法:
- 先删除与它关联的子表,再删除父表;但是这样会同时删除两个表中的数据。
- 将关联表的外键约束取消,再删除父表;适用于需要保留子表的数据,只删除父表的情况。
#在数据库中创建两个关联表。创建表 tb_emp4 的 SQL 语句如下:
CREATE TABLE tb_emp4
(
id INT(11) PRIMARY KEY,
name VARCHAR(22),
location VARCHAR (50)
);
#接下来创建表 tb_emp5,SQL 语句如下:
CREATE TABLE tb_emp5
(
id INT(11) PRIMARY KEY,
name VARCHAR(25),
deptId INT(11),
salary FLOAT,
CONSTRAINT fk_emp4_emp5 FOREIGN KEY (deptId) REFERENCES tb_emp4(id)
);
#解除子表 tb_emp5 的外键约束,SQL语句如下:
ALTER TABLE tb_emp5 DROP FOREIGN KEY fk_emp4_emp5;
#解除关联关系后,可以使用 DROP TABLE 语句直接删除父表 tb_emp4,SQL 语句如下:
DROP TABLE tb_emp4;
表数据的操作语句:
1.INSERT语句:
注意:
a.插入数据应该与字段的数据类型相同;
b.数据的大小应该在列的规定范围内,如:不能将一个长度为80的字符串加入到长度为40的列中;
c.values中列出的数据位置必须与被加入的列的排列位置相对应;
d.字符和日期函数应包含在单引号中;
1.1无字段名,values值的顺序须与字段在表中顺序一致
INSERT INTO TABLENAME VALUES(val1,val2,....)
1.2值顺序、类型须与对应的字段相匹配
INSERT INTO TABLENAME (field1,field2,...) VALUES(val1,val2,...)
1.3批量插入
INSERT INTO TABLENAME (field1,field2,...) VALUES(val11,val12,...),(val21,val22,...)
2.SELECT语句
SELECT
{* | <字段列名>}
[
FROM <表 1>, <表 2>…
[WHERE <表达式>
[GROUP BY <group by definition>
[HAVING <expression> [{<operator> <expression>}…]]
[ORDER BY <order by definition>]
[LIMIT[<offset>,] <row count>]
]
注意:
a.指定查询那些列,指定列名查询
b.*代表查询所有列
c.FROM指定查询哪张表
d.DISTINCT可选,选择是否剔除重复数据
2.1 查看表内容
SELECT *FROM film
2.2选所有字段,特定条件查询
SELECT *FROM film WHERE film_id<5;
2.3使用值“where”过滤显示选定的某些行。
SELECT * FROM [table name] WHERE [field name] = "whatever";
2.4显示所有包含name为”Bob”和phone number为“3444444”的记录。
SELECT * FROM [table name] WHERE name = "Bob" AND phone_number = '3444444';
2.5使用like匹配。
显示所有的name以字母“bob”开头和phone number为“3444444”的记录。
SELECT * FROM [table name] WHERE name like "Bob%" AND phone_number = '3444444';
SELECT *FROM film WHERE title LIKE '%RRO%' -- 包含RRO的内容 , not like '%RRO%' 不包含RRO的内容
SELECT *FROM film WHERE title LIKE '%ARK' -- 以ARK结尾的内容
SELECT *FROM film WHERE title LIKE 'ZORRO%' -- 以ZORRO开头的内容
SELECT * FROM film WHERE title LIKE 'ZORRO%K' -- 检索以ZORRO开头以K结尾的内容
2.6查询指定的几条记录。
显示name以字母“bob”开头和phone number为“3444444”的第1至第5条记录。
SELECT * FROM [table name] WHERE name like "Bob%" AND phone_number = '3444444' limit 1,5;
2.7查询从第2行开始后数5行
LIMIT 初始位置,记录数
SELECT *FROM film ORDER BY film_id DESC LIMIT 1,5;
2.8使用正则表达式查找记录。
使用“正则表达式二进制”强制区分大小写。此命令查找以a开头的任何记录。
SELECT * FROM [table name] WHERE rec RLIKE "^a";
2.9以升序或降序显示选定的记录。默认按升序,降序用desc
SELECT [col1],[col2] FROM [table name] ORDER BY [col2] DESC;
2.10返回唯一不同的记录。
SELECT DISTINCT [column name] FROM [table name];
2.11统计指定列的数量。
SELECT COUNT(*) FROM [table name];
SELECT COUNT(NAME) FROM dt_areaconfig;
2.12统计指定列值的总和。
SELECT SUM(*) FROM [table name];
2.13求平均值
2.14求最大值/最小值
SELECT MAX(field1) AS MAXVAL FROM table1;
SELECT MIN(field1) AS MAXVAL FROM table1;
2.15 在某范围内
SELECT *FROM film WHERE last_update BETWEEN "2022-01-01 10:21:01" AND "2022-05-11 16:35:58"
2.16查询表里数据是否有重复。
例:查询tb_dt_area_config表里name,code两列的值是否有重复
SELECT * FROM tb_dt_area_config WHERE (CODE,NAME) IN(SELECT CODE,NAME FROM tb_dt_area_config GROUP BY CODE,NAME HAVING COUNT(*)>1);
2.17查询在A表但不在B表的数据。
例:查询新增产品类型数据在digital_inspection_device.tb_dt_product_for_sealer表但不在digital_inspection_device.tb_product_type表
SELECT * FROM tb_dt_product_for_sealer WHERE NAME NOT IN (SELECT tb_product_type.NAME FROM tb_product_type WHERE tb_dt_product_for_sealer.NAME=tb_product_type.NAME);
2.18 空值查询
#语法:IS [NOT] NULL
mysql> SELECT `name`,`login_date` FROM tb_students_info
-> WHERE login_date IS NULL;
2.19 分组查询
单独使用 GROUP BY 关键字时,查询结果会只显示每个分组的第一条记录。
mysql> SELECT `name`,`sex` FROM tb_students_info
-> GROUP BY sex;
+-------+------+
| name | sex |
+-------+------+
| Henry | 女 |
| Dany | 男 |
+-------+------+
2 rows in set (0.01 sec)
结果中只显示了两条记录,这两条记录的 sex 字段的值分别为“女”和“男”。
GROUP BY 关键字可以和 GROUP_CONCAT() 函数一起使用。GROUP_CONCAT() 函数会把每个分组的字段值都显示出来。
mysql> SELECT `sex`, GROUP_CONCAT(name) FROM tb_students_info
-> GROUP BY sex;
+------+----------------------------+
| sex | GROUP_CONCAT(name) |
+------+----------------------------+
| 女 | Henry,Jim,John,Thomas,Tom |
| 男 | Dany,Green,Jane,Lily,Susan |
+------+----------------------------+
2 rows in set (0.00 sec)
由结果可以看到,查询结果分为两组,sex 字段值为“女”的是一组,值为“男”的是一组,且每组的学生姓名都显示出来了。
在数据统计时,GROUP BY 关键字经常和聚合函数一起使用。
聚合函数包括 COUNT(),SUM(),AVG(),MAX() 和 MIN()。
mysql> SELECT sex,COUNT(sex) FROM tb_students_info
-> GROUP BY sex;
+------+------------+
| sex | COUNT(sex) |
+------+------------+
| 女 | 5 |
| 男 | 5 |
+------+------------+
2 rows in set (0.00 sec)
WITH POLLUP 关键字用来在所有记录的最后加上一条记录,这条记录是上面所有记录的总和,即统计记录数量。
mysql> SELECT sex,GROUP_CONCAT(name) FROM tb_students_info
->GROUP BY sex WITH ROLLUP;
+------+------------------------------------------------------+
| sex | GROUP_CONCAT(name) |
+------+------------------------------------------------------+
| 女 | Henry,Jim,John,Thomas,Tom |
| 男 | Dany,Green,Jane,Lily,Susan |
| NULL | Henry,Jim,John,Thomas,Tom,Dany,Green,Jane,Lily,Susan |
+------+------------------------------------------------------+
3 rows in set (0.00 sec)
2.20 过滤分组
HAVING <查询条件>
HAVING 关键字和 WHERE 关键字都可以用来过滤数据,且 HAVING 支持 WHERE 关键字中所有的操作符和语法。
但是 WHERE 和 HAVING 关键字也存在以下几点差异:
- 一般情况下,WHERE 用于过滤数据行,而 HAVING 用于过滤分组。
- WHERE 查询条件中不可以使用聚合函数,而 HAVING 查询条件中可以使用聚合函数。
- WHERE 在数据分组前进行过滤,而 HAVING 在数据分组后进行过滤 。
- WHERE 针对数据库文件进行过滤,而 HAVING 针对查询结果进行过滤。也就是说,WHERE 根据数据表中的字段直接进行过滤,而 HAVING 是根据前面已经查询出的字段进行过滤。
- WHERE 查询条件中不可以使用字段别名,而 HAVING 查询条件中可以使用字段别名。
#查询出分组后平均身高大于 170 的学生姓名、性别和身高
mysql> SELECT GROUP_CONCAT(name),sex,height FROM tb_students_info
-> GROUP BY height
-> HAVING AVG(height)>170;
+--------------------+------+--------+
| GROUP_CONCAT(name) | sex | height |
+--------------------+------+--------+
| John | 女 | 172 |
| Jim | 女 | 175 |
| Thomas | 女 | 178 |
| Henry | 女 | 185 |
+--------------------+------+--------+
4 rows in set (0.00 sec)
3.更新已存在表的数据。
UPDATE [table name] SET Select_priv = 'Y',Insert_priv = 'Y',Update_priv = 'Y' where [field name] = 'user';
4.DELETE语句:
注意:
a.不用WHERE子句,将删除所有语句
b.使用DELETE语句仅删除表中的记录,不删除表本身
清空表中全部数据
DELETE FROM TABLENAME;
删除表中[field name] = ‘whatever’的行。
DELETE from [table name] where [field name] = 'whatever';
5.UPDATE语句:
注意:
a.Update语法可以用新值更新原有表行中的各列
b.SET语句指示要修改那些列和给予哪些值
c.WHERE子句指定更新那些行。若无WHERE子句,则更新所有行
UPDATE film SET release_year=2008,language_id=3 where film_id=3;
6.TRUNCATE 清空表记录
TRUNCATE [TABLE] 表名
- DELETE 是逐行一条一条删除记录的;TRUNCATE 则是直接删除原来的表,再重新创建一个一模一样的新表
- DELETE 删除数据后,配合事件回滚可以找回数据;TRUNCATE 不支持事务的回滚,数据删除后无法找回。
7.CASE关键字
SELECT file_id,title,description,language_id,
CASE
WHEN language_id=1 THEN 'English'
WHEN language_id=2 THEN 'Italian'
END
AS '语言分类'
FROM film WHERE file_id<5;
8.IF关键字
SELECT file_id,title,description,language_id,
(CASE language_id WHEN 1 THEN 'English' WHEN 2 THEN 'Italian' ELSE 'Other' END)
AS '语言分类'
FROM film WHERE file_id<5;
9.存储引擎
查看数据库的默认存储引擎:
SHOW VARIABLES LIKE 'default_storage_engine%';
修改数据库的默认存储引擎:
SET default_storage_engine=< 存储引擎名 >
修改数据表的存储引擎:
ALTER TABLE <表名> ENGINE=<存储引擎名>;
ALTER TABLE student ENGINE=MyISAM;
四、联表查询
1概念:
在SQL标准中规划的(Join)联结大致分为下面四种:
1.内联结:将两个表中存在联结关系的字段符合联结关系的那些记录形成记录集的联结。
内连接查询使用关键字join或cross join 或 inner join, 然后通过on连接表与表之间的条件
语法:
SELECT 字段,字段1,..
FROM table_name1
INNER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
2.外联结:分为外左联结和外右联结。
左联结A、B表的意思就是将表A中的全部记录和 表B中联结的字段与表A的联结字段符合联结条件的那些记录 形成的记录集的联结,这里注意的是最后出来的记录集会包括表A的全部记录。
右联结A、B表的结果和左联结B、A的结果是一样的,也就是说:Select
A.
name
B.
name
From
A
Left
Join
B
On
A.id=B.id 和 Select
A.
name
B.
name
From
B
Right
Join
A
on
B.id=A.id的结果是一样的
内外联结的区别是内联结将去除所有不符合条件的记录,而外联结则保留其中部分。外左联结与外右联结的区别在于如果用A左联 结B则A中所有记录都会保留在结果中,此时B中只有符合联结条件的记录,而右联结相反。
左外连接使用关键字left join,然后通过on连接表与表之间的条件
注意:left join 会查询出left join左边的表所有的数据,即使右表没有匹配
语法:
SELECT 字段,字段1,...
FROM table_name1
LEFT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
右外连接使用关键字right join,然后通过on连接表与表之间的条件
注意: 即使左表中没有匹配,也从右表返回所有的行
语法:
SELECT 字段,字段1,....
FROM table_name1
RIGHT JOIN table_name2
ON table_name1.column_name=table_name2.column_name
3.全联结:将两个表中存在联结关系的字段的所有记录取出形成记录集的联结。
显示左表(TESTA表)的全部记录和右表(TESTB表)的全部记录,两个表中没有的数据显示为NULL。
语法:
SELECT 字段,字段1,....
FROM table_name1
FULL JOIN table_name2
ON table_name1.column_name=table_name2.column_name;
4.无联结:没有使用联结功能,也有自联结的说法。5..2 MySQL子查询:
子查询就是把一个查询嵌套在另一个查询中。
子查询可以包含普通select可以包括任何子句,比如:distinct,group by, order by,limit,join等
子查询先执行里面的SQL语句,再执行外面SQL语句;
子查询的效率比较低,一般建议使用join替换子查询;
子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表,然后再外层查询语句,可参考例3;
2.联表查询中用到的一些参数
1.USING (column_list):
其作用是为了方便书写联结的多对应关系,大部分情况下USING语句可以用ON语句来代替,如下面例子:
a LEFT JOIN b USING (c1,c2,c3),其作用相当于
a LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3
2.STRAIGHT_JOIN:
由于默认情况下MySQL在进行表的联结的时候会先读入左表,当使用了这个参数后MySQL将会先读入右表,这是个MySQL的内置优化参数,大家应该在特定情况下使用,譬如已经确认右表中的记录数量少,在筛选后能大大提高查询速度。
3. 联表查询举例
例1:
SELECT COUNT(1) FROM (SELECT IFNULL(tr.id, '') AS regionId,
IFNULL(tpt.id, '') AS productTypeId,
IFNULL(tp.sale_area, '') AS regionName,
IFNULL(tpt.name, '') AS productTypeName,
COUNT(1) total
FROM tb_product tp
INNER JOIN `tb_product_type` tpt ON tpt.id = tp.product_type_id
INNER JOIN `tb_region` tr ON tr.name = tp.sale_area
WHERE tp.create_time >= startTime
AND tp.create_time < endTime
GROUP BY regionId, productTypeId, regionName, productTypeName) AS temp;
例2-例6引用自 mysql数据库之联表查询 - 希希大队长 - 博客园 (cnblogs.com)
例2:查询所有的课程的名称以及对应的任课老师姓名
分析需求:我们需要用到course和teacher表:既需要得到课程名称又要拿到老师姓名,然后看表结构模型,我们可以知道course有外键字段teacher_id指向teacher表id,那么我们就可以用内连接inner join将两张表拼接起来然后取其字段course.cname和teacher.tname即可得到我们想要的数据,SQL语句如下:
SELECT cname,tname FROM teacher INNER JOIN course ON course.teacher_id = teacher.tid;
例3:查询平均成绩大于八十分的同学的姓名和平均成绩
需求分析:我们需要用到score表和shtudent表,既要拿到学生姓名又要拿到成绩,我们理所当然需要将这两个表联表或者做子连接,然后需求中需要用到平均数,那么我们应想到用聚合函数avg(),但使用聚合函数的前提是分组(不人为分组时默认整个表就是一个组) group by,下面我们来写sql语句:
首先在联表或子连接前可以通过score表分组得到student_id和平均成绩:
select student_id,avg(num) as avg_score from score group by student_id having avg(num) >80;
然后在以上虚拟表的基础上通过student_id拼接student表,取student.sname和avg_score即可
SELECT student.sname,k.avg_score FROM student
INNER JOIN ( SELECT student_id, avg( num ) AS avg_score FROM score GROUP BY student_id HAVING avg( num ) > 80 ) AS k ON k.student_id = student.sid;
例4:查询没有报李平老师课的学生姓名
需求分析:我们根据表结构得知我们需要用到student,score,course,teacher这4张表,直接得到没有报李平老师课程的学生比较困难,那么我们就反过来想,哪些是报了李平老师课程的,然后在学生表里剔除掉即可:
首先我们可以先得到李平老师教了哪几门课,用course和teacher联表:
select course.cid,course.cname from course inner join teacher on course.teacher_id = teacher.tid where teacher.tname = "李平老师";
根据表结构我们可以知道,course表和score表通过外键连接,那么我们就可以把上面得到的虚拟表和score表子查询,取字段score.student_id即可得到所有选了李平老师课程的学生id,然后根据student_id分组或去重就可以得到不重名的学生id选了李平老师课程的虚拟表:
select score.student_id from score where course_id in (
select course.cid from course inner join teacher on course.teacher_id = teacher.tid where teacher.tname = "李平老师"
) ;
然后将上面得到的虚拟表与student表做子连接的条件得到选了李平老师课程的学生姓名,然后我们not in即可得到需求
select sname from student where sid not in (
select score.student_id from score where course_id in (
select course.cid from course inner join teacher on course.teacher_id = teacher.tid where teacher.tname = "李平老师"
)
);
例5:查询挂科超过两门(包括两门)的学生姓名和班级
需求分析:这个需求和第四个需求类似,我们可以先拿到所有挂科的学生id,然后进行分组,筛选出挂科数大于等于2的一部分学生id,然后把取到的id作为student表的查询条件去取学生姓名即可,sql语句如下:
SELECT
caption,
k.sname
FROM
class
INNER JOIN (
SELECT
sname,
class_id
FROM
student
WHERE
sid IN ( SELECT student_id FROM score WHERE num < 60 GROUP BY student_id HAVING count( student_id ) >= 2 )
) k ON k.class_id = class.cid;
例6、找出同时选了李平老师所有课的学生班级和姓名
需求分析:需要用到班级和老师,那么5张表都要用到,我们还是套用前面的方法,先通过teacher表找到李平老师的id,通过这个id在course表里找到李平老师的课程表的id,然后拿这个id去score表里找选了李平老师课程的student_id,这时候我们要对student_id进行分组了,筛选出含2个以上的student_id,再通过得到的student_id去student_表里找到对应的姓名和class_id,然后将生成的虚拟表去和class表联表,取出class.cname和student.sname即是我们想要的数据,sql语句如下:
SELECT
class.caption,
n.sname
FROM
class
INNER JOIN (
SELECT
class_id,
sname
FROM
student
WHERE
sid IN (
SELECT
student_id
FROM
(
SELECT
student_id,
course_id
FROM
score
WHERE
course_id IN ( SELECT course.cid FROM teacher INNER JOIN course ON course.teacher_id = teacher.tid WHERE teacher.tid = 2 )
) AS k
GROUP BY
student_id
HAVING
count( student_id ) = 2
)
) AS n ON class.cid = n.class_id ORDER BY n.sname;
五、SQL函数:
日期函数
SELECT DATE_FORMAT(NOW(),'%m-%d-%Y') AS pd -- 05-11-2022
SELECT NOW() -- 当前时间 2022-05-11 16:50:00
SELECT CURRENT_DATE() -- 当前日期 2022-05-11
SELECT DATEDIFF('2008-12-30','2008-12-29') AS DiffDate -- 时间差 1
字符串函数
SELECT LOWER('Hello') -- hello
SELECT UPPER('Hello') -- HELLO
SELECT CONCAT('Hello','World') -- HelloWorld
SELECT LENGTH('Hello') -- 5
数学函数
SELECT ROUND(45.926,2) -- 45.93 按指定的位数对数值进行四舍五入
SELECT MOD(1600,300) -- 100 求余函数