Mysql

 0、数据库基础介绍

MySQL常用数据类型

数据库管理系统  DBMS(data base management system ),包括Oracle,mysql,SQLserver,MongoDB,db2等

数据库/仓库     DB

SQL       结构化查询语言

Mysql      一种数据库软件,使用sql语言管理数据

数据库中事务的四大特性(ACID):原子性(Atomicity);一致性(Consistency);隔离性(Isolation);⑷ 持久性(Durability)

SQL语句分类:

1、DQL:数据查询语句,select         (Data Query Language)

2、DML:数据操作语句,insert/delete/update  (Data Manipulation Language)

3、DDL:数据库定义语句,create/drop/alter    (Data Denifition Language)

4、TCL:事务控制语言,commit/rollback    (Trasactional Control Language)

5、DCL:  数据控制语言,grant ,revoke     (Data Control Language)

创建数据库:

create database bjpowernode;

导入数据库脚本

数据库脚本:以.sql后缀结尾的文件

导入数据库脚本:

1.    选定数据库

2.    source命令

mysql> use bjpowernode;

Database changed

mysql> source C:UserscopywangDesktopjpowernode.sql

数据库表的介绍:

mysql>show tables;

mysql>desc dept;

1、查询字段

select ename,sal,job from emp;

select * from emp;  不建议使用,效率比前一个方法要低,因为要把*转成所有具体字段

2、进行数学运算,并对字段重命名

select ename,sal*12 as yearsal from emp;

 

3、条件查询

运算符

说明

=

等于

<>或!=

不等于

小于

<=

小于等于

大于

>=

大于等于

between … and ….

两个值之间,等同于 >= and <=

is null

为null(is not null 不为空)

and

并且

or

或者

in

包含,相当于多个or(not in不在这个范围中)

not

not可以取非,主要用在is 或in中

like

like称为模糊查询,支持%或下划线匹配

%匹配任意个字符

下划线,一个下划线只匹配一个字符


select ename,sal from emp where sal=5000;

MySQL支持自动类型转换,比如(但是其他数据库不支持,所以不要这么写):

select ename,sal from emp where sal='5000';

select job,ename from emp where job='MANAGER';

这里使用单引号是SQL的标准写法,MySQL也支持使用双引号,开发中只使用单引号

select ename,sal from emp where sal!=5000;

select job,ename from emp where job<>'MANAGER';

select ename,sal from empwhere sal>=1600;

select ename,sal from empwhere sal between 1600 and 3000;

select ename,sal from empwhere sal in (800,1600);

select ename,sal from empwhere job not in (‘MANAGER’,SALESMAN’);

select ename,comm fromemp where comm is null;

null不是数字,是空值,不能进行数学计算,因此不能用=号

select ename from empwhere ename like ‘%s%’;  包含s

select ename from empwhere ename like ‘s%’;   s开头

select ename from empwhere ename like ‘_d%’;   第二位为d

select ename from empwhere ename like ‘%n_’;   倒数第二位为n

4、排序

select ename,sal from emporder by sal;      默认asc升序

select ename,sal from emporder by sal desc;     降序

select deptno,ename,salfrom emp order by deptno,sal desc;       多字段排序:先按照deptno升序排列,deptno相同的记录按照sal降序排列

select job,ename,sal fromemp where job=’MANAGER’ order by 3 asc;  通过字段下标排序

5、数据处理函数

Lower

转换小写

upper

转换大写

substr

取子串(substr(被截取的字符串,起始下标,截取的长度)

length

取长度

trim

去空格

str_to_date

将字符串转换成日期

date_format

格式化日期

format

设置千分位

round

四舍五入

rand()

生成随机数

Ifnull

可以将null转换成一个具体值

注意:数据处理函数有些是Mysql特有的,可能在其他数据库不起作用

select lower(ename) as lowername from emp;   lower转小写

select upper(ename) as uppername from emp;  upper转大写

select substr(ename,1,1)as firstchar from emp;  截取首字母

select substr(ename,3,3)as ename from emp;    取3,4,5个字符

select length(ename) as enameLength from emp; 求字符长度

select * from emp where ename=trim(‘     king     ‘);  去掉前后空格(MySQL会自动去掉后面的空格)

select round(123.56);      输出是124

select round(123.56,0);      输出是124

select round(123.56,1);    输出是123.6

select round(123.56,-1);     输出是120

select rand();        随机数:输出【0,1】区间的随机数

select round(rand()*122);   生成【0,122】区间的任意整数(round用于取整)

case_when_then_else_end函数

示例:匹配工作岗位,为MANAGER时,薪水上调10%,为SALESMAN的时候,薪水上调50%

select ename,job,sal,
    (case job 
        when 'manager' then sal*1.1
        when 'salesman' then sal*1.5
        else sal
    end) as newsal
from emp;

注意:经测试,空格多了有时会报错

ifnull函数

select ename,(sal+comm)*12 as yearsal from emp;

select ename,(sal+ifnull(comm,0))*12 as yearsal from emp;

MySQL日期格式:

%Y:代表4位的年份          %y:代表2位的年份

%m:代表月, 格式为(01……12)        %c:代表月, 格式为(1……12)

%d :代表日

%H:代表24小时制,格式为(00……23)    %h: 代表12小时制,格式为(01……12)  

%i  : 代表分钟, 格式为(00……59) 

%S或%s:代表秒,格式为(00……59)       

%r:代表 时间,格式为12 小时(hh:mm:ss [AP]M)    %T:代表 时间,格式为24 小时(hh:mm:ss) 

 

select ename,hiredate from emp  where hiredate=str_to_date('12-03-1981','%m-%d-%Y');  str_to_date字符串转日期:将字符串按照“月-日-年”的读取方式转换成1981-12-03日期

select ename,date_format(hiredate,'%Y/%m/%d') as hiredate from emp;            date_format日期转字符串:以特定格式展示

6、分组/聚合/多行处理函数

count

取得记录数

sum

求和

avg

取平均

max

取最大的数

min

取最小的数

单行函数(如字符串处理函数等)一行输入对应一行输出

多行函数(如上述的聚合函数)    多行输入对应一行输出

注意:

1、聚合函数自动忽略空值,不需要添加where条件排除空值;

2、聚合函数不能直接用在where关键字之后。

select distinct deptno,job from emp order by deptno;  多字段去重   注意:distinct只能出现在所有字段最前面,后面如果有多个字段即为多字段联合去重

select job,max(sal) as maxsal from emp group by job order by maxsal desc;  group by分组:计算每个工作岗位的最高薪水,并按从高到低排序

select deptno,job,max(sal) as maxsal from emp group by deptno,job order by deptno,maxsal desc;  计算不同部门不同岗位的最高薪水,并按deptno由低到高、maxsal 由高到低排序

select job,max(sal) as maxsal from emp where job!='manager' group by job;    分组之前过滤:找出除manager以外的工作岗位的最高薪水

 select job,avg(sal) as avgsal from emp group by job having avgsal>2000;    having分组之后筛选:求每个岗位的平均薪水,要求显示平均薪水>2000的岗位。having必须在group by后面出现,先分组再筛选

select语句总结

一个完整的select语句格式如下

select 字段

from 表名

where …….

group by ……..

having …….(就是为了过滤分组后的数据而存在的—不可以单独的出现)

order by ……..

limit n;

以上关键字的顺序不能变,严格遵守。

以上语句的执行顺序:

  1)from:将硬盘上的表文件加载到内存

  2)where:将符合条件的数据行摘取出来,生成一张临时表T

  3)group by:根据列中的数据种类,将临时表T划分为多个新的临时表t1、t2....tn

  4)having:过滤掉group by中生成的不符合条件的临时表

  5)select:对当前的临时表进行整列读取

  6)order by:对select生成的临时表进行排序,默认为升序(降序为desc),多字段为联合排序

  7)limit:对最终生成的表,截取前面的n条记录

7、跨表查询

left join   :以左边为准,返回 左边的所有内容+右边共同内容

right join   :同理,以右边为准

(inner ) join :返回共同的内容

      

年代分类:
  SQL92
    select ename,dname from emp as e,dept as d where e.deptno=d.deptno;
    SQL99(掌握)
        select 
            e.ename,d.dname 
        from 
            emp e
        join
            dept d
        on 
            e.deptno=d.deptno
        where
            数据过滤条件;
    

连接方式分类:
    内连接:省略了inner关键字
        等值连接
            查询员工所对应的部门名称
            select e.ename,d.dname from emp as e (inner) join dept as d on e.deptno=d.deptno;
        非等值连接
            查询员工薪水对应的薪水等级
            select ename,sal,grade from emp as e join salgrade as s on e.sal between s.losal and s.hisal;
        自连接:把一张表当两张表用
            查询员工所对应的领导名称:显示员工和领导的姓名(king没有领导,所以不显示)
            select a.ename,b.ename as leaderName from emp as a join emp as b on a.mgr=b.empno;
            
    外连接:省略了outer关键字
        左连接/右连接
            显示所有员工对应的领导名称(king没有领导,以null填充其领导)
            select a.ename,b.ename as leaderName from emp as a left/right (outer) join emp as b on a.mgr=b.empno;    
            
    全连接
            查询员工的部门名称,领导名称和薪水等级
            select 
                e.ename,d.dname,b.ename as leaderName,s.grade 
            from 
                emp e
            join
                dept d
            on e.deptno=d.deptno
            join
                emp b
            on e.mgr=b.empno
            join
                salgrade s
            on e.sal between s.losal and s.hisal;

等值连接

非等值连接

自连接

左连接

全连接

7、子查询

显示比平均薪资高的员工姓名及薪资

 select ename,sal from emp where sal>(select avg(sal) from emp);

找出每个部门的平均薪水,并且显示平均薪水的薪水等级

select deptno,avgsal,grade from
    (select deptno,avg(sal) as avgsal from emp group by deptno) as t
join salgrade as s    
on t.avgsal between s.losal and s.hisal;

8、其他查询(union、limit)

union:查询岗位为manager和salesman的员工

select ename,job from emp where job='manager' or job='salesman';
select ename,job from emp where job in('manager','salesman');
select ename,job from emp where job='manager'   union   select ename,job from emp where job='salesman';

limit:只在MySQL中起作用

9、表

DDL数据定义语言:create、drop、alter

1、创建表

 

create table student(
    no int(4),
    name varchar(32),
    gender char(1) default '1',
    birth date,
    email varchar(128)
);

create table emp_bak as select * from emp;  复制表

2、删除表

drop table student;
drop table if exists student;          MySQL特有

3、修改表

create table student(
    no int(4),
    name varchar(32)
);

alter table student add email varchar(128);                //添加字段
alter table student modify no int(8);                    //修改字段数据类型
alter table student drop email;                            //删除字段
alter table student change name username varchar(32);    //修改字段名称
alter table student add (c1 char(1),c2 char(1));                //添加多列字段
alter table student change c1 c3 int(1),change c2 c4 char(2);    //修改多列字段
alter table student drop c3,drop c4;                            //删除多列字段

DML数据操控语言:insert,update,delete

3、插入语句

insert into student(no,name,gender,birth,email) values (1,'zhangsan','1','1949-10-1','zhangsan@163.com');
insert into student(no,name,gender,birth,email) values (2,'lisi','0',str_to_date('1949-10-1','%Y-%m-%d'),'lisi@163.com');
insert into student(no,name,gender,birth,email) values (3,'wangwu','0',str_to_date('10-1-1949','%m-%d-%Y'),'wangwu@163.com');
insert into student(no,name,gender) values (4,'lilei','1');
insert into student values (5,'Jerry','1','1959-11-21','Jerry@163.com');    mysql特有,不建议用

4、修改语句

update student set birth='1994-05-10',email='lilei@163.com' where no=4;

5、删除语句

delete from student where no=4;
delete from student;                //删除表中所有记录

10、约束

常见的约束

a)        非空约束,not null

b)        唯一约束,unique

c)        主键约束,primary key

d)        外键约束,foreign key

e)        自定义检查约束,check(不建议使用)(在mysql中现在还不支持)

create table user(
       id int(4) PRIMARY key AUTO_INCREMENT,    //主键,自增(mysql特有)
       name varchar(32) not null,               //非空
       email varchar(128) unique                //唯一,不可重复
);

需求:设计数据库表用来存储学生和班级信息

需求分析:

  a)学生表student包含:sno,sname,classno,cname

  b)一个班级对应多个学生,一对多关系

create table student(
    id int(4) primary key auto_increment
    sno int(4) unique,
    sname varchar(32),
    classno int(4),
    cname varchar(32)
);

这样建表会造成数据冗余

create table student(
    sno int(4) primary key auto_increment,
    sname varchar(32),
    classno int(4),
    constraint fk foreign key(classno) references class(cno)    //constraint fk:给这个约束起名fk,不需要时可删除。该语句可省略。    字段classno源自class表中的cno
);

create table class(
    cno int(4) primary key,
    cname varchar(32)
);

11、窗口函数

可以把“窗口”这个词想象成一个集合,一个窗口就是一个集合。

over (partition by a order by b) from T 是指:把表T按照a列进行分组,然后,分别让每一个集合的记录按照b列进行排序。

partiton by是可选的。如果不使用partition by,那么就是将整张表作为一个集合,最后使用排序函数得到的就是每一条记录根据b列的排序编号。

在窗口函数中使用SUM、AVG、MAX、MIN计算的范围是排序后每条记录自身和排在它之前的所有记录。

比如按照时间排序,计算各个时间的销售总额,这种统计方法称为累计:

SUM(sale_price)over(partition by 日期 order by 时间) as date_sum
name  subject score
zs math 75
zs chinese 81
zhaoliu chinese 59
zhaoliu math 16
zhaoliu english 48
wangwu chinese 81
wangwu math 100
wangwu english 99
lisi math 89
lisi chinese 76

1、用SQL选出每个人成绩的最高的前两条纪录

select *,row_number() over(partition by name order by score desc) as flag from tmp;
select * from (select *,row_number() over(partition by name order by score desc) as flag from tmp)t where t.flag<=2;

 2、查询成绩表中每一科成绩最高的分数以及这个学生的名字,学科名

select *,rank() over(partition by subject order by score desc) as flag from tmp;

select name,subject from (select *,rank() over(partition by subject order by score desc) as flag from tmp)t where t.flag=1;

3、学生成绩表,把每科最高分前两名统计出来

select *,row_number() over(partition by subject order by score desc) as flag from tmp;

select * from (select *,row_number() over(partition by subject order by score desc) as flag from tmp)t where t.flag<=2;

 4、找出单科成绩高于该科平均成绩的同学名单(无论该学生有多少科,只要有一科满足即可)

传统方法

select subject,avg(score) from tmp group by subject;
    
select tmp.name,tmp.subject,tmp.score,t.avg_score
from tmp
join (select subject,avg(score) as avg_score  from tmp group by subject)t 
on tmp.subject=t.subject
where tmp.score>t.avg_score;

 窗口函数

select *,avg(score) over(partition by subject) as flag from tmp;

select * from (select *,avg(score) over(partition by subject) as flag from tmp)t where t.score>t.flag;

 5、每个用户按照订单id,截止到当前的累计订单金额/平均订单金额/最大订单金额/最小订单金额/订单数是多少?

select * from
(select order_id,user_no,amount,create_date,
    sum(amount) over w as sum1,
    avg(amount) over w as avg1,
    max(amount) over w as max1,
    min(amount) over w as min1,
    count(amount) over w as count1
    from order_tab
    WINDOW w AS (partition by user_no order by order_id )
) t;

12、经典面试题

1、取得每个部门最高薪水的人员名字

第一步,求出每个部门的最高薪水

select deptno,max(sal) as maxsal from emp group by deptno;

第二步,将上述查询当成临时表t,进行表连接查询

select e.deptno,e.ename,t.maxsal,e.sal from 
emp e
join (select deptno,max(sal) as maxsal from emp group by deptno) t
on e.deptno=t.deptno
where t.maxsal=e.sal
order by e.deptno;

2、哪些人的薪水在平均薪水之上

第一步,先求出每个部门的平均薪水

select deptno,avg(sal) as avgsal from emp group by deptno;

第二步,将上述查询当成临时表t,进行表连接查询

select e.deptno,e.ename,e.sal,t.avgsal from
emp e
join (select deptno,avg(sal) as avgsal from emp group by deptno)t
on e.deptno=t.deptno
where e.sal>t.avgsal
order by e.deptno;

 3、取得部门中所有人平均的薪水等级

select e.deptno,e.ename,s.grade from
emp e
join salgrade s
on e.sal between s.losal and s.hisal
order by e.deptno;

select t.deptno,avg(t.grade) as avgGrade from
(select e.deptno,e.ename,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal order by e.deptno) t
group by t.deptno;

4、平均薪水最高的部门编号

第一步,先求出每个部门的平均薪水

select deptno,avg(sal) as avgsal from emp group by deptno;

第二步,将上述查询当成临时表t(deptno,avgsal),进行子查询,得到最高平均薪水

select max(t.avgsal) from (select deptno,avg(sal) as avgsal from emp group by deptno) t;

第三步,having筛选

select deptno,avg(sal) as avgsal from emp group by deptno having avgsal=  (select max(t.avgsal) from (select deptno,avg(sal) as avgsal from emp group by deptno) t)  ;

 5、平均薪水最高的部门名称

select 
    e.deptno,d.dname,avg(e.sal) as avgsal 
from emp e
join dept d
on e.deptno=d.deptno
group by deptno 
having avgsal=(select max(t.avgsal) from (select deptno,avg(sal) as avgsal from emp group by deptno) t);

 6、取得比普通员工(员工代码没有在mgr上出现的)的最高薪水还要高的经理人姓名

第一步,找出普通员工

select * from emp where empno not in (select distinct mgr from emp where mgr is not null);

第二步,找出普通员工的最高薪水

select max(sal) as maxsal from emp where empno not in (select distinct mgr from emp where mgr is not null);

第三步,子查询

select ename from emp where sal>(select max(sal) as maxsal from emp where empno not in (select distinct mgr from emp where mgr is not null)) ;

 7、取得薪水最高的前五名员工,第六到第十的员工,最后入职的5名员工

select * from emp order by sal desc limit 5;       //前5
select * from emp order by sal desc limit 5,5;     //第6到第10
select * from emp order by hiredate desc limit 5;

 8、每个薪水等级有多少员工

第一步,先求出每个员工的薪水等级

select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal;

第二步,将以上结果当成临时表t(ename,sal,grade),进行子查询

select t.grade,count(*) from (select e.ename,e.sal,s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal)t group by t.grade;

 9、列出所有员工及领导名字

select e.ename,t.ename as LeaderName
from emp e 
left join emp t
on e.mgr=t.empno;

 10、列出受雇日期早于其领导的员工编号、姓名、部门(多表连接)

select e.empno,e.ename,e.hiredate,t.hiredate as leaderDate,d.dname     //hiredate可省略,仅为了直观观察
from emp e 
join emp t on e.mgr=t.empno
join dept d on e.deptno=d.deptno
where e.hiredate<t.hiredate; 

 11、列出至少有5个员工的部门(having对分组后的结果进行筛选)

select deptno,count(ename) as totalEmp
from emp 
group by deptno
having totalEmp>=5;

 12、列出所有‘CLERK’的姓名及其部门名称、部门人数

第一步,求出CLERK姓名及部门名称,令查询结果为t1

select d.deptno,d.dname,e.ename from emp e join dept d on e.deptno=d.deptno where e.job='CLERK';

第二步,求出每个部门的员工数量,令查询结果为t2

select deptno,count(*) as numEmp from emp group by deptno;

第三步,内连接合并

select t1.ename,t1.dname,t2.numEmp from
(select d.deptno,d.dname,e.ename from emp e join dept d on e.deptno=d.deptno where e.job='CLERK')t1
join (select deptno,count(*) as numEmp from emp group by deptno)t2 
on t1.deptno=t2.deptno;

 13、列出最低薪水大于1500的各种工作,及从事此工作的全部人数

select job,min(sal) as minsal,count(ename) as empNum from emp group by job having minsal>1500;

 14、列出薪水高于平均薪水的所有员工、所在部门、上级领导、工资等级

第一步,求出平均薪水

select avg(sal) from emp;

第二步,多表连接

select e.ename,d.dname,e2.ename as leaderName,s.grade
from emp e
join dept d on e.deptno=d.deptno 
left join emp e2 on e2.empno=e.mgr 
join salgrade s on e.sal between s.losal and s.hisal
where e.sal>(select avg(sal) from emp);

 15、列出每个部门的员工数量、平均工资和平均工作期限

select d.dname,count(e.ename) as empNum,avg(e.sal) as avgsal,avg((to_days(now())-to_days(e.hiredate))/365) as avgworkYear
from emp e
join dept d
on e.deptno=d.deptno
group by e.deptno;

 16、列出各种工作的最低薪水及从事该工作的员工姓名

第一步,求出各工作的最低薪水

select job,min(sal) as minsal from emp group by job;

第二步,将以上查询结果令为t表(job,minsal),进行表连接

select e.job,e.ename,e.sal
from emp e
join (select job,min(sal) as minsal from emp group by job)t
on e.job=t.job
where e.sal=t.minsal;

 17、列出所有员工的年工资,按年薪从低到高排序

 

 考察 ifnull 的用法

IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。

 18、给任职时日超过30年的员工加薪10%

create table emp_bak as select * from emp;

update emp_bak set sal=sal*1.1 where (to_days(now())-to_days(hiredate))>30;

 

 

 

create table s(
    sno int(4) primary key auto_increment,
    sname varchar(32)
); 

create table c(
    cno int(4) primary key auto_increment,
    cname varchar(32),
    cteacher varchar(32)
); 

create table sc(
    sno int(4),
    cno int(4),
    scgrade double(3,1),    //3位有效数字,1位小数
    constraint sc_sno_cno_pk primary key(sno,cno),
    constraint sc_sno_fk foreign key(sno) references s(sno),
    constraint sc_cno_fk foreign key(cno) references c(cno)
); 

插入语句

insert into s(sname) values('zhangsan');
insert into s(sname) values('lisi');
insert into s(sname) values('wangwu');
insert into s(sname) values('zhaoliu');

insert into c(cname,cteacher) values('java','吴老师');
insert into c(cname,cteacher) values('c++','王老师');
insert into c(cname,cteacher) values('Python','张老师');
insert into c(cname,cteacher) values('MySQL','郭老师');
insert into c(cname,cteacher) values('Oracle','黎明');

insert into sc values(1,1,30);
insert into sc values(1,2,50);
insert into sc values(1,3,80);
insert into sc values(1,4,90);
insert into sc values(1,5,70);
insert into sc values(2,2,80);
insert into sc values(2,3,50);
insert into sc values(2,4,70);
insert into sc values(2,5,80);
insert into sc values(3,1,60);
insert into sc values(3,2,70);
insert into sc values(3,3,80);
insert into sc values(4,3,50);
insert into sc values(4,4,80);
View Code

 1、找出没选过黎明老师的所有学生姓名

第一步,黎明老师的授课编号

select cno from c where cteacher='黎明';

第二步,选过黎明老师的学生编号

select sno from sc where cno=(select cno from c where cteacher='黎明');

第三步,子查询反推

select sname from s where sno not in(select sno from sc where cno=(select cno from c where cteacher='黎明'));

2、列出2门及以上不及格学生姓名及其平均成绩

第一步,求2门及以上不及格的学生姓名,令为t1

select sc.sno,sname,count(*) as failNum 
from sc 
join s on s.sno=sc.sno
where scgrade<60 
group by sno having failNum>=2;

第二步,求各学生的平均分,令为t2

select sno,avg(scgrade) as avgScore from sc group by sno;

第三步,合并两表

select t1.sname,t2.avgScore
from (select sc.sno,sname,count(*) as failNum from sc join s on s.sno=sc.sno where scgrade<60 group by sno having failNum>=2)t1
join (select sno,avg(scgrade) as avgScore from sc group by sno)t2
on t1.sno=t2.sno;

 3、既学过1号课又学过2号课的所有学生姓名

第一步

select sno from sc where cno=1;
select sno from sc where cno=2;

第二步,合并

select sno from sc where cno=1 and sno in (select sno from sc where cno=2);

第三步,表连接

select sname from sc join s on sc.sno=s.sno where sc.cno=1 and sc.sno in (select sc.sno from sc where sc.cno=2);

 

原文地址:https://www.cnblogs.com/little-monkey/p/11312333.html