SQL语言详解

SQL

1. 概述

Structured Query Language 结构化查询语言

  • 结构化查询语言(Structured Query Language)简称SQL,是一种数据库查询和程序设计语言,用于存取数据以及查询更新管理数据。
  • SQL语言使我们有能力访问数据库,并且SQL是一种ANSI(美国国家标准化组织)的标准计算机语言,各大数据库 厂商在生产数据库软件的时候,几乎都会去支持SQL的语法,以使得用户在使用软件时更加容易上手,以及在不同 厂商软件之间进行切换时更加适应,因为大家的SQL语法都差不多。
  • SQL语言功能很强,十分简洁,核心功能只用了9个动词。语法接近英语口语,所以,用户很容易学习和使用。
image-20220421141508464

SQL全称叫做结构化查询语言,结构化是什么意思?

结构化数据

  • 结构化数据也称作行数据,是由二维表结构来逻辑表达和实现的数据,严格地遵循数据格式与长度规范,主要通过关系型数据库进行存储和管理。
  • 与结构化数据相对的是不适于由数据库二维表来表现的非结构化数据,包括所有格式的办公文档、XML、HTML、 各类报表、图片和音频、视频信息等。
  • 通俗来说,结构化数据会有严格的行列对齐,便于解读与理解。
image-20220421141804631 image-20220421141846676

SQL语法分类

SQL主要语法分为两个部分:数据定义语言 (DDL)数据操纵语言 (DML)

  • DDL语法使我们有能力创建或删除表,以及数据库、索引等各种对象,但是不涉及表中具体数据操作

    • CREATE DATABASE - 创建新数据库
    • CREATE TABLE - 创建新表
  • DML语法是我们有能力针对表中的数据进行插入、更新、删除、查询操作

    • SELECT - 从数据库表中获取数据
    • UPDATE - 更新数据库表中的数据
    • DELETE - 从数据库表中删除数据
    • INSERT - 向数据库表中插入数据

什么是数据库?什么是数据库管理系统?什么是SQL?他们之间的关系是什么?

  • 数据库

    • 英文单词Database,简称DB。 按照一定格式存储数据的一些文件的组合。顾名思义:存储数据的仓库,实际上就是一堆文件。这些文件中存储了具有特定格式的数据。
  • 数据库管理系统

    • Database Management,简称DBMS。数据库管理系统是专门用来管理数据库中数据的,数据库管理系统可以对数据库当中的数据进行增删改查

    • 常见的数据库管理系统

      • MySQL、Oracle、 MS SqlServer、 DB2、sybase等...
  • SQL

    • 结构化查询语句
  • 三者之间的关系?

    • 程序员需要学习SQL语句,程序员通过编写SQL语句,然后DBMS负责执行SQL语句,最终来完成数据库中数据的增删改查操作。
    DBMS --执行--> SQL --操作--> DB
    

准备

此文学习需要用到此sql数据,建议先将数据导入到库中

数据放到了末尾

表名区分大小写问题

表的列名是不区分大小写的

  • win10 mysql不区分大小写
  • linux mysql区分大小写
    • 让MYSQL不区分表名大小写的方法其实很简单:
    • 用ROOT登录,修改/etc/my.cnf
    • 在[mysqld]下加入一行:lower_case_table_names=1
    • 重新启动数据库即可

2. DDL

Data Definition Language 数据定义语言

  • 凡是带有create、drop、alter 的都是DDL

  • DDL主要操作的是表的结构。不是表中的数据

  • 这个增删改和DML不同,这个主要是对表结构进行操作

  • 不同数据库的DDL略微有些差异,此文只提及最基本的DDL操作。

create database

  • create database用于创建新的数据库

    CREATE DATABASE [IF NOT EXISTS] database_name
    
  • 例子:创建数据库itcast

    create database if not exists itcast;
    

use database

  • 选择特定的数据库:切换当前会话使用哪一个数据库进行操作

drop database

  • 删除数据库

    DROP DATABASE [IF EXISTS] database_name;
    

create table

create table 表名(
	字段名1 数据类型,
	字段名2 数据类型,
	字段名3 数据类型
);

------------------------------
varchar : 可变长度的字符串,根据送进来的字符串的长度自动分配
   char : 定长字符串,分配固定长度的空间区存储数据
    int \ bigint 长整型=long(java)
  float \ double
   data \ datetime 
   clob : 字符大对象 最多存储4G的字符串,超过255字符的都需要使用clob (character large object)
   blob : 二进制大对象 专门存储图片、声音、视频等流媒体数据 (binary large object)

show

  • Show相关的语句可以帮助用户查询相关信息。
  • 比如我们最常使用的查询当前数据库下有哪些表 show tables.
--1、显示所有数据库
show databases;

--2、显示当前数据库所有表
show tables;
SHOW TABLES [IN database_name]; --指定某个数据库

--3、查询显示一张表的元数据信息
desc table_name;

3. DQL

Data Query Language 数据查询语句

(凡是带有select关键字的都是查询语句)

Select语法

  • 表名和列名不区分大小写
  • 关键词的顺序不能变
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[LIMIT [offset,] rows];

关键词的执行顺序(很重要)

// 执行顺序
from -> where -> group by -> having -> select -> order by -> limit

基本使用

-- 查看表的所有数据
select * from table; -- 效率低,可读性差

-- 查看具体字段的数据
select field from table;

-- 查询多个字段的数据
select field, field from table;

-- 给查询的列起别名,as可以省略保留空格
-- 只是将显示的查询结果改变,实际不变
select dname, deptno as deptname from dept;

-- 别名有空格需要加单或者双引号,建议使用单引号
select dname, deptno as 'dept name' from dept;

-- 字段可以使用数学运算
select dname, deptno * 10 as deptno from dept;

-- 字段为常数时,会导出一个列,行数与表的行数相等
select 'KingDom' as name from emp;
-- +---------+
-- |  name   |
-- +---------+
-- | KingDom |
-- | KingDom |
-- | KingDom |
--    ...
-- +---------+

-- 查看表的结构 descripe
desc table;
-- 查看版本号
select version();
-- 查看此数据库
select database();

where

  • WHERE后面是一个布尔表达式(结果要么为true,要么为false),用于查询过滤,当布尔表达式为true时,返回select后面expr表达式的结果,否则返回空
  • 在WHERE表达式中,可以使用数据库支持的任何函数和运算符,但聚合函数除外
-- = 判断是否相等
select dname, deptno from dept where loc = 'dallas';

-- <> or != 判断是否不等
select dname, deptno from dept where loc <> 'dallas';

-- <=, <, >, >=
select dname, deptno from dept where loc > 'dallas';
select dname, deptno, loc from dept where loc >= 'dallas';

-- between ... and ...
-- 等同于 >= and <=
select dname, deptno, loc from dept where loc between 'dallas' and 'dallas';
select dname, deptno, loc from dept where loc >= 'dallas' and <= 'dallas';

-- 在数据库中null不能使用等号衡量,需要使用is null
select empno, ename, sal, comm from emp where comm is null;
select empno, ename, sal, comm from emp where comm is not null;

-- and / or
select empno, ename, sal, comm from emp where comm is not null and comm = 300;
select empno, ename, sal, comm from emp where sal = 1600 or comm = 300;
-- and和or同时出现 and优先级更高,同时使用需要加括号
select empno, ename, sal, comm from emp where sal > 1600 and (deptno = 10 or deptno = 20);
  
-- in 
select empno, ename, sal, job from emp where job in ('manager', 'salesman');
-- not取反
select empno, ename, sal, job from emp where job not in ('manager', 'salesman');

-- like
-- %:匹配任意多个字符
-- 下划线_:任意一个字符
-- %和_都是特殊字符,代表字符时需要加上反斜线转义
select ename from emp where ename like '%o%';
select ename from emp where ename like '%\_%';

数据处理函数

  • 单行处理函数:一个输入对应一个输出

  • 多行处理函数:多个输入对应一个输出

  • 函数之间可以嵌套调用

单行处理函数

Lower\upper

  • 转换小写\转换大写
select empno, ename, lower(job) from emp;
select empno, ename, lower(job) as job from emp;

substr(串,起始下标,取出长度)

  • 取子串,起始下标从1开始
select empno, ename, substr(lower(job), 1, 3) as job from emp;

-- 不区分大小写
select ename from emp where substr(ename, 1, 1) = 'S';
select ename from emp where substr(ename, 1, 1) = 's';

-- 首字母大写,两个字符串需要使用concat连接
select concat(upper(substr(ename, 1, 1)), lower(substr(ename, 2, length(ename) - 1))) as ename from emp;

trim

  • 去空格
select * from emp where ename = trim('  King');

round(数字, 保留几位小数)

  • 四舍五入
round(199.22, -1)
// 200, -1是保留十数位

rand()

  • 产生0-1随机数
rand()

ifnull()

  • 判断是否为null,是null的话可以将其值替换
select ename, (sal + ifnull(comm, 0)) * 10 as yearsal from emp;
+--------+----------+
| ename  | yearsal  |
+--------+----------+
| SMITH  |  8000.00 |
| ALLEN  | 19000.00 |
| WARD   | 17500.00 |
| JONES  | 29750.00 |
| MARTIN | 26500.00 |
| BLAKE  | 28500.00 |
		...
+--------+----------+

case..when..then..when..then..else..end

  • 分支语句,有点像switch
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;
+--------+-----------+---------+---------+
| ename  | job       | sal     | newsal  |
+--------+-----------+---------+---------+
| SMITH  | CLERK     |  800.00 |  800.00 |
| ALLEN  | SALESMAN  | 1600.00 | 2400.00 |
| WARD   | SALESMAN  | 1250.00 | 1875.00 |
| JONES  | MANAGER   | 2975.00 | 3272.50 |
| MARTIN | SALESMAN  | 1250.00 | 1875.00 |
| BLAKE  | MANAGER   | 2850.00 | 3135.00 |
| CLARK  | MANAGER   | 2450.00 | 2695.00 |
					...
+--------+-----------+---------+---------+

分组函数

多行处理函数

分组函数在使用的时候必须先进行分组,然后才能用。如果你没有对数据进行分组,整张表默认为一组。

  • 分组函数自动忽略null

  • 分组函数不能只用使用在where子句中

    • 因为分组函数在使用的时候必须先分组之后能使用

    • where执行的时候还没有分组,所以where后面不能出现分组函数

    • 执行顺序

      from -> where -> group by -> select -> order by
      

分组函数

  • 函数的最大特点是不管原始数据有多少行记录,经过聚合操作只返回一条数据,这一条数据就是聚合的结果
min、max、avg、sum、count
-- 返回薪资最小值
select min(sal) from emp;
-- 返回薪资最大值
select max(sal) from emp;
-- 返回薪资的平均值
select avg(sal) from emp;
-- 返回薪资的总和
select sum(sal) from emp;
-- 返回领取薪资的人个数(不一定为行数,若存在null)
select count(sal) from emp;

select count(*) from emp; -- 14 统计行数
select count(comm) from emp; -- 4 统计除null的数据数

Group by

  • GROUP BY语句用于结合分组函数,根据一个或多个列对结果集进行分组
  • 如果没有group by语法,则表中的所有行数据当成一组
-- 按照工作岗位对工资求平均
select job, avg(sal) from emp group by job;
+-----------+-------------+
| job       | avg(sal)    |
+-----------+-------------+
| CLERK     | 1037.500000 |
| SALESMAN  | 1400.000000 |
| MANAGER   | 2758.333333 |
| ANALYST   | 3000.000000 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+

-- 可以对多个列分组
select deptno, job, max(sal) from emp group by deptno, job order by deptno;
+--------+-----------+----------+
| deptno | job       | max(sal) |
+--------+-----------+----------+
|     10 | CLERK     |  1300.00 |
|     10 | MANAGER   |  2450.00 |
|     10 | PRESIDENT |  5000.00 |
|     20 | ANALYST   |  3000.00 |
|     20 | CLERK     |  1100.00 |
|     20 | MANAGER   |  2975.00 |
|     30 | CLERK     |   950.00 |
|     30 | MANAGER   |  2850.00 |
|     30 | SALESMAN  |  1600.00 |
+--------+-----------+----------+

注意

  • 在一条select语句中,如果有group by语句的话,select后面只能跟参加分组的字段分组函数
    • 避免出现一个字段多个值的歧义
    • 参加分组的字段:因为分组的依据就是该字段,因为组内的值相同不存在歧义
    • 分组函数:分组函数对组内进行操作,是多进一出,也不存在歧义
-- 此语句会报错,因为sal既参加分组的字段,也并未使用分组函数
select job, sal from emp group by job;

Having

  • 在SQL中增加HAVING子句原因是,WHERE关键字无法与聚合函数一起使用
  • HAVING子句可以让我们筛选分组后的各组数据,并且可以在Having中使用聚合函数,因为此时where,group by 已经执行结束,结果集已经确定
-- 找出平均薪资大于2k的部门
where select deptno, avg(sal) from emp group by deptno having avg(sal) > 2000;
+--------+-------------+
| deptno | avg(sal)    |
+--------+-------------+
|     20 | 2175.000000 |
|     10 | 2916.666667 |
+--------+-------------+

HAVING与WHERE区别

  • having是在分组后对数据进行过滤
  • where是在分组前对数据进行过滤
  • having后面可以使用聚合函数
  • where后面不可以使用聚合函数

order by

排序

  • ORDER BY 语句用于根据指定的列对结果集进行排序
  • ORDER BY 语句默认按照升序(ASC)对记录进行排序。如果您希望按照降序对记录进行排序,可以使用DESC关键字
select ename from emp order by ename;
-- 先按薪资排序,薪资相同看名字
select ename,sal from emp order by sal asc ename asc;
-- 按照第几列排序,只做了解
select empno, ename, job from emp order 3;
-- desc降序
select empno, ename, job, sal from emp where sal between 1250 and 3000 order by sal desc;

limit

  • LIMIT用于限制SELECT语句返回的行数
  • LIMIT接受一个或两个数字参数,这两个参数都必须是非负整数常量。
  • 第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。当给出单个参数时,它代表最大行数,并且偏移量默认为0。
-- limit startIndex(可缺省从0), length 
select ename, sal from emp order by sal desc limit 2, 3;
+-------+---------+
| ename | sal     |
+-------+---------+
| FORD  | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+

distinct

去重

-- 查看有哪些job
select distinct job from emp;

-- distinct只能出现在最前方,表示联合去重
select distinct job, comm from emp;
+-----------+---------+
| job       | comm    |
+-----------+---------+
| CLERK     |    NULL |
| SALESMAN  |  300.00 |
| SALESMAN  |  500.00 |
| MANAGER   |    NULL |
| SALESMAN  | 1400.00 |
| ANALYST   |    NULL |
| PRESIDENT |    NULL |
| SALESMAN  |    0.00 |
+-----------+---------+

-- job的总数量
select count(distinct job) from emp;

4. Join关联查询

从一张表中单独查询,称为单表查询。emp表和dept表联合起来查询数据,从emp表中取员工名字,从dept表中取部门名字。这种跨表查询,多张表联合起来查询数据,被称为连接查询。

语法

select
	...
from
	...
join
	...
on
	...

4.1 内连接

  • 只有进行连接的两个表中都存在与连接条件相匹配的数据才会被留下来

    image-20220422221420860

等值连接

-- 查询每个人的部门名
select 
	e.ename, d.dname 
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno;

非等值连接

-- 查询每个人的薪资等级
select 
	e.ename, e.sal, s.grade 
from 
	emp e 
join 
	salgrade s 
on 
	e.sal between s.losal and hisal;
+--------+---------+-------+
| ename  | sal     | grade |
+--------+---------+-------+
| SMITH  |  800.00 |     1 |
| ALLEN  | 1600.00 |     3 |
| WARD   | 1250.00 |     2 |
| JONES  | 2975.00 |     4 |
| MARTIN | 1250.00 |     2 |
| BLAKE  | 2850.00 |     4 |
| CLARK  | 2450.00 |     4 |
| SCOTT  | 3000.00 |     4 |
| KING   | 5000.00 |     5 |
| TURNER | 1500.00 |     3 |
| ADAMS  | 1100.00 |     1 |
| JAMES  |  950.00 |     1 |
| FORD   | 3000.00 |     4 |
| MILLER | 1300.00 |     2 |
+--------+---------+-------+

4.2 外连接

会将主表没有匹配上的例子也输出出来

左外连接

  • left join中文叫做是左外连接(Left Outer Join)或者左连接,其中outer可以省略,left outer join是早期的写法。 left join的核心就在于left左。左指的是join关键字左边的表,简称左表。
  • 通俗解释:join时以左表的全部数据为准,右边与之关联;左表数据全部返回,右表关联上的显示返回,关联不上的显示null返回
image-20220422221445715
-- 查询每个人的上级名
-- king没有老板,显示为null
select e.ename, d.ename from emp e left join emp d on e.mgr = d.empno;
+--------+-------+
| ename  | ename |
+--------+-------+
| SMITH  | FORD  |
| ALLEN  | BLAKE |
| WARD   | BLAKE |
| JONES  | KING  |
| MARTIN | BLAKE |
| BLAKE  | KING  |
| CLARK  | KING  |
| SCOTT  | JONES |
| KING   | NULL  |
| TURNER | BLAKE |
| ADAMS  | SCOTT |
| JAMES  | BLAKE |
| FORD   | JONES |
| MILLER | CLARK |
+--------+-------+

右外连接

  • 同理
  • right表示右边的表是主表
select e.ename, d.dname from emp e right join dept d on e.deptno = d.deptno;
+--------+------------+
| ename  | dname      |
+--------+------------+
| MILLER | ACCOUNTING |
| KING   | ACCOUNTING |
| CLARK  | ACCOUNTING |
| FORD   | RESEARCH   |
| ADAMS  | RESEARCH   |
| SCOTT  | RESEARCH   |
| JONES  | RESEARCH   |
| SMITH  | RESEARCH   |
| JAMES  | SALES      |
| TURNER | SALES      |
| BLAKE  | SALES      |
| MARTIN | SALES      |
| WARD   | SALES      |
| ALLEN  | SALES      |
| NULL   | OPERATIONS |
+--------+------------+

-- OPERATIONS 岗位没有人,显示为null

4.3 多表相连

-- a表与b、c表相连
select
	...
from
	a
join 
	b
on
	...
join
	c
on
	...

找出每个员工的部门名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级?

select 
	e.ename name, d.dname bumen, e.sal sal, s.grade salgrade 
from 
	emp e 
join 
	dept d 
on 
	e.deptno = d.deptno 
join 
	salgrade s 
on 
	e.sal between s.losal and s.hisal;
+--------+------------+---------+----------+
| name   | bumen      | sal     | salgrade |
+--------+------------+---------+----------+
| SMITH  | RESEARCH   |  800.00 |        1 |
| ALLEN  | SALES      | 1600.00 |        3 |
| WARD   | SALES      | 1250.00 |        2 |
| JONES  | RESEARCH   | 2975.00 |        4 |
| MARTIN | SALES      | 1250.00 |        2 |
| BLAKE  | SALES      | 2850.00 |        4 |
| CLARK  | ACCOUNTING | 2450.00 |        4 |
| SCOTT  | RESEARCH   | 3000.00 |        4 |
| KING   | ACCOUNTING | 5000.00 |        5 |
| TURNER | SALES      | 1500.00 |        3 |
| ADAMS  | RESEARCH   | 1100.00 |        1 |
| JAMES  | SALES      |  950.00 |        1 |
| FORD   | RESEARCH   | 3000.00 |        4 |
| MILLER | ACCOUNTING | 1300.00 |        2 |
+--------+------------+---------+----------+

5. 子查询

select语句中嵌套select语句

select
	...(select)
from
	...(select)
where
	...(select)

示例

找出比最低工资高的员工

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

找出每个工作岗位的平均工资的等级

select 
	s.job, s.avgsal, d.grade 
from 
	(select 
		job, avg(sal) avgsal 
	 from 
	 	emp 
	 group by job) s 
join 
	salgrade d 
on 
	s.avgsal between d.losal and d.hisal;
+-----------+-------------+-------+
| job       | avgsal      | grade |
+-----------+-------------+-------+
| CLERK     | 1037.500000 |     1 |
| SALESMAN  | 1400.000000 |     2 |
| MANAGER   | 2758.333333 |     4 |
| ANALYST   | 3000.000000 |     4 |
| PRESIDENT | 5000.000000 |     5 |
+-----------+-------------+-------+

6. 总结

关键词的书写顺序

select 
	...
from
	...
where
	...
group by
	...
having
	...
order by
	...
limit
	...

关键词的执行顺序

from -> where -> group by -> having -> select -> order by -> limit

7. 练习题

  1. 取得每个部门最高薪水的人员名称

    先将每个部门最高的薪水和部门号给取出来,然后再将其和原表进行内联,找出结果

 select 
 	e.ename ename, e.sal sal, e.deptno 
 from 
 	emp e 
 join 
 	(select max(sal) maxsal, deptno from emp group by deptno) d 
 on 
 	e.sal = d.maxsal and e.deptno = d.deptno;
 	
+-------+---------+--------+
| ename | sal     | deptno |
+-------+---------+--------+
| BLAKE | 2850.00 |     30 |
| SCOTT | 3000.00 |     20 |
| KING  | 5000.00 |     10 |
| FORD  | 3000.00 |     20 |
+-------+---------+--------+
  1. 取得每个部门薪资比平均薪资高的人

    与前一个题类似,我们只需先找出平均工资,然后再对比就行

select 
	e.ename ename, e.sal sal, e.deptno 
from 
	emp e 
join 
	(select avg(sal) avgsal, deptno from emp group by deptno) d 
on 
	e.sal > d.avgsal and e.deptno = d.deptno;
+-------+---------+--------+
| ename | sal     | deptno |
+-------+---------+--------+
| FORD  | 3000.00 |     20 |
| SCOTT | 3000.00 |     20 |
| JONES | 2975.00 |     20 |
| BLAKE | 2850.00 |     30 |
| ALLEN | 1600.00 |     30 |
| KING  | 5000.00 |     10 |
+-------+---------+--------+
  1. 取得部门中所有人的平均薪水等级

    先取出所有人的分组和平均薪资等级,再将其求取平均

select 
	deptno, avg(grade) 
from 
	(select 
     	e.deptno, s.grade 
     from 
     	emp e
     join 
     	salgrade s 
     on 
     	e.sal between s.losal and s.hisal) em 
group by 
	deptno;
+--------+------------+
| deptno | avg(grade) |
+--------+------------+
|     20 |     2.8000 |
|     30 |     2.5000 |
|     10 |     3.6667 |
+--------+------------+
  1. 不准使用函数(MAX)取得最高薪水
select 
	sal 
from 
	emp 
order by 
	sal desc 
limit 1;
+---------+
| sal     |
+---------+
| 5000.00 |
+---------+
  1. 取得平均薪水最高的部门的部门编号
select 
	deptno 
from 
	(select 
		deptno, avg(sal) avgsal 	
	from 
		emp 
	group by 
		deptno 
	order by 
		avgsal desc) em 
limit 1;
+--------+
| deptno |
+--------+
|     10 |
+--------+
  1. 取得平均薪水最高的部门的部门名称
select 
	d.dname 
from 
	(select 
		deptno, avg(sal) avgsal 	
	from 
		emp 
	group by 
		deptno 
	order by 
		avgsal desc) em 
join 
	dept d
on
	em.deptno = d.deptno
limit 1;
+------------+
| dname      |
+------------+
| ACCOUNTING |
+------------+
  1. 求平均薪水的等级最低的部门的部门名称
select 
	d.dname
from
    (select 
        deptno, avg(grade) as avgg
    from 
        (select 
            e.deptno, s.grade 
         from 
            emp e
         join 
            salgrade s 
         on 
            e.sal between s.losal and s.hisal) em 
    group by 
        deptno
    order by
    	avgg asc
    limit 1) nw
join 
	dept d
on
	nw.deptno = d.deptno;
+-------+
| dname |
+-------+
| SALES |
+-------+
  1. 取得比普通员工(员工代码没有在mgr字段上出现的)的最高薪水还要高的领导人姓名

    只需要找出员工的最高薪水就行,只要薪水比这个最高薪水高那肯定是领导

    需要去除null,不然无法筛选

select 
	ename 
from 
	emp 
where 
	sal > (select 
           		max(sal) 
           from 
           		emp 
           where 
           		empno not in (select distinct mgr from emp where mgr is not null));
+-------+
| ename |
+-------+
| JONES |
| BLAKE |
| CLARK |
| SCOTT |
| KING  |
| FORD  |
+-------+
  1. 取出薪水最高的前五名员工
select 
	ename, sal 
from 
	emp 
order by 
	sal desc 
limit 5;
+-------+---------+
| ename | sal     |
+-------+---------+
| KING  | 5000.00 |
| SCOTT | 3000.00 |
| FORD  | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
+-------+---------+
  1. 取得薪水最高的第六到第十名员工
select 
	ename, sal 
from 
	emp 
order by 
	sal desc 
limit 5, 5;
+--------+---------+
| ename  | sal     |
+--------+---------+
| CLARK  | 2450.00 |
| ALLEN  | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD   | 1250.00 |
+--------+---------+
  1. 取得最后入职的5名员工
select 
	ename, hiredate 
from 
	emp 
order by 
	hiredate desc 
limit 5;
+--------+------------+
| ename  | hiredate   |
+--------+------------+
| ADAMS  | 1987-05-23 |
| SCOTT  | 1987-04-19 |
| MILLER | 1982-01-23 |
| JAMES  | 1981-12-03 |
| FORD   | 1981-12-03 |
+--------+------------+
  1. 取得每个薪水等级有多少员工
select grade,count(grade) from (select s.grade as grade from emp e join salgrade s on e.sal between s.losal and s.hisal) em group by grade;
// 等价,后者更简洁
select s.grade, count(*) as grade from emp e join salgrade s on e.sal between s.losal and s.hisal group by s.grade;
+-------+-------+
| grade | grade |
+-------+-------+
|     1 |     3 |
|     3 |     2 |
|     2 |     3 |
|     4 |     5 |
|     5 |     1 |
+-------+-------+
  1. 列出所有员工及领导的姓名
select 
	ee.ename, eb.ename 
from 
	emp ee 
left join 
	emp eb 
on 
	ee.mgr = eb.empno;
+--------+-------+
| ename  | ename |
+--------+-------+
| SMITH  | FORD  |
| ALLEN  | BLAKE |
| WARD   | BLAKE |
| JONES  | KING  |
| MARTIN | BLAKE |
| BLAKE  | KING  |
| CLARK  | KING  |
| SCOTT  | JONES |
| KING   | NULL  |
| TURNER | BLAKE |
| ADAMS  | SCOTT |
| JAMES  | BLAKE |
| FORD   | JONES |
| MILLER | CLARK |
+--------+-------+
  1. 列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称
select 
	e.empno, e.ename, d.dname 
from 
	emp e 
join 
	emp e2 
on 
	e.mgr = e2.empno and e.hiredate < e2.hiredate 
join 
	dept d 
on 
	e.deptno = d.deptno;
+-------+-------+------------+
| empno | ename | dname      |
+-------+-------+------------+
|  7369 | SMITH | RESEARCH   |
|  7499 | ALLEN | SALES      |
|  7521 | WARD  | SALES      |
|  7566 | JONES | RESEARCH   |
|  7698 | BLAKE | SALES      |
|  7782 | CLARK | ACCOUNTING |
+-------+-------+------------+

8. 数据

CREATE DATABASE if not EXISTS bjpowernode;
USE bjpowernode;

DROP TABLE IF EXISTS EMP;
DROP TABLE IF EXISTS DEPT;
DROP TABLE IF EXISTS SALGRADE;

CREATE TABLE DEPT (
    DEPTNO int(2) not null ,
	DNAME VARCHAR(14) ,
	LOC VARCHAR(13),
	primary key (DEPTNO)
);

CREATE TABLE EMP (   
    EMPNO int(4)  not null ,
	ENAME VARCHAR(10),
	JOB VARCHAR(9),
	MGR INT(4),
	HIREDATE DATE  DEFAULT NULL,
	SAL DOUBLE(7,2),
	COMM DOUBLE(7,2),
	primary key (EMPNO),
	DEPTNO INT(2) 
);

CREATE TABLE SALGRADE ( 
    GRADE INT,
	LOSAL INT,
	HISAL INT 
);

INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 10, 'ACCOUNTING', 'NEW YORK'); 
INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 20, 'RESEARCH', 'DALLAS'); 
INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 30, 'SALES', 'CHICAGO'); 
INSERT INTO DEPT ( DEPTNO, DNAME, LOC ) VALUES ( 40, 'OPERATIONS', 'BOSTON'); 
 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7369, 'SMITH', 'CLERK', 7902,  '1980-12-17', 800, NULL, 20); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7499, 'ALLEN', 'SALESMAN', 7698,  '1981-02-20', 1600, 300, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7521, 'WARD', 'SALESMAN', 7698,  '1981-02-22', 1250, 500, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7566, 'JONES', 'MANAGER', 7839,  '1981-04-02', 2975, NULL, 20); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7654, 'MARTIN', 'SALESMAN', 7698,  '1981-09-28', 1250, 1400, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7698, 'BLAKE', 'MANAGER', 7839,  '1981-05-01', 2850, NULL, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7782, 'CLARK', 'MANAGER', 7839,  '1981-06-09', 2450, NULL, 10); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7788, 'SCOTT', 'ANALYST', 7566,  '1987-04-19', 3000, NULL, 20); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7839, 'KING', 'PRESIDENT', NULL,  '1981-11-17', 5000, NULL, 10); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7844, 'TURNER', 'SALESMAN', 7698,  '1981-09-08', 1500, 0, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7876, 'ADAMS', 'CLERK', 7788,  '1987-05-23', 1100, NULL, 20); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7900, 'JAMES', 'CLERK', 7698,  '1981-12-03', 950, NULL, 30); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7902, 'FORD', 'ANALYST', 7566,  '1981-12-03', 3000, NULL, 20); 
INSERT INTO EMP ( EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM,DEPTNO ) VALUES ( 7934, 'MILLER', 'CLERK', 7782,  '1982-01-23', 1300, NULL, 10); 
 
INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 1, 700, 1200); 
INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 2, 1201, 1400); 
INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 3, 1401, 2000); 
INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 4, 2001, 3000); 
INSERT INTO SALGRADE ( GRADE, LOSAL, HISAL ) VALUES ( 5, 3001, 9999); 
posted @ 2022-04-22 22:44  Xi-iX  阅读(416)  评论(0编辑  收藏  举报