数据库学习day03:SQL基础应用及元数据获取

1. DDL应用

1.1 数据定义语言

1.2 库定义

1.2.1 创建数据库

create database school charset utf8mb4;   #指定字符集
create database school charset utf8mb4 collate utf8mb4_bin;  #指定校对规则(默认大小写不敏感)

show charset;      #查看数据库中支持的字符集
show cllocation;   #查看校对规则

建库规范:
1.库名不能有大写字母   
2.建库要加字符集         
3.库名不能有数字开头
4. 库名要和业务相关

建库标准语句

damao[(none)]>create database test charset utf8mb4;
Query OK, 1 row affected (0.01 sec)

damao[(none)]>show create database test;
+----------+------------------------------------------------------------------+
| Database | Create Database                                                  |
+----------+------------------------------------------------------------------+
| test     | CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8mb4 */ |
+----------+------------------------------------------------------------------+
1 row in set (0.00 sec)

damao[(none)]>

1.2.2 删除数据库(生产中禁止使用)

damao[(none)]>drop database test;

1.2.3 查询及修改数据库

show create database test;  #查看数据库的字符集及较对规则
alter database test charset utf8;
注意:修改字符集不会使数据库中原有的数据字符集发生改变,只会改变新数据的字符集,所以要将原有的数据导出更改字符集再进行导入。
注意:修改字符集,修改后的字符集一定是原字符集的严格超集

1.3 表定义

1.3.1 创建表

create table stu(
列1  属性(数据类型、约束、其他属性) ,
列2  属性,
列3  属性
) 存储引擎,字符集编码,注释;

1.3.2 建表

use school;  #首先要进入到相应的库中

CREATE TABLE stu(
id      INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学号',
sname   VARCHAR(64) NOT NULL COMMENT '姓名',
sage    TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '年龄',
sgender ENUM('m','f','n') NOT NULL DEFAULT 'n' COMMENT '性别' ,
sfz     CHAR(18) NOT NULL UNIQUE  COMMENT '身份证',
intime  DATETIME NOT NULL DEFAULT NOW() COMMENT '入学时间'
) ENGINE=INNODB CHARSET=utf8mb4 COMMENT '学生表';

建表规范

1. 表名小写
2. 不能是数字开头
3. 注意字符集和存储引擎
4. 表名和业务有关
5. 选择合适的数据类型
6. 每个列都要有注释
7. 每个列设置为非空,无法保证非空,用0来填充。

1.3.3 删除表(生产中禁用命令)

drop table stu;       *删除整个表(表结构+数据行)
truncate table stu;  *只会删除表中的数据行,不会删除表结构

1.3.4 修改表

1.在school库的stu表中添加qq列

alter table stu add qq varchar(20) not null unique comment 'QQ号';

2.在sname后加入地址列

alter table stu add addr varchar(64) not null commit '地址' after sname;

3.在id列前加入新列 num

alter table stu add num int not null comment '数字' first;

4.

alter table stu drop num;
alter table stu drop addr;
alter table stu drop qq;

5.修改sname列的数据类型属性

alter table stu modify sname varchar(32) not null;

6.将sgender列改为sg列,将数据类型改为char类型

alter table stu change sgender sg tinyint not null default 0 comment '0是女生,1是男生';
desc stu;

7.修改表名

alter table stu reanme to xuesheng;

说明:归档表,日志表
作为一个企业或者DBA,我们通常会有这种想法,数据是一个公司的核心命脉,应该需要永久保存,很多时候DBA和开发沟通的时候,开发人员也会这么告诉我们,这份数据非常重要,数据需要永久保存。然而,如果将数据库的数据永久保存,那么迟早有一天,你会拥有一个非常大的数据库。作为一个DBA,通常为了业务对数据库的操作性能考虑和存储容量的考虑。我们会建议对数据库里大表进行数据归档,例如将使用的高频数据保留在当前表,对低频数据保留在归档表中,或定期对数据进行归档,或当数据达到一定量时对数据表进行归档处理;

归档表原理操作(类似于日志切割)
1.方式一
alter table stu rename to stu_2019_11;  *将旧表改名
create table stu like stu_2019_11;          *创建新表

2.方式二
 Oracle 物化视图 (了解)


面试题:若开发要紧急上线DDL SQL,如何进行评估,请写审核SQL要点

答:SQL语句是数据DDL操作,是属于列的添加操作
直接执行时会产生表锁,对业务的影响较大,数据量大,业务量大时,对于业务影响较大。
所以我们推荐
(1)最好业务不繁忙做
(2)使用 pt-osc(percona-toolkit) 工具来进行online DDL,减少对业务的影响
https://www.percona.com/software/database-tools/percona-toolkit
(3)对于归档表,可以使用pt-archiver 自己扩展.

1.3.5 表属性查询

use school  *进入到指定库
show tables;  *查看表
desc stu;       *查看表结构
show create table stu;  *查看表(列)属性

2. DCL 数据控制语言

grant  权限 on 库表 to 用户名@'白名单' identified by '密码';
revoke 权限 on 库表 from 用户名@'白名单' identified by '密码';

3. DML 数据操纵语言

主要对表中数据行操作

3.1 insert 数据插入

-----标准写法
use database school;
desc stu;
INSERT INTO stu(id,sname,sage,sg,sfz,intime) 
VALUES
(1,'zs',18,'m','123456',NOW());

-----省事写法
INSERT INTO stu 
VALUES
(2,'ls',18,'m','1234567',NOW());

--- 针对性的录入数据
INSERT INTO stu(sname,sfz)
VALUES ('w5','34445788');

--- 同时录入多行数据
INSERT INTO stu(sname,sfz)
VALUES 
('w55','3444578d8'),
('m6','1212313'),
('aa','123213123123');
SELECT * FROM stu;

3.2 数据修改(更新)

update stu  set age=18 where name='zs';
注意:update语句必须要加where。

3.3 delete 数据删除

-----删除id为4的数据行
delete from stu where id=4;

------若不跟条件,则删除所有数据行,类似于 truncate table stu
delete from stu ;
说明:
DELETE 语句数据逻辑删除,磁盘空间不会立即释放,会产生碎片.
truncate会立即释放磁盘空间
思考: 2亿行的大表,批量删除5000w(按时间条件)

3.4 伪删除

删除id=5的行,伪删除实现
ALTER TABLE stu ADD state TINYINT NOT NULL DEFAULT 1;
SELECT * FROM stu;
原语句:
DELETE FROM stu WHERE id=5;
替换为: 
UPDATE stu SET state=0 WHERE id=5;

原业务语句:
SELECT * FROM stu;
替换为:
SELECT * FROM stu WHERE state=1;

4. DQL 数据查询语言 ********

4.1 select ******

4.1.1 单独使用

(1)查询参数

SELECT @@datadir;
SELECT @@port;
SELECT @@socket;
SELECT @@basedir;
SELECT @@innodb_flush_log_at_trx_commit;
SHOW VARIABLES ;      **配置文件中的所有参数

(2)简易计算

select 1024*1024;
select   1+1;

(3)函数查询

SELECT NOW();
SELECT DATABASE();
SELECT USER();
SELECT CONCAT("hello world");
SELECT CONCAT(USER,"@",HOST) FROM mysql.user;
SELECT GROUP_CONCAT(USER,"@",HOST) FROM mysql.user;
https://dev.mysql.com/doc/refman/5.7/en/func-op-summary-ref.html?tdsourcetag=s_pcqq_aiomsg

4.1.2 配合多子句(单表查询标准用法)

多子句应用顺序: *****
(1) FROM     必须使用的
(2) WHERE    
(3) GROUP BY 
(5) HAVING 
(6) ORDER BY  
(7) LIMIT 

(1)单表子句 ---from

SELECT 列1,列2 FROM 表
SELECT  *  FROM 表

例:

--- 1. 查询city表中的所有数据(不要对大表进行操作)
SELECT * FROM city;
--- 2. 查询city表中所有的name和population
SELECT NAME,population FROM city;

(2)单表子句----where

SELECT 列1,列2 FROM TABLE WHERE 条件;

1.where 配合等值查询

--- 查询中国所有城市的信息
SELECT * FROM city WHERE countrycode='CHN';

-- 查询北京市的信息
SELECT * FROM city WHERE NAME='peking';

-- 查询甘肃省所有城市信息
SELECT * FROM city WHERE district='gansu';

2.where 的不等值查询(> < >= <= !=)

--- 1. 城市人口小于100人的城市
SELECT * FROM city WHERE population<100;

--- 2. 不是中国的城市信息 
SELECT * FROM city WHERE countrycode <> 'CHN';

3.where 配合 like语句使用(模糊查询)

--- 1. 查询国家代号是CH开头的城市信息.
SELECT * FROM city WHERE countrycode LIKE 'CH%';

注意: LIKE 语句 百分号不要出现在查询条件前,因为查询不走索引

4.where 配合逻辑连接符(and or)

--- 1. 中国城市人口大于500w的城市
SELECT * FROM city WHERE countrycode='CHN' AND population>5000000 ;

--- 2. 中国或者美国城市信息
SELECT * FROM city WHERE countrycode='CHN' OR countrycode='USA';

5.where配合in语句(or)

--- 中国或者美国城市信息
SELECT * FROM city WHERE countrycode IN ('CHN','USA');

6.where 配合 between ...and....(and)

--- 查询 人口数量在100w-200w之间的城市
SELECT * FROM city WHERE population >= 1000000 AND population <= 2000000;

SELECT * FROM city WHERE population BETWEEN 1000000 AND 2000000;

(3)group by (分组)+ 聚合函数应用

常用聚合函数
MAX()        最大值
MIN()        最小值
AVG()        平均值
COUNT()      数量
SUM()        求和
GROUP_CONCAT() 列转行

说明:
有 GROUP by子句,必然会有聚合函数
在业务查询需求中,需要对于表中数据按照数据特点进行分别统计时,GROUP BY + 聚合函数来实现

--- 1. 统计世界的所有人口总和
SELECT  SUM(population) FROM city ;

--- 2. 统计国家的总人口数量
SELECT countrycode, SUM(population) FROM city GROUP BY countrycode ;

--- 3. 统计中国每个省的总人口数
SELECT countrycode,district , SUM(population)  FROM city GROUP BY district;

--- 5. 统计中国每个省的城市名列表.
SELECT district,GROUP_CONCAT(NAME) FROM city WHERE countrycode='CHN'  GROUP BY district;

关于 GROUP BY 的限制
group by的工作原理,先将group by之后的所写之列进行排序,然后去重,再将函数中包含的列进行函数运算;

damao[(none)]>select countrycode,district,sum(population) from world.city group by district;
ERROR 1055 (42000): Expression 
-- #1 of SELECT list is not in GROUP BY clause and contains nonaggregated 
-- column 'world.city.CountryCode' which is not functionally dependent 
-- on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

--- sql_mode=only_full_group_by
1. 在 SELECT 后的条件,不在 GROUP BY 后
2. 在 SELECT 后的条件,不在函数里包裹
3. 如果select后列是唯一值时候,就不会报错
5. GROUP BY 的条件列是主键或者唯一键时.

总结: sql_mode=only_full_group_by 为了防止出现结果集1对多的关系.

(4)having
作用:用于进一步过滤,在group by 之后执行

where | group by |having   #使用顺序

例:统计中国每个省的总人口数,只打印总人口数小于100万

select district,sum(population) from city
where countrycode='CHN'
group by district
having sum(population) <1000000;

(5)order by + limit
作用:用于将将指定列数据进行排序

----1.查看中国所有的城市,并按人口数进行排序(从大到小)

select name,population from city
where countrycode='CHN'
order by population desc;
注:加上desc表示逆序(从大到小),不加为升序(从小到大)

----2.统计中国各个省的总人口数量,按照总人口从大到小排序

SELECT district AS 省 ,SUM(Population) AS 总人口
FROM city
WHERE countrycode='chn'
GROUP BY district
ORDER BY 总人口 DESC ;

----3.统计中国,每个省的总人口,找出总人口大于500w的,并按总人口从大到小排序,只显示前三名

SELECT  district, SUM(population)  FROM  city 
WHERE countrycode='CHN'
GROUP BY district 
HAVING SUM(population)>5000000
ORDER BY SUM(population) DESC
LIMIT 3 ;    注:此时相当于为limit 0,3. 跳过0行,显示3行

注:LIMIT N ,M --->跳过N,显示一共M行
LIMIT 5,5 跳过五行,一共显示5行。显示6-10行  

SELECT  district, SUM(population)  FROM  city 
WHERE countrycode='CHN'
GROUP BY district 
HAVING SUM(population)>5000000
ORDER BY SUM(population) DESC
LIMIT 5,5;

4.1.3 distinct:去重复

----从city表中查出国家名称

SELECT countrycode FROM city ;
SELECT DISTINCT(countrycode) FROM city  ;

4.1.4 联合查询- union all 将多个select的数据合并(纵向合并)显示

-- 中国或美国城市信息

SELECT * FROM city 
WHERE countrycode IN ('CHN' ,'USA');

SELECT * FROM city WHERE countrycode='CHN'
UNION ALL
SELECT * FROM city WHERE countrycode='USA'

说明:一般情况下,我们会将 IN 或者 OR 语句 改写成 UNION ALL,来提高性能
UNION     去重复
UNION ALL 不去重复

4.1.5 join 多表连接查询

案例准备,按需创建表

CREATE DATABASE school CHARSET utf8mb4;
USE school

CREATE TABLE student(
sno INT NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '学号',
sname VARCHAR(20) NOT NULL COMMENT '姓名',
sage TINYINT UNSIGNED  NOT NULL COMMENT '年龄',
ssex  ENUM('f','m') NOT NULL DEFAULT 'm' COMMENT '性别'
)ENGINE=INNODB CHARSET=utf8;

CREATE TABLE course(
cno INT NOT NULL PRIMARY KEY COMMENT '课程编号',
cname VARCHAR(20) NOT NULL COMMENT '课程名字',
tno INT NOT NULL  COMMENT '教师编号'
)ENGINE=INNODB CHARSET utf8;

CREATE TABLE sc (
sno INT NOT NULL COMMENT '学号',
cno INT NOT NULL COMMENT '课程编号',
score INT  NOT NULL DEFAULT 0 COMMENT '成绩'
)ENGINE=INNODB CHARSET=utf8;

CREATE TABLE teacher(
tno INT NOT NULL PRIMARY KEY COMMENT '教师编号',
tname VARCHAR(20) NOT NULL COMMENT '教师名字'
)ENGINE=INNODB CHARSET utf8;

INSERT INTO student(sno,sname,sage,ssex)
VALUES 
(1,'zhang3',18,'m'),
(2,'zhang4',18,'m'),
(3,'li4',18,'m'),
(4,'wang5',19,'f'),
(5,'zh4',18,'m'),
(6,'zhao4',18,'m'),
(7,'ma6',19,'f'),
(8,'oldboy',20,'m'),
(9,'oldgirl',20,'f'),
(10,'oldp',25,'m');


INSERT INTO teacher(tno,tname) VALUES
(101,'oldboy'),
(102,'hesw'),
(103,'oldguo');



INSERT INTO course(cno,cname,tno)
VALUES
(1001,'linux',101),
(1002,'python',102),
(1003,'mysql',103);


INSERT INTO sc(sno,cno,score)
VALUES
(1,1001,80),
(1,1002,59),
(2,1002,90),
(2,1003,100),
(3,1001,99),
(3,1003,40),
(4,1001,79),
(4,1002,61),
(4,1003,99),
(5,1003,40),
(6,1001,89),
(6,1003,77),
(7,1001,67),
(7,1003,82),
(8,1001,70),
(9,1003,80),
(10,1003,96);

语法

image.png

查询张三的家庭住址

SELECT A.name,B.address FROM
A JOIN  B
ON A.id=B.id
WHERE A.name='zhangsan';

多表练习SQL题

-- 1. 每位老师讲的课程名称
SELECT teacher.tno,teacher.tname,GROUP_CONCAT(course.cname)
FROM teacher 
JOIN course
ON teacher.tno=course.tno
GROUP BY teacher.tno;

思考: 如果老师名重名,或者老师讲多门课,怎么办?

-- 2. 每位学员学习了几门课?
SELECT student.sno,student.sname,COUNT(sc.cno)
FROM student 
JOIN sc
ON student.sno=sc.sno 
GROUP BY student.sno;

-- 3. 每位学员学习了几门课及课程名称列表?
SELECT 
student.sno,
student.sname,
COUNT(sc.cno),
GROUP_CONCAT(course.cname)
FROM student 
JOIN sc
ON student.sno=sc.sno 
JOIN course
ON sc.cno=course.cno
GROUP BY student.sno;

** case when ...then.. end 语句**

5. 写多表连接技巧

1. 相关表 
2. 找相关表关联条件
E-R 图 (自己扩展) ----> 开发DBA要做的事情

外连接

A  left join  B 
A 表所有的数据+B表满足关联条件的数据

A  right join B
B表所有的数据+A 满足关联条件的数据

实现外连接原生功能,需要把where的条件改为and/

mysql> select city.name,city.population ,country.name from city left join country on city.countrycode=country.code   and  city.population<100 order by population desc ;

结论: left join 应用场景,强制驱动表(关联查询中结果集小的)

  1. where 条件
  2. 原始表大小

6. 别名的应用

表别名: 给表设计的别名,在任何子句中调用
列别名: 给select 后的列设定别名,在having 和 order by子句中调用

表别名:

select a.tname AS "老师姓名" ,group_concat(d.sname) AS "不及格的学生"
from  teacher AS a 
join course AS b 
on a.tno = b.tno
join sc AS c
on c.cno = b.cno
join student AS d
on d.sno = c.sno
where c.score < 60
group by a.tno;

列别名:

select 
student.sno   AS 学生学号 ,
student.sname AS 学生姓名,
avg(sc.score) AS 平均成绩
from student
join sc
on student.sno=sc.sno
group by sutdent.sno
having 平均成绩 >85

==================
子查询 : (自己了解)
高级SQL编程: 内置函数,存储过程,函数,视图,事件,触发器,游标,Json开发 (自己了解)

==================

7. show 语句

show databases ;                      查看所有库名
show tables;                          查看当前库下的所有表名.
show tables from world;               查看world库下的所有表
show create database world;           查看建库语句
show create tables city;              查看建表语句
show [global] variables like '%trx%'; 查看参数信息
show grants for root@'localhost'; 查看用户权限信息
show [full] processlist;      查看会话连接情况 
show engines;                 查看当前数据库支持的引擎.
show charset;                 查看当前数据库支持的字符集.
show collation;               查看当前数据库支持的排序规则.
show [global] status;         查看当前数据库的状态信息.
show status like '%lock%'\G   模糊查询数据库状态.
show master status;           查看当前使用的二进制日志信息.
show binary logs;             查看所有二进制日志信息.
show binlog evnets in 'xxxx'  查看二进制日志事件信息.
show relaylog events in 'xxx' 查看中继日志事件信息.
show slave status \G          查看从库复制状态信息.
show engine innodb status \G  查看InnoDB引擎相关状态信息.

======================

8. 元数据获取

8.1 什么是元数据?

库,表   : 属性(字符集,校对规则,数据类型,存储引擎,约束,其他数据)
权限    :
状态信息:
等.

8.2 元数据获取方法

show语句                : 封装好的基础功能,可以实现大部分的元数据查询需求.     
information_schema<视图>库:  mysql 给我们定义好的元数据查询的方法.

8.3 information_schema<视图>库

应用场景: 做数据库资产统计.
tables : 
TABLE_SCHEMA  :  表所在的库
TABLE_NAME    :  表名
ENGINE        :  引擎
TABLE_ROWS    :  表的行数
AVG_ROW_LENGTH:  平均行长度
INDEX_LENGTH  :  索引长度
TABLE_COMMENT :  表的注释
create view  v_xxx as
select a.tname AS "老师姓名" ,group_concat(d.sname) AS "不及格的学生"
    from  teacher AS a 
    join course AS b 
    on a.tno = b.tno
    join sc AS c
    on c.cno = b.cno
    join student AS d
    on d.sno = c.sno
    where c.score < 60
    group by a.tno;

select  * from v_xxx ;

例子:
----- 1. 统计所有库下的表的个数

select table_schema,count(table_name) from information_schema.tables group by table_schema;

----- 2. 统计不同存储引擎的表名

select engine,group_concat(table_name) from information_schema.tables group by engine;

-----3. 统计所有非系统表,非InnoDB的表

mysql 
information_schema 
performace_schema 
sys

SELECT table_schema,table_name ,ENGINE 
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
HAVING  ENGINE != 'innodb';

作业:
-- 5. 统计总数据量(不包含系统表)
-- 6. 统计每个库的数据量(不包含系统表)

SELECT 
table_schema,
SUM( TABLE_ROWS * AVG_ROW_LENGTH + index_length)/1024/1024 AS "total_mb"
FROM information_schema.tables
WHERE table_schema NOT IN ('mysql','information_schema','performance_schema','sys')
GROUP BY table_schema
ORDER BY total_mb DESC; 

扩展题
-- 7. 将school库下所有的数据字典信息(列名,数据类型,注释信息)进行统计
例如:
id int 城市id
name varchar 城市名

SELECT column_name,column_type,column_comment 
FROM information_schema.columns 
WHERE table_schema='school'; 

.....
-- 8. 模仿以下语句,生成数据库下单表的备份语句(不包含系统表),并保存至/backup/sh/bak.sh
例子语句:
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql
mysqldump -uroot -p123 world city >/backup/world_city.sql

select  concat('mysqldump -uroot -p123 ' ,table_schema, ' ' ,table_name ', >/backup/',table_schema,'_',table_name,'.sql' ) 
from information_schema.tables
 where table_schema not in ('mysql','information_schema','performance_schema','sys')
 into outfile '/backup/sh/bak.sh';

你可能感兴趣的:(数据库学习day03:SQL基础应用及元数据获取)