MySQL数据库基本知识

一、数据库表的相关操作

1、什么是SQL语言

SQL是用于访问和处理数据的标准的计算机语言
SQL语句不区分大小写,但是字符串区分,语句必须以分号结尾
空白和换行没有限制,但是不能破坏语法
注释有两种:#或/*xxxxxxxxxxxx*/

(1)创建逻辑库

SHOW DATABASES;  查看所有逻辑库
CREATE DATABASE demo; 创建demo逻辑库
DROP DATABASE demo; 删除demo逻辑库

(2)创建数据表

创建数据表
CREATE TABLE 数据库(
列名1 数据类型[约束] [COMMENT 注释],
列名1 数据类型[约束] [COMMENT 注释],
......
)[COMMENT = 注释];

# 创建一个逻辑库并且使用它
CREATE
DATABASE test; USE test;
CREATE TABLE student( id INT UNSIGNED PRIMARY KEY, name VARCHAR(20) NOT NULL, sex CHAR(1) NOT NULL, birthday DATE NOT NULL, tel CHAR(11) NOT NULL, remark VARCHAR(200) ); INSERT INTO student VALUES(1,"李强","男","1995-09-18","12345678912","体育生")

(3)数据表的其他操作

SHOW tables; //打印出逻辑空间数据表的名字
DESC student; //查看数据表内的字段
SHOW CREATE TABLE student; //打印创建数据表时的SQL语句
DROP TABLE student; //删除数据表

2、不同的数据类型

(1)数字

 

 

 注意:

float double 会存在丢失精度

decimal 的数据类型是数字串(10,2) 10表示一共有几个字符,2表示精确到小数点后面几位【优先使用decimal保存精确的浮点数】

(2)字符串

 

 (3)日期类型

 3、修改数据表结构

(1)添加字段

ALTER TABLE 表名

ADD 列1 数据类型[约束] [COMMENT 注释],

ADD 列2 数据类型[约束] [COMMENT 注释],

......;

(2)修改字段类型和约束

ALTER Table 表名称

MODIFY 列1 数据类型[约束] [COMMENT 注释],

MODIFY 列1 数据类型[约束] [COMMENT 注释],

......;

(3)修改字段的名称

ALTER TABLE 表名称

CHANGE 列1 新列名1 数据类型[约束] [COMMENT 注释],

CHANGE 列1 新列名1 数据类型[约束] [COMMENT 注释],

......;

(4)删除字段

ALTER TABLE 表名称

DROP 列1,

DROP 列2,

......;

4、数据库表字段约束

(1)数据库的范式

(2)字段约束

 

 

主键约束:
a、主键约束要求字段的值在全表必须唯一,而且不能为NULL值
b、建议主键一定要使用数字类型,因为数字的检索速度会非常快
c、如果主键是数字类型,还可以设置自动生成自动增长
create table t_teacher(
id int primary key auto_increment,
.....
);

 

非空约束:
a、非空约束要求字段的值不能为null值
b、null值为没有值,而不是“”空字符串
create table t_teacher(
id int primary key auto_increment,
name varchar(200) not null,
married boolean note null default false
.....
);

 

default 表示默认值
数据库中没有boolean数据类型,会转化成tinyint型,True用1表示,False用0表示
唯一约束:
唯一约束要求字段值如果不为null,那么在全表必须唯一
create table t_teacher(
.....
tel char(11) not null unique
.....
);

 

外键约束:
外键约束用来保证关联数据的逻辑关系
外键约束的定义是写在子表上的
create table t_dept(
deptno int unsigned primary key,
dname varchar(20) not null unique,
tel char(4) unique
);
create table t_temp(
empno int unsigned primary key,
ename varchar(20) not null,
sex enum('','') not null,
deptno int unsigned,
hiredate date not null,
foreign key (deptno) references t_dept(deptno)
);

 

enum枚举值,选择枚举内容填写
建表时先建主表,后建从表
删数据时,先删从表,在删主表
外键约束的闭环问题:
如果形成外键闭环,我们将无法删除任何一张表的记录       

5、数据库的索引机制

(1)创建索引
CREATE TABLE 表名称(
……,
INDEX [索引名称] (字段),
……
);

(2)添加索引
CREATE INDEX 索引名称 ON 表名称(字段);
ALTER TALBE 表名称 ADD INDEX [索引名](字段)

(3)查看数据表的所有索引:
SHOW INDEX FROM 表名称;

(4)删除索引:
DROP INDEX 索引名称 ON 表名;

(5)举例

CREATE TABLE t_message(
id INT UNSIGNED PRIMARY KEY ,
content VARCHAR(200) NOT NULL,
type ENUM("公告","通报","个人通知") NOT NULL,
create_time TIMESTAMP NOT NULL,
INDEX idx_type (type)
);
DROP INDEX idx_type ON t_message;
CREATE INDEX idx_type ON t_message(type);
SHOW INDEX FROM t_message;

DROP INDEX idx_type ON t_message;

ALTER TABLE t_message ADD INDEX idx_type(type);   

 二、数据库的基本查询

1、数据表的基本查询

(1)记录查询

  • 基本的查询语句是由SELECT和FROM关键字组成的
SELECT * FROM t_emp;

SELECT empno,ename,sal FROM t_emp;
  • SELECT 语句屏蔽了物理层的操作,用户不必关心数据的真实存储,交由数据库高效的查找数据
  • 使用列别名:通常情况下,SELECT 子句中使用了表达式,那么这列的名字就默认为表达式,因此需要一种对列名重命名的机制
SELECT

empno,

sal*12 AS "income"

FROM t_emp;
  • 查询语句的子句执行顺序:1. 词法分析与优化(读取SQL语句)2.FROM 选择数据来源 3. SELECT 选择输出内容 (FROM 优先级高于SELECT)

2、如何让数据分页显示

  • 如果结果集的记录很多,则可以使用LIMIT关键字限定结果集数量

语法:SELECT ...... FROM ...... LIMIT 起始位置,偏移量;
例如:

SELECT empno, ename FROM t_emp LIMIT 0,20;
  • 数据分页的简写用法

如果LIMIT子句只有一个参数,它表示的是偏移值,起始值默认为0,以下两条查询语句是相等的

SELECT empno,ename FROM t_emp LIMIT 10;
SELECT empno,ename FROM t_emp LIMIT 0,10;

 

  • 执行顺序

FROM -> SELECT -> LIMIT

3、如何对查询结果集进行排序

  • 如果没有设置,查询语句不会对结果进行排序。也就是说,如果想让结果集按照某种排序排列,就必须使用ORDER BY子句

SELECT ...... FROM ...... ORDER BY 列名[ASC|DESC];

【ASC 代表升序(默认),DESC代表降序,默认使用升序】

  • 如果排序列是数字类型,数据库就按照数字大小排列,如果是日期类型就按照日期大小排序,如果是字符串就按照字符集序号排序
  • 注意:默认情况下,如果两条数据排序字段内容相同,那么排序是什么样子?-----------按照主键大小排序
  • 多个排序字段:使用ORDER BY规定首要排序条件和次要排序条件。数据库会先按照首要排序条件排序,如果遇到首要排序内容相同的记录,那么就会启用次要排序条件接着排序
SELECT empno, ename, sal, hiredate

FROM t_emp

ORDER BY sal DESC, hiredate ASC;
  • 排序+分页

    ORDER BY 子句书写的时候放在LIMIT子句的前面

    FROM -> SELECT -> ORDER BY -> LIMIT

4、如果去除结果集中的重复记录

如果我们需要去除重复的记录,可以使用DISTINCT关键字来实现
语法: SELECT DISTINCT 字段 FROM ……;
例子:

SELECT DISTINCT job FROM t_emp;
  • 注意事项

使用DISITINCT的SELECT子句中只能查询一列数据,如果查询多列,去除重复记录就会失效。

SELECT DISTINCT job,ename FROM t_emp; # 错误

DISTINCT关键字只能在SELECT子句中使用一次,而且必须写在第一个字段的前面

SELECT DISTINCT job, DISTINCT ename FROM t_emp; # 错误
SELECT ename,DISTINCT job FROM t_emp; # 错误

5、条件查询语句

(1)WHEREE子句实现数据的筛选

SELECT ...... FROM ...... WHERE 条件[AND| OR] 条件 ......;

SELECT empno,ename,sal FROM t_emp WHERE deptno=10 AND sal >= 2000;
SELECT empno,ename,sal FROM t_emp WHERE (deptno=10 OR deptno=20) AND sal >= 2000;

(2)四类运算符

  • 算数运算符

 

 

 

ifnull语句

SELECT 10*null; 若结果为0可用ifnull语句
如果想让null值参与运算:SELECT 10*IFNULL(字段名,0);## 遇到null值就用0代替

计算两日期差DateDiff语句

DATEDIFF(日期1,日期2)

NOW语句

用NOW()可以获取当前日期与时间

SELECT empno,ename,sal,hiredate
FROM t_emp
WHERE deptno=10 AND (sal+IFNULL(comm,0))*12>=15000 
AND DATEDIFF(NOW(),hiredate)/365>=20;
  • 比较运算符

 

 

 

 注:LIKE 模糊查询   如ename LIKE "A%"(名字以A开头),%A 名字以A结尾 ,%A% 名字中含有A,_A第 第二个字母为A

举例1:

SELECT empno,ename,sal,hiredate
FROM t_emp
WHERE deptno IN(10,20,30)AND job!="SALEMAN"
AND hiredate<"1985-01-01";

举例2:

SELECT ename, comm,sal
FROM t_emp WHERE comm IS NOT NULL
AND sal BETWEEN 2000 AND 3000
AND ename LIKE "%A%";

举例3:

SELECT ename, comm,sal
FROM t_emp WHERE comm IS NOT NULL
AND sal BETWEEN 1000 AND 3000
AND ename REGEXP "^[\\u4e00-\\u9fa5]{2,4}$";
  • 逻辑运算符

 

 

 注意:

逻辑运算符的特殊:XOR异或关系 例如:age > 18 XOR sex = '男'  # 多个条件判断结果相同,结果为FALSE;判断结果不同,结果为TRUE

SELECT ename,deptno
FROM t_emp
WHERE NOT deptno IN(10,20) XOR sal>=1000;
  • 按位运算符

6、WHERE子句中条件执行的顺序

  • 筛选的过程,where条件排序 1 有索引的条件放在前面,2 查询数据多的 3 普通查询条件
  • 执行顺序:
    from->where->select->order by-> limit
    选择则数据来源(数据表):from
    有条件查询的语法和运算符:where
    显示结果集:select子句中的列别名和去除重复记录
    数据摆列语法:order by
    数据分页的语法:limit

三、数据库的高级查询

 (1)聚合函数的使用【聚合函数不能出现在where子句里】

聚合函数在数据的查询分析中,应用十分广泛。聚合函数可以对数据求和、求最大值和最小值、求平均值等等。

  • SUM函数

SUM函数用于求和,只能用于数字类型,字符类型的统计结果为0,日期类型统计结果是毫秒数相加

SELECT SUM(sal) FROM t_temp;

 

  • MAX函数

MAX函数用于获取非空值得最大值。

SELECT MAX(comm) FROM t_emp;

 

  • MIN函数

MIN函数用于获取非空值得最小值。

SELECT MIN(comm) FROM t_emp;

 

  • AVG函数

AVG函数用于获取非空值得平均值,非数字数据统计结果为0

SELECT AVG(sal+IFNULL(comm)) FROM t_emp;

 

  • COUNT函数

COUNT(*)用于获得包含空值的所有记录,COUNT(列名)用于获得包含非空值的记录数。

SELECT COUNT(*) FROM t_emp;
SELECT COUNT(comm) FROM t_emp;

(2)分组查询的应用

  • 分组:

默认情况下汇总函数是对全表范围内的数据做统计
GROUP BY子句的作用是通过一定的规则将一个数据集划分成若干个小的区域,然后针对每个小区域分别进行数据汇总处理

SELECT deptno,AVG(sal) FROM t_emp GROUP BY deptno;
  • 逐级分组

· 数据库支持多列分组条件,执行时候逐级分组

SELECT deptno,job,AVG(sal) FROM t_emp GROUP BY deptno,job;

对SELECT子句的要求
· 查询语句中如果含有GROUP BY子句,那么SELECT子句中的内容就必须要遵守规定:SELECT子句中可以包含聚合函数,或者GROUP BY子句的分组列,其余内容不可以出现在SELECT子句中

SELECT deptno,COUNT(*),AVG(sal) FROM t_emp GROUP BY deptno; 正确
SELECT deptno,COUNT(*),AVG(sal),sal FROM t_emp GROUP BY deptno; 错误
  • 对分组结果集再次做汇总计算
SELECT deptno,COUNT(*),AVG(sal),MAX(sal),MIN(sal)
FROM t_emp GROUP BY deptno WITH ROLLUP;

WITH ROLLUP可以对分组结果集再次做汇总计算,也就是都多个结果做聚合函数的总计算,非聚合函数为NULL值

  • GROUP_CONCAT函数

· GROUP_CONCAT函数可以把分组查询的某个字段拼接成一个字符串

SELECT deptno,GROUP_CONCAT(ename) FROM t_emp GROUP BY deptno;

  • 各种子句的执行顺序

FROM -> WHERE -> GROUP BY -> SELECT -> ORDER BY -> LIMIT

(3)HAVING子句

  • HAVING 子句不能独立存在,必须依赖于GROUP BY 语句    
  • WHERE 对普通条件作判断,HAVING 对聚合函数作判断

  • HAVING子句的特殊用法:按照数字1分组,MySQL会依据SELECT子句中的列进行分组,HAVING 子句也可以正常使用【GROUP BY 1 等于 GROUP BY SELECT的第一个数据】
select deptno from t_emp
where hiredate>='1982-01-01'
group by deptno having count(*)>=2;

select deptno,count(*) from t_emp group by 1(1指的是select中第一个字段)
#不建议
select deptno,count(*) from t_emp group by 1 having deptno in (10,20)     
#建议
select deptno,count(*) from t_emp where deptno in (10,20)group by 1   

(4)表的连接

  • 从多张表中提取数据:

从多张表中提取数据,必须指定关联的条件。如果不定义关联条件就会出现无条件连接,两张表的数据会交叉连接,产生笛卡尔积。

不定义关联条件:

select empno,ename,dname from t_emp join t_dept; # 错误

定义关联条件:

select e.empno,e.ename,d.dname
from t_emp e 
join t_dept d
on e.deptno = d.deptno;
  • 表连接的分类

表连接分为两种:内连接和外连接
内连接是结果集中只保留符合连接条件的记录
外连接是不管符不符合连接条件,记录都要保留在结果集中

(5)表的内连接

  • 内连接是最常见的一种表连接,用于查询多张关系表符合连接条件的记录

select ..... from 表1
[inner] join 表2 on 条件
[inner] join 表3 on 条件
.....

  • 内连接的多种语法形式

SELECT ...... FROM 表1 JOIN 表2 ON 连接条件;

SELECT ...... FROM 表1 JOIN 表2 WHERE 连接条件;

SELECT ...... FROM 表1 ,表2 WHERE 连接条件;

SELECT e.empno,e.ename,d.dname
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno;

SELECT e.empno,e.ename,d.dname
FROM t_emp e JOIN t_dept d WHERE e.deptno=d.deptno;

SELECT e.empno,e.ename,d.dname
FROM t_emp e,t_dept d WHERE e.deptno=d.deptno;
  • 练习
#1、查询每个员工的工号、姓名、部门名称、底薪、职位、工资等级
#内连接的数据表不一定必须有同名字段,只要字段之间符合逻辑关系就可以
SELECT e.empno,e.ename,d.dname,e.sal,e.job,s.grade
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno
JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal;

#2、查询与SCOTT相同部门的员工
#第一个比第二个慢
SELECT ename
FROM t_emp
WHERE deptno=(SELECT deptno FROM t_emp WHERE ename="SCOTT") AND ename!="SCOTT";
#相同数据表也可以做表连接 
SELECT e2.ename
FROM t_emp e1 JOIN t_emp e2 ON e1.deptno=e2.deptno
WHEREre e1.ename='SCOTT' AND e2.ename!='SCOTT';

#3、查询底薪超过公司平均底薪的员工
SELECT ename
FROM t_emp
WHERE sal>(SELECT AVG(sal) FROM t_emp);
#错误表连接
SELECT e2.deptno,e2.ename,e2.sal
FROM t_emp e1 JOIN t_emp e2 ON e2.sal>AVG(e1.sal);
#正确表连接
SELECT e.deptno,e.ename,e.sal
FROM t_emp e JOIN (SELECT AVG(sal) AS avg FROM t_emp) t ON e.sal>t.avg;

#4、查询RESEARCH部门的人数、最高底薪、最低底薪、平均底薪、平均工龄
SELECT COUNT(*),MAX(e.sal),MIN(e.sal),AVG(e.sal),FLOOR(AVG(DATEDIFF(NOW(),e.hiredate)/365))
FROM t_emp e JOIN t_dept d ON e.deptno=d.deptno
WHERE d.dname="RESEARCH";
#FLOOR()函数会将小数舍去;CELL()函数会将小数进位。

#5、查询每种职业的最高工资、最低工资、平均工资、最高工资等级和最低工资等级
SELECT e.job,MAX(e.sal+IFNULL(e.comm,0)),MIN(e.sal+IFNULL(e.comm,0)),AVG(e.sal+IFNULL(e.comm,0)),MAX(S.grade),MIN(S.grade)
FROM t_emp e JOIN t_salgrade s ON (e.sal+IFNULL(e.comm,0)) BETWEEN s.losal AND s.hisal
GROUP BY e.job;

#6、查询每个底薪超过部门平均底薪的员工信息
SELECT e.empno,e.ename,e.sal
FROM t_emp e JOIN
(SELECT deptno,AVG(sal) AS avg FROM t_emp GROUP BY deptno) t 
ON e.deptno=t.deptno AND e.sal>t.avg;

(6)表的外连接

  • 外连接与内连接的区别在于,除了符合条件的记录之外,结果集中还会保留不符合条件的记录。

 

  • 左连接和右连接:

    左外连接就是保留左表所有的记录,与右表做连接。如果右表有符合条件的记录就与左表连接。如果右表没有符合条件的记录,就用null与左表连接。右外连接也是如此。

#查询每个部门的名称和部门的人数
SELECT d.dname, count(e.deptno)
FROM t_dept d
LEFT JOIN  t_emp e ON e.deptno=d.deptno
GROUP BY d.deptno;
#查询每个部门的名称和部门的人数。如果没有部门的员工,部门名称用null替代
#union关键字可以将多个查询语句的结果集进行合并
(SELECT d.dname, count(e.deptno)
FROM t_dept d
LEFT JOIN  t_emp e on e.deptno=d.deptno
GROUP BY d.deptno)
UNION
(SELECT d.dname, count(*)
FROM t_dept d
RIGHT JOIN  t_emp e ON e.deptno=d.deptno
GROUP BY d.deptno)    
#查询每名员工的编号、姓名、部门、月薪、工资等级、工龄、上司编号、上司姓名、上司部门
SELECT e.empno,e.ename,d.dname,e.sal+IFNULL(e.comm,0),s.grade,FLOOR(DATEDIFF(NOW(),e.hiredate)/365),t.empno AS mgrno,t.ename AS mgrname,t.dname AS mgrdname
FROM t_emp e 
LEFT JOIN t_dept d ON e.deptno=d.deptno 
LEFT JOIN t_salgrade s ON e.sal BETWEEN s.losal AND s.hisal 
LEFT JOIN (SELECT e1.empno,e1.ename,d1.dname FROM t_emp e1 JOIN t_dept d1 ON e1.deptno=d1.deptno) t ON e.mgr=t.empno;
  • 外连接的注意事项

内连接只保留条件的记录,所以查询条件写在on子句和where子句中的效果是相同的。但是外连接里,条件写在where子句里,不符合条件的记录是会被过滤掉的,而不是保留下来       

 

 

(7)子查询的语法规则

  • 子查询: 子查询是一种查询中嵌套查询的语句。
  • 子查询的分类: 子查询可以写在三个地方:where子句、from子句、select子句,但是只有from子句子查询是最可取的。
  • where子查询: 这种子查询最简单,最简单理解,但是却是效率最低的子查询
  • from子查询: 这种子查询只会执行一次,所以查询效率很高
  • select子查询: 这种子查询每输出一条记录的时候都要执行一次,查询效率很低

(8)单行和多行子查询语法规则

  • 1.单行子查询的结果集只要一条记录,多行子查询结果集有多行记录
  • 多行子查询只能出现在where子句和from子句中
  • where子句中,可以使用in、all、any、exists关键字来处理多行表达式结果集的条件判断 all关键字:必须大于、小于或等于......子查询中所有的值 any关键字:只要大于、小于或等于......子查询中任意一值即可 exists关键字:把原来在子查询之外的条件判断,写到了子查询里面 exists语法:select ...... from 表名 where [not] exists(子查询);

 

posted @ 2021-08-28 13:58  钟胜一  阅读(1510)  评论(0编辑  收藏  举报