SQL
SQL用来和数据库打交道,完成和数据库的通信,SQL是一套标准
数据库(DataBase):
通常是一个或一组文件,保存了一些符合特定规格的数据
表(table):
命名规则:小写,单词之间用”_”分割开来
是一种结构化的文件,可以用来存储特定类型的数据
表中的概念:列,行,主键
列叫做字段(Column),行叫做表中的记录,每一个字段都有:
字段名称/字段数据类型/字段约束/字段长度
学生信息表:
学号(主键) | 姓名 | 性别 | 年龄 |
---|---|---|---|
00001 | 张三 | 男 | 20 |
00002 | 李四 | 女 | 20 |
主键是不能重复的
在mysql中语句是不区分大小写的
数据查询语言(DQL-Data Query Language)
代表关键字:select
数据操作语言(DML-Data Manipulation Language)
代表关键字:insert,delete,update
数据定义语言(DDL-Data Definition Language)
代表关键字:create,drop,alter
事务控制语言(TCL-Transaction Control Language)
代表关键字:commit,rollback
数据控制语言(DCL-Data Control Language)
代表关键字:grant,revoke
创建数据库
create database 数据库名称
create database os467test;
use 数据库名称
use os467test;
在数据库中建立表,因此创建表的时候必须要先选择数据库
可以查询当前使用的数据库
select database();
查询数据库版本也可以使用
select version();
终止一条语句,输入ctrl + c
退出mysql
可以使用\q,QUIT或EXIT
显示表
show tables;
基本流程:
1.安装mysql
2.启动mysql
net start mysql
3.登录mysql
mysql -u -p
4.创建数据库
create database 数据库名称;
5.使用数据库
use 数据库名称;
6.创建测试表,添加测试数据
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');
commit;
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);
commit;
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);
commit;
7.关于表的结构
emp员工表
dept部门表
SALGRADE薪水等级表
员工表和部门表的关系是多对一的关系,因为多个员工会对应一个部门
一个部门会对应多个员工;然后现在我们要找到员工表和部门表之间对应的关系
dept 主键 deptno(唯一标识)
emp 主键 empno 外键(通过主键id建立多表关系的字段,一般就是另外一张表的主键id)deptno
列出当前可用数据库:
show databases;
写SQL语句:
1.DQL语句(select)
单表查询
//查询员工表emp所有的数据 , *
通配符,代表所有的数据 from 属于
select * from emp;
查询结果:
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
2.DML语句(增删改 insert(添加) delete(删除) update(修改))
//a:在emp员工表中添加一条员工数据 一般在添加数据的时候,主键在有自动递增的情况下是不用添加的,因为主键我们在设计表的时候给了它自动递增的约束
//into关键字可加可不加
insert into emp(EMPNO,ename,job,mgr,hiredate,sal,comm,deptno)
values(7935,"Tom","CLERK",7698,"1980-12-17",1600.00,1400.00,10);
//删除员工表中姓名为”Tom”的数据
//条件关键字where(在一条sql中只能出现一次)
delete from emp where ename = "Tom";
//修改员工表中SMITH的薪水为850;
update emp set SAL = 850 where ename = "SMITH";
3.带条件查询
//查询一个字段
//查询多个字段
select ename from emp;
+--------+
| ename |
+--------+
| SMITH |
| ALLEN |
| WARD |
| JONES |
| MARTIN |
| BLAKE |
| CLARK |
| SCOTT |
| KING |
| TURNER |
| ADAMS |
| JAMES |
| FORD |
| MILLER |
+--------+
select ename,job from emp;
+--------+-----------+
| ename | job |
+--------+-----------+
| SMITH | CLERK |
| ALLEN | SALESMAN |
| WARD | SALESMAN |
| JONES | MANAGER |
| MARTIN | SALESMAN |
| BLAKE | MANAGER |
| CLARK | MANAGER |
| SCOTT | ANALYST |
| KING | PRESIDENT |
| TURNER | SALESMAN |
| ADAMS | CLERK |
| JAMES | CLERK |
| FORD | ANALYST |
| MILLER | CLERK |
+--------+-----------+
//计算员工的年薪(月薪*12)
select ename,SAL*12 from emp;
+--------+----------+
| ename | SAL*12 |
+--------+----------+
| SMITH | 10200.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
select ename,SAL*12 as '年薪' from emp;
//或者 select ename,SAL*12 '年薪' from emp;
+--------+----------+
| ename | 年薪 |
+--------+----------+
| SMITH | 10200.00 |
| ALLEN | 19200.00 |
| WARD | 15000.00 |
| JONES | 35700.00 |
| MARTIN | 15000.00 |
| BLAKE | 34200.00 |
| CLARK | 29400.00 |
| SCOTT | 36000.00 |
| KING | 60000.00 |
| TURNER | 18000.00 |
| ADAMS | 13200.00 |
| JAMES | 11400.00 |
| FORD | 36000.00 |
| MILLER | 15600.00 |
+--------+----------+
//查询出薪资大于2000的员工
select ename,SAL from emp where SAL > 2000;
+-------+---------+
| ename | SAL |
+-------+---------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| FORD | 3000.00 |
+-------+---------+
Sql语句条件运算符(where后面的)
运算符 | 说明 |
---|---|
= | 等于 |
<>或!= | 不等于 |
< | 小于 |
<= | 小于等于 |
> | 大于 |
>= | 大于等于 |
between … and …. | 两个值之间,等同于 >= and <= (日期比较闭区间,时间戳左闭右开) |
is null | 为null(is not null 不为空) |
and | 并且 |
or | 或者 |
in | 包含,相当于多个or(not in不在这个范围中) |
not | not可以取非,主要用在is 或in中 |
like | like称为模糊查询,支持%或下划线匹配 %匹配任意个字符 下划线,一个下划线只匹配一个字符,”_”代表占位符 |
//部门编号不等于20的员工
select * from emp where deptno != 20;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
//查找薪资大于500小于1000的员工
select * from emp where SAL > 500 and SAL < 1000;
//或 select * from emp where sal between 500 and 1000;
+-------+-------+-------+------+------------+--------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-------+------+------------+--------+------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
+-------+-------+-------+------+------------+--------+------+--------+
//查询出COMM字段不为空的数据
select * from emp where comm is not null;
//查询为空的: select * from emp where comm is null;
+-------+--------+----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+----------+------+------------+---------+---------+--------+
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
+-------+--------+----------+------+------------+---------+---------+--------+
//查询出薪资小于1000或者薪资大于2000的员工
select * from emp where sal < 1000 or sal > 2000;
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
+-------+-------+-----------+------+------------+---------+------+--------+
//in(包含的数据),查询出员工编号是7369、7839、7788的员工 in()
//不包含:not in not in()
select * from emp where empno in (7369,7839,7788);
+-------+-------+-----------+------+------------+---------+------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+-------+-----------+------+------------+---------+------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
+-------+-------+-----------+------+------------+---------+------+--------+
- Like可以实现模糊查询,like支持%和下划线匹配
- 查询姓名以M开头所有的员工
select ename as '员工姓名' from emp where ename like "M%";
+----------+
| 员工姓名 |
+----------+
| MARTIN |
| MILLER |
+----------+
//查询以S结尾的员工姓名
select ename as '员工姓名' from emp where ename like "%S";
+----------+
| 员工姓名 |
+----------+
| JONES |
| ADAMS |
| JAMES |
+----------+
//查询员工姓名中包含O的员工姓名
select ename as '员工姓名' from emp where ename like "%O%";
+----------+
| 员工姓名 |
+----------+
| JONES |
| SCOTT |
| FORD |
+----------+
Field函数
可以指定某一列按照指定顺序排序
SELECT * from tb_user where id in(3,2,5,4)
ORDER BY FIELD(id,6,3,5,1,2,4)
4.排序数据
排序采用order by子句,order by后面跟上排序字段,排序字段可以放多个,多个采用逗号间隔,order by默认采用升序,如果存在where子句那么order by必须放到where语句的后面
//按照薪水由小到大排序 order by 排序关键字 (默认是升序)
注意:order by后面的排序依据字段不加引号
select ename '员工姓名',SAL '薪水' from emp order by SAL asc;//asc为正序关键字可以省略
+----------+---------+
| 员工姓名 | 薪水 |
+----------+---------+
| SMITH | 850.00 |
| JAMES | 950.00 |
| ADAMS | 1100.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| MILLER | 1300.00 |
| TURNER | 1500.00 |
| ALLEN | 1600.00 |
| CLARK | 2450.00 |
| BLAKE | 2850.00 |
| JONES | 2975.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| KING | 5000.00 |
+----------+---------+
select ename '员工姓名',SAL '薪水' from emp order by SAL desc;
//此为倒序排序 使用desc关键字
//查询出薪资大于1000的员工,然后按照薪水降序排列
select ename '员工姓名',SAL '薪水' from emp where SAL > 1000 order by SAL desc;
+----------+---------+
| 员工姓名 | 薪水 |
+----------+---------+
| KING | 5000.00 |
| SCOTT | 3000.00 |
| FORD | 3000.00 |
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| ALLEN | 1600.00 |
| TURNER | 1500.00 |
| MILLER | 1300.00 |
| WARD | 1250.00 |
| MARTIN | 1250.00 |
| ADAMS | 1100.00 |
+----------+---------+
//按照job 和 sal 倒序 (满足前面的条件,再满足后面的条件,排序具有优先级)
select * from emp order by job desc,sal desc;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
+-------+--------+-----------+------+------------+---------+---------+--------+
5.分组函数/聚合函数/多行处理函数
函数 | 作用 |
---|---|
count | 取得记录数 |
sum | 求和 |
avg | 取平均 |
max | 取最大的数 |
min | 取最小的数 |
//统计emp这张表中有多少个员工 count(*) 求一张表中的总记录条数
select count(1) '总记录条数' from emp; //作用一样,但是执行效率高
+------------+
| 总记录条数 |
+------------+
| 14 |
+------------+
mysql> select count(comm) from emp;//统计comm有记录的条数
+-------------+
| count(comm) |
+-------------+
| 4 |
+-------------+
select count(distinct job) '岗位个数' from emp;
//统计岗位个数,distinct关键字起到去重作用
+----------+
| 岗位个数 |
+----------+
| 5 |
+----------+
//取得薪水和津贴的合计,ifnull函数表示将空值用后面的数字替换
select sum(sal+IFNULL(comm,0)) '薪水和津贴的合计' from emp;
+------------------+
| 薪水和津贴的合计 |
+------------------+
| 31275.00 |
+------------------+
//求出员工薪资大于2000的薪资总和
select sum(SAL) '薪资总和' from emp where SAL > 2000;
+----------+
| 薪资总和 |
+----------+
| 19275.00 |
+----------+
//求出薪资小于2000的薪资平均值
select avg(SAL) '薪资平均值' from emp where SAL < 2000;
+-------------+
| 薪资平均值 |
+-------------+
| 1225.000000 |
+-------------+
//求出薪资的最大值,最小值
select max(SAL) '薪资最大值',min(SAL) '薪资最小值' from emp;
+------------+------------+
| 薪资最大值 | 薪资最小值 |
+------------+------------+
| 5000.00 | 850.00 |
+------------+------------+
//组合聚合函数
select count(1),sum(sal),avg(sal),max(sal),min(sal) from emp;
+----------+----------+-------------+----------+----------+
| count(1) | sum(sal) | avg(sal) | max(sal) | min(sal) |
+----------+----------+-------------+----------+----------+
| 14 | 29075.00 | 2076.785714 | 5000.00 | 850.00 |
+----------+----------+-------------+----------+----------+
在SQL中,如果你在SELECT语句中选择了一个非聚合列,并且这个列没有在GROUP BY子句中列出,那么MySQL就会抛出一个错误1。这是因为,当你使用GROUP BY子句时,MySQL需要知道如何对每个组中的每一行进行聚合。对于聚合函数(如AVG()、SUM()、COUNT()等),这很明显,因为它们是对一组值进行操作的。但是,对于非聚合列,MySQL需要知道在每个组中选择哪一行的值,而GROUP BY子句就提供了这个信息。
6.分组查询
group by 关键字
//取得每个工作岗位的工资和,要求显示岗位名称和工资总和,按照薪水的倒序进行排序
select job '岗位',sum(SAL) '薪资总和' from emp group by job order by 薪资总和 desc;
+-----------+----------+
| 岗位 | 薪资总和 |
+-----------+----------+
| MANAGER | 8275.00 |
| ANALYST | 6000.00 |
| SALESMAN | 5600.00 |
| PRESIDENT | 5000.00 |
| CLERK | 4200.00 |
+-----------+----------+
//按照工作岗位和部门编码分组,取得的工资合计
select job '工作岗位',deptNO '部门编码',sum(SAL) from emp group by job,deptNO;
+-----------+----------+----------+
| 工作岗位 | 部门编码 | sum(SAL) |
+-----------+----------+----------+
| ANALYST | 20 | 6000.00 |
| CLERK | 10 | 1300.00 |
| CLERK | 20 | 1950.00 |
| CLERK | 30 | 950.00 |
| MANAGER | 10 | 2450.00 |
| MANAGER | 20 | 2975.00 |
| MANAGER | 30 | 2850.00 |
| PRESIDENT | 10 | 5000.00 |
| SALESMAN | 30 | 5600.00 |
+-----------+----------+----------+
如果有group by 语句,那么在select语句后面只能跟分组函数
+参与分组的字段
having关键字(分组之后的数据再过滤)
如果想对分组数据再进行过滤需要使用having子句
取得每个岗位的平均工资大于2000
select job, avg(sal) from emp group by job having avg(sal) >2000;
+-----------+-------------+
| job | avg(sal) |
+-----------+-------------+
| ANALYST | 3000.000000 |
| MANAGER | 2758.333333 |
| PRESIDENT | 5000.000000 |
+-----------+-------------+
聚合函数不能用在where子句中,可以选择用在having后过滤
select语句总结
一个完整的select语句格式如下
- select 字段
- from 表名
- where …….
- group by ……..
- having …….(就是为了过滤分组后的数据而存在的—不可以单独的出现)
- order by ……..
以上语句的执行顺序
- 首先执行where语句过滤原始数据
- 执行group by进行分组
- 执行having对分组数据进行操作
- 执行select选出数据
- 执行order by排序
原则:能在where中过滤的数据,尽量在where中过滤,效率较高。having的过滤是专门对分组之后的数据进行过滤的。
多表查询:
在项目中,业务是很复杂的,那表与表之间的关系也很复杂,而且以后在公司中我们接触到的表会有几百张或者几千张,在进行多表查询的时候,我们要捋清楚表与表之间的关系
多表查询的时候一定要带条件进行查询,不然会出现笛卡尔积现象!
多表查询语法:
sql92:
emp 主表 找到从表的外键deptno
dept 从表
select * from emp,dept where emp.deptno = dept.deptno;
//映射关系:主表的外键 = 从表的主键
+-------+--------+-----------+------+------------+---------+---------+--------+--------+------------+----------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | DEPTNO | DNAME | LOC |
+-------+--------+-----------+------+------------+---------+---------+--------+--------+------------+----------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | 30 | SALES | CHICAGO |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | 30 | SALES | CHICAGO |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | 30 | SALES | CHICAGO |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | 30 | SALES | CHICAGO |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | 30 | SALES | CHICAGO |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | 30 | SALES | CHICAGO |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | 20 | RESEARCH | DALLAS |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | 10 | ACCOUNTING | NEW YORK |
+-------+--------+-----------+------+------------+---------+---------+--------+--------+------------+----------+
//查询每个员工所对应的部门
select e.ename '员工姓名',d.dname '部门名称' from emp e,dept d where e.deptno = d.deptno;
+----------+------------+
| 员工姓名 | 部门名称 |
+----------+------------+
| SMITH | RESEARCH |
| ALLEN | SALES |
| WARD | SALES |
| JONES | RESEARCH |
| MARTIN | SALES |
| BLAKE | SALES |
| CLARK | ACCOUNTING |
| SCOTT | RESEARCH |
| KING | ACCOUNTING |
| TURNER | SALES |
| ADAMS | RESEARCH |
| JAMES | SALES |
| FORD | RESEARCH |
| MILLER | ACCOUNTING |
+----------+------------+
//显示出薪资大于2000的员工,并显示出每个员工对应的部门(连接查询)
select e.ename '员工姓名',e.SAL '薪水',d.dname '部门' from emp e,dept d where e.deptno = d.deptno and e.sal > 2000;
+----------+---------+------------+
| 员工姓名 | 薪水 | 部门 |
+----------+---------+------------+
| JONES | 2975.00 | RESEARCH |
| BLAKE | 2850.00 | SALES |
| CLARK | 2450.00 | ACCOUNTING |
| SCOTT | 3000.00 | RESEARCH |
| KING | 5000.00 | ACCOUNTING |
| FORD | 3000.00 | RESEARCH |
+----------+---------+------------+
sql99:
内连接
//显示出薪资大于2000的员工,并显示出每个员工对应的部门 inner join 等值连接 (效率高 inner可以不写)
select e.ename '员工姓名' , e.sal '薪水',d.dname '部门'
from emp e
inner join dept d
on e.deptno = d.deptno
where e.sal > 2000;
+----------+---------+------------+
| 员工姓名 | 薪水 | 部门 |
+----------+---------+------------+
| JONES | 2975.00 | RESEARCH |
| BLAKE | 2850.00 | SALES |
| CLARK | 2450.00 | ACCOUNTING |
| SCOTT | 3000.00 | RESEARCH |
| KING | 5000.00 | ACCOUNTING |
| FORD | 3000.00 | RESEARCH |
+----------+---------+------------+
外连接
左外连接 left join
select 查询的数据 from 表1(主表) left join 表2(从表) on 表1的条件 = 表2的条件;
右外连接 right join
select 查询的数据 from 表1(从表) right join 表2(主表) on 表1的条件 = 表2的条件;
在外连接中,主表的数据要求全部显示出来,即使在从表中没用数据与之匹配,那该数据也必须显示出来,从从表中不能匹配的数据用null来代替
//显示员工信息,并显示所属的部门名称,如果某一个部门没有员工,那么该部门也必须显示出来
select e.*,d.dname '部门' from emp e right join dept d on e.deptno = d.deptno;
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO | 部门 |
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 850.00 | NULL | 20 | RESEARCH |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 | SALES |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 | SALES |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 | RESEARCH |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 | SALES |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 | SALES |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 | ACCOUNTING |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 | RESEARCH |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 | ACCOUNTING |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 | SALES |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 | RESEARCH |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 | SALES |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 | RESEARCH |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 | ACCOUNTING |
| NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | OPERATIONS |
+-------+--------+-----------+------+------------+---------+---------+--------+------------+
//查询出所有的员工的薪资以及员工的薪水等级显示每个员工所对应的部门
select
e.ename '员工姓名',e.sal '员工薪资',s.grade '薪水等级',d.dname '所属部门'
from emp e left join dept d
on e.deptno = d.deptno
left join salgrade s
on e.sal between s.losal and s.hisal;
+----------+----------+----------+------------+
| 员工姓名 | 员工薪资 | 薪水等级 | 所属部门 |
+----------+----------+----------+------------+
| SMITH | 850.00 | 1 | RESEARCH |
| ADAMS | 1100.00 | 1 | RESEARCH |
| JAMES | 950.00 | 1 | SALES |
| MILLER | 1300.00 | 2 | ACCOUNTING |
| WARD | 1250.00 | 2 | SALES |
| MARTIN | 1250.00 | 2 | SALES |
| ALLEN | 1600.00 | 3 | SALES |
| TURNER | 1500.00 | 3 | SALES |
| CLARK | 2450.00 | 4 | ACCOUNTING |
| JONES | 2975.00 | 4 | RESEARCH |
| SCOTT | 3000.00 | 4 | RESEARCH |
| FORD | 3000.00 | 4 | RESEARCH |
| BLAKE | 2850.00 | 4 | SALES |
| KING | 5000.00 | 5 | ACCOUNTING |
+----------+----------+----------+------------+
通过子查询的方式查表
//查询出薪水大于平均薪水的员工的薪水
select ename '员工姓名',sal '员工薪水' from emp
where sal > (select avg(e.sal) '平均薪水' from emp e);
+----------+----------+
| 员工姓名 | 员工薪水 |
+----------+----------+
| JONES | 2975.00 |
| BLAKE | 2850.00 |
| CLARK | 2450.00 |
| SCOTT | 3000.00 |
| KING | 5000.00 |
| FORD | 3000.00 |
+----------+----------+
//查询每个工作岗位对应的薪资总和并且降序排序
select e.job '工作岗位',sum(e.sal) '工资合计' from emp e group by e.job order by 工资合计 desc;
+-----------+----------+
| 工作岗位 | 工资合计 |
+-----------+----------+
| MANAGER | 8275.00 |
| ANALYST | 6000.00 |
| SALESMAN | 5600.00 |
| PRESIDENT | 5000.00 |
| CLERK | 4200.00 |
+-----------+----------+
//查询每个员工所对应的领导姓名
select e1.ename '员工姓名',e2.ename '领导姓名' from emp e1
inner join emp e2 on e1.MGR = e2.EMPNO;
+----------+----------+
| 员工姓名 | 领导姓名 |
+----------+----------+
| SMITH | FORD |
| ALLEN | BLAKE |
| WARD | BLAKE |
| JONES | KING |
| MARTIN | BLAKE |
| BLAKE | KING |
| CLARK | KING |
| SCOTT | JONES |
| TURNER | BLAKE |
| ADAMS | SCOTT |
| JAMES | BLAKE |
| FORD | JONES |
| MILLER | CLARK |
+----------+----------+
7.子查询
子查询就是嵌套的select语句,可以理解为子查询是一张表
在where语句中使用子查询,也就是在where语句中加入select语句
//查询每个部门平均薪水所对应的薪水等级
select y.部门名称,s.grade '薪水等级' from
(select d.dname '部门名称',avg(e.sal) '平均薪水' from
emp e left join dept d on e.deptno = d.deptno
group by d.dname) y left join salgrade s on
y.平均薪水 between s.losal and hisal;
+------------+----------+
| 部门名称 | 薪水等级 |
+------------+----------+
| SALES | 3 |
| ACCOUNTING | 4 |
| RESEARCH | 4 |
+------------+----------+
分页:
limit关键字(在sql语句最后面)
select * from emp limit 起始索引位置,分页单位;
1.select * from emp limit 0,3;
2.select * from emp limit 3,3;
3.select * from emp limit 6,3;
起始索引位置:从哪个位置开始查(小标索引是从0开始)
分页单位:查询多少条数据
起始索引位置跟当前页的关系**(平均分页)**:
$$
起始索引位置 = (当前页-1)* 分页单位
$$
//根据分页来查询5-10条的数据
select * from emp limit 4,6;
//查询出每个员工的所属部门,薪水,薪水等级,取到薪资最低的三个员工
select e.ename '员工姓名',d.dname '部门名称',
e.sal '薪水',s.GRADE '薪水等级' FROM
emp e left join dept d on e.DEPTNO = d.DEPTNO
left join salgrade s on e.sal BETWEEN s.LOSAL and s.HISAL
ORDER BY e.SAL LIMIT 0,3;
+----------+----------+---------+----------+
| 员工姓名 | 部门名称 | 薪水 | 薪水等级 |
+----------+----------+---------+----------+
| SMITH | RESEARCH | 850.00 | 1 |
| JAMES | SALES | 950.00 | 1 |
| ADAMS | RESEARCH | 1100.00 | 1 |
+----------+----------+---------+----------+
8.去重Distinct
DISTINCT 用来返回指定字段的不重复的值(删除重复的,只保留一个)
SELECT DISTINCT author_id AS id FROM views WHERE author_id = viewer_id ORDER BY id ASC
直接加在要去重的列前
9.CASE WHEN THEN
SELECT s.sname as '学生',
c.cname as '课程名称'
,sc.score as '考试成绩',
CASE
WHEN
sc.score >= 90 THEN 'A'
WHEN
sc.score >= 80 THEN 'B'
WHEN
sc.score >= 70 THEN 'C'
WHEN
sc.score >= 60 THEN 'D'
ELSE
'不及格'
END
as '考试等级'
FROM course c,student s,score sc
WHERE c.cno = sc.cno AND s.sno = sc.sno
AND class = '计算机一班';
其它用法
SELECT machine_id, round(SUM(CASE WHEN activity_type = 'end' THEN timestamp ELSE -timestamp END) / COUNT(DISTINCT process_id),3) AS processing_time FROM activity GROUP BY machine_id
SELECT a1.user_id, round(SUM(CASE WHEN action = 'confirmed' THEN 1 ELSE 0 END) / COUNT(*),2) AS confirmation_rate FROM signups a1 LEFT JOIN confirmations a2 ON a1.user_id = a2.user_id GROUP BY a1.user_id
CASE WHEN THEN 类似编程中的if else
但是一旦满足对应的WHEN 那么立即返回 THEN的内容,不再判断下面的WHEN。
如果不满足WHEN的条件才会继续向下判断。
10.EXISTS 和 NOT EXISTS
exists一般会配合子查询使用,如果查询结果集非空,则exists成立
如果是not exists 则只有在结果集为空时才成立
SELECT a1.product_id, product_name FROM product a1 LEFT JOIN sales a2 ON a1.product_id = a2.product_id
WHERE
EXISTS (SELECT sale_date FROM sales WHERE sales.product_id = a1.product_id) AND NOT EXISTS (SELECT sale_date FROM sales WHERE sales.product_id = a1.product_id AND (sale_date < '2019-01-01' OR sale_date > '2019-03-31'))
GROUP BY product_id
11.UNION 和 UNION ALL
UNION 操作符用于合并两个或多个 SELECT 语句的结果集
UNION 内部的 SELECT 语句必须拥有相同数量的列,列也必须拥有相似的数据类型,同时,每条 SELECT 语句中的列的顺序必须相同
UNION
和UNION ALL
的区别是,UNION
会自动压缩多个结果集合中的重复结果,而UNION ALL
则将所有的结果全部显示出来,不管是不是重复
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序
SELECT employee_id , department_id FROM employee GROUP BY employee_id HAVING COUNT(department_id) = 1
UNION
SELECT employee_id , department_id FROM employee WHERE primary_flag = 'Y'
自定义变量
自定义变量可以起到优化查询语句的作用,如下面使用一个变量来累计weight值
SELECT person_name FROM
(SELECT person_name,@p := @p + weight AS weight FROM queue,(SELECT @p := 0) tmp ORDER BY turn) a1 WHERE
weight <= 1000 ORDER BY weight DESC LIMIT 1
存储过程
SQL语句需要先编译然后执行,而存储过程(Stored Procedure)是一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给定参数(如果该存储过程带有参数)来调用执行它。
存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和控制结构组成。当想要在不同的应用程序或平台上执行相同的函数,或者封装特定功能时,存储过程是非常有用的。数据库中的存储过程可以看做是对编程中面向对象方法的模拟,它允许控制数据的访问方式。
优点
存储过程可封装,并隐藏复杂的商业逻辑。
存储过程可以回传值,并可以接受参数。
存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
存储过程可以用在数据检验,强制实行商业逻辑等。
缺点
存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。
存储过程的性能调校与撰写,受限于各种数据库系统。
/*删除存储过程*/
DROP PROCEDURE IF EXISTS stuscoreinfo;
/*创建一个存储过程*/
CREATE PROCEDURE stuscoreinfo()
BEGIN
SELECT s.class, s.sno, s.sname, s.sex, c.cname, sc.score
FROM student s
JOIN score sc ON s.sno = sc.sno
JOIN course c ON c.cno = sc.cno;
END
/*运行存储过程*/
CALL stuscoreinfo();
带参数
DROP PROCEDURE IF EXISTS stu_info;
/*创建一个存储过程*/
CREATE PROCEDURE stu_info(IN stu_id INT)
BEGIN
SELECT * FROM student WHERE sno = stu_id;
END;
/*运行存储过程*/
CALL stu_info(1);
带返回值
DROP PROCEDURE IF EXISTS stu_age;
/*创建一个存储过程*/
CREATE PROCEDURE stu_age(IN stu_id INT, OUT result INT)
BEGIN
BEGIN
GET DIAGNOSTICS CONDITION 1 @sqlstate = RETURNED_SQLSTATE, @errno = MYSQL_ERRNO;
SET result = @errno;
END;
SELECT age INTO result
FROM student
WHERE sno = stu_id;
IF result IS NOT NULL THEN
SET result = 0;
END IF;
END;
CALL stu_age(1,@result);
SELECT @result;
用户自定义函数
求班级课程平均分
DROP FUNCTION IF EXISTS fun_avgscores;
/*用户自定义函数*/
CREATE FUNCTION fun_avgscores(class VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci , cno INT) RETURNS FLOAT
BEGIN
DECLARE avg_score FLOAT;
SELECT AVG(score) INTO avg_score
FROM score sc,student s
WHERE s.class = class AND sc.cno = cno
AND sc.sno = s.sno;
RETURN avg_score;
END;
/*执行函数*/
SELECT s.class as '班级',sc.cno as '课程号',fun_avgscores(s.class, sc.cno) as '平均分'
FROM score sc,student s GROUP BY s.class,sc.cno;
常用函数
isnull()
isnull() 和 is null区别
ISNULL()函数是用于替换NULL值的,而IS NULL运算符是用于判断一个值是否为NULL的
在写 SQL 条件语句时经常用到 不等于
!=
的筛选条件。此时要注意此条件会将字段为Null
的数据也当做满足不等于的条件而将数据筛选掉。(也就是说会忽略过滤掉为 null 的数据,导致数据不准确)。
字符串
length(str)
获取字符串长度
concat(str1,str2,str3)
拼接字符串
upper(expression)
大写
lower(expression)
小写
substring(column name,index,length)
index从1开始,截取子串
round(1.3211,2)
保留小数点后2位
if(条件,ret1,ret2)
类似三元表达式,true返回ret1,false返回ret2
大数据量情况下case when then效率高一点
日期操作
date_sub(date, INTERVAL 1 day)
获取date的前一天
date_add(w1.recordDate, INTERVAL 1 day)
获取date的后一天
日期操作不要用
+-
号
日期格式化
date_format(date,'%Y-%m-%d')
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com