表的增删查改
CURD:create retrieve update delete 增删查改
create :
insert [INTO] table_name[(column [, column] ... )] values (value_list)[,(value_list)]... value_list : value [, value]...
单行全列插入可以不在table name 后指明column,但是我们建议不要省略。
多行插入可以用逗号隔开。
在unique 和 primary key 中,要求不能重复。 所以如果我们想修改主键/unique 的时候,可以直接
insert into test (id, ...) values (1, ...) on duplicate key update id=1;
如果没冲突,那就执行前面的语句,一行被影响(新增一行)。如果冲突了,那就按update 后面进行修改。这时候会发现有两行被影响,这是因为冲突了是一次影响,冲突后的修改又是一次影响。
Replace
-
主键或者唯一键没有冲突,就直接插入。
-
主键或者唯一键冲突了,删除后再插入。
REPLACE INTO students (sn, name) values (20001, 'amor'); -- 1 row affected; 表中没有冲突数据,数据被插入 -- 2 row affected; 表中有冲突数据,删除后又被重新插入
Retrieve
SELECT [DISTINCT] {* | {column [, column] ... } [FROM TALBE_NAME] [WHERE ...] [ORDER BY column [ASC | DESC], ...] LIMIT ...
-
通常情况下不建议使用 * 进行全列查询。支持按列查询,将想要查询的列名 放在* 位置处即可。可以修改查询列的顺序。
-
select 在查询时,可以添加在表达式中不存在的字段,比如10 比如 10+ 10(应该是一个表达式,一个可以计算的式子),可以对字段进行乘除加减。就比如:
select id, name, chinese+10 from test; -- 甚至还可以修改这个名字 select id, name, chinese+english+math as 'total grade' from test;
但是只是对筛选的结果做修改,不会修改原数据。
-
选项 distinct ,表示去重
select distinct math, id from exam_table;
对整个的行进行去重,如果输出很多行,要全部都相同才会被筛选删去。
-
排序 order by:
select id, name, chinese+english+math as 'total grade' from test order by total grade; -- 默认升序 select id, name, chinese+english+math as 'total grade' from test order by total grade desc; -- 加desc 降序 -- 加asc 升序(default) -- NULL 虽然不参与计算,但是在排序中如果升序会放到最前面。 -- NULL 视为比任何值都笑,升序会出现在最上面。
如果同时按照多个方法排序,会先按照最前面的排序,如果前面的字段相等,看后面,比如:
select * from test order by math desc, chinese asc, english asc;
-
WHERE 条件:
可以加 >= / > / = / <= / < 来限制输出条件
select id,name,math from exam_result where math>=80;
如果要找到NULL,不能用 = 比较,而是用<=> 比较 或者IS (NOT)NULL 来筛选。
-
where + between and 来查找在范围中的字段
select name,math from exam_result where math bewtween 70 and 80; select name,math from exam_result where math >= 70 and math<=80; -- where 可以用 and / or / not
-
Where + in(option, ...) 来查找含有option 的字段
select name,math from exam_result where math in(70,75,80,85); -- 等价于 select name,math from exam_result where math = 70 or math = 75 or math = 80 or math =85;
-
where + like '' + % 代表任意多个字符, + _ 代表一个字符
select name,math from exam_result where name like '孙%'; -- 所有姓孙的 select name,math from exam_result where name like '孙_'; -- 叫孙某的 就是孙一一 三个字的不算
-
select 的查询首先按照条件筛选数据,再按照要求计算数据,所以我们不能用起的别名来约束后面的的where 比如:
select name, chinese+english+math as total_grade from exam_result wherechinese+english+math < 200 -- 如果写成 : where total_grade < 200 就会不识别
但是order by 就可以使用total_grade。
这是因为排序时已经把数据全部都根据条件筛选完了。
排序的本质就是计算。
根据上述,要对于mysql 各个子句的执行顺序有刻意的练习。
条件可以很多同时筛选,用( ) 加 and / or 分隔开。
-
limit n 代表只显示前n 行,顺序在最后。
-
offset n 配合limit m 使用,可以分页面显示。
-
在select 中使用group by子句可以对指定列进行分组查询:
select column1, column2, ... from table group by column;
having 和group by 相配合,这里的用法与where 完全类似, 根本原因在于二者的执行位置的次序不同。
-
where 是过滤表中的数据的。(先where 筛选,再group by)
-
having 是过滤分组数据的。(先分组,先group by -> having)
-
所以二者不会冲突,不过要按照他们执行的顺序来排列,如下:
select deptno, avg(sal),count(*) from emp where deptno!=10 group by deptno havingavg(sal) < 2000;
实际顺序是:where 过滤 -> 聚合语句 -> group by 分组 -> having
-
Update
update exam_result set math=math+30 order by math+english+chinese asc limit 3; -- 将三科成绩倒数前三名的数学成绩加上30分
注意:更新全表的语句慎用!
delete
-
删除表的数据:
delete from table_name;
删除表的数据,但是注意,删除之后,自增的序号仍然从原来的序号开始。比如自增的id 已经有了1,2,3,4,那么此时删除表的数据,再插入,id = 5;
-
截断表:
TRUNCATE [TABLE] table_name;
操作慎用:
只能对整个表操作,不能像delete 那样针对部分数据操作。
实际上不对数据操作,所以比delete 更快,但是TRUNCATE 在删除数据的时候,并不经过真正的事物,所以无法回滚。
会重置AUTO_INCREMENT 项。
delete 和 truncate 清空的区别:
日志:承担很大的功能要求,分为:
-
bin log:几乎所有的sql操作,mysqld 服务器都会给我们记录下来,该log 用来进行多主机同步,再增量备份
-
redo log :mysql 数据持久化 和crash-safe 功能(不怕崩溃,崩溃不影响mysql 的正常功能)
-
undo log:在事务中承担回滚的日志,数据操作恢复功能。
delete 清空会更新日志,truncate 清空不会更新日志。
复制表(去重)
比如我们先建立一个表,然后使用如下命令,就可以复制创建属性。
create table newTable like oldTtable;
去重操作:
select distinct * from oldTable; -- 挑出来不重复的 insert into newTable select distinct * from oldTable; -- 直接插入
如果想保留去重后的表:
rename table oldTable to oldTable_old; rename table newTable to oldTable;
聚合函数
将一个表中的多行进行聚合。
-
count,比如我们使用count 函数统计人数,可以使用:
select count(*) 人数 from table_name;
去重之后再统计:
select count(distinct math) from exam_result;
-
sum
-
max/min
-
avg
-
聚合函数和其他的字段显示可能不对应,现在不处理。
内置函数
内置函数不需要表,统一使用select 调用。
-
日期函数:
Current_date() 描述当前日期
Current_time() 描述当前时间
Current_timestamp() 描述当前时间戳
Date(datetime) 返回datetime 参数的日期部分
date_add(date, interval d_value_type) 在date 中添加日期或者时间,interval 后的数值单位可以是:year minute second day.
Date_sub (date, interval d_value_type) 在date 中减去日期或者时间,interval 后的数值单位可以是:year minute second day.
datediff(date1, date2) 描述两个日期的差,单位是天
now(), 描述当前日期的时间。
可以创建timestamp 的字段来完成自动更新时间的操作。
可以使用 评论时间+ 2min > now() 来筛选两分钟内的评论。但是时间不能直接加两分钟,就需要使用date_add。
select * from table_name where date_add(sendtime, interval 2 minute) >= now();
-
字符串函数
名 作用 Charset(str) 返回字符串字符集 concat(string2 [, ...]) 连接字符串 instr(string, substring) 返回substring 在string 中出现的位置,没有则返回0 Ucase(string2) 转换成大写 lcase(string2) 转换成小写 left(string2, length) 从string2 中的左边起取length 个字符 length(string) string 的长度(字节数) replace(str, search_str, replace_str) 在str 中用replace_str 替换search_str strcmp(string1, string2) 逐字符比较两个字符串的大小 substring(str, position [,length]) 从str 的position 开始,取length 个字符 ltrim(string) / rtrim(string) / trim(string) 去掉前空格或者后空格 举例:
-
获取emp 表的name 列字符集
select charset(name) from EMP;
-
显示student 表中的信息,显示格式是:"XXX的语文是XXX分,数学XXX分,英语XXX分"
select concat(name, '的语文是',chinese,'分,数学是',math,'分,英语是',english,'分') as'grade' from student;
-
-
数学函数
函数名称 描述 abs(number) 绝对值函数 Bin(decimal_number) 十进制转换二进制 hex(decimal_number) 转换成十六进制 Conv(number, from_base, to_base) 进制转换 Ceiling(number) 向上取整 向正无穷的方向取整 Floor(number) 向下取整 Format(number, decimal_places) 格式化,保留小数位数 Rand() 返回随机浮点数,范围[0.0 , 1.0) mod(number, denominator) 取模,求余 -
其他函数
名称 描述 user() 哪个用户 Md5(str) 形成定长摘要 password() 形成密码 ifnull(val1, val2) 有点像三目运算符,val1不为空,返回val1,val1 为空,返回val2
复合查询
-
找出工资大于500 或者 岗位为MANAGER的雇员,同时满足名字首字母为J
from emp where (sal > 500 or job ='MANAGER') and substring('ename,1,1); -- or from emp where (sal > 500 or job ='MANAGER') and ename like 'J%';
-
显示工资最高的员工的名字和工作岗位
select ename,job from emp where sal=(select max(sal) from emp);
-
显示工资高于平均工资的员工信息;
select * from emp where sal>(select avg(sal) from emp);
-
显示平均工资低于2000 的部门号和他的平均工资
select deptno, format(avg(sal) ,2)from emp group by deptno having avg(sal) < 2000;
顺序:因为我们判断的是平均工资低于2000,平均工资是聚合条件,所以我们应该先分组然后判断,判断用having。
-
显示每种岗位的雇员总数和平均工资。
select job, count(*), avg(sal) from emp group by job;
多表查询
如果我们使用from 用逗号连接多个表,不加过滤条件得到的结果是的是两个表的笛卡尔积,意思是从第一张表中选出第一条记录,和第二张表中的每一行组合,然后从第一张表的第二条记录继续。
select * from EMP, DEPT;
我们可以把多个表合成一表,所以在心中永远都是只有一张表。所以多表查询,本质上都是单表查询。
我们认为,所有select 查询出来的记录,都可以把它看作一个表。
-
显示雇员名、雇员工资以及所在部门的名字
我们知道雇员名和雇员的工资是在emp 表中,部门的名字在dept 表中,二者通过外键 deptno 联系起来。我们需要做的就是建立一张大表,如下。
select * from emp, dept;
+--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+ | empno | ename | job | mgr | hiredate | sal | comm | deptno | deptno | dname | loc | +--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+ | 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20| 40 | OPERATIONS | BOSTON | | 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20| 30 | SALES | CHICAGO | | 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20| 20 | RESEARCH | DALLAS | | 007369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | NULL | 20| 10 | ACCOUNTING | NEW YORK | | 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30| 40 | OPERATIONS | BOSTON | | 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30| 30 | SALES | CHICAGO | | 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30| 20 | RESEARCH | DALLAS | | 007499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30| 10 | ACCOUNTING | NEW YORK | | 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30| 40 | OPERATIONS | BOSTON | | 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30| 30 | SALES | CHICAGO | | 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30| 20 | RESEARCH | DALLAS | | 007521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30| 10 | ACCOUNTING | NEW YORK | | 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20| 40 | OPERATIONS | BOSTON | | 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20| 30 | SALES | CHICAGO | | 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20| 20 | RESEARCH | DALLAS | | 007566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | NULL | 20| 10 | ACCOUNTING | NEW YORK | | 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30| 40 | OPERATIONS | BOSTON | | 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30| 30 | SALES | CHICAGO | | 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30| 20 | RESEARCH | DALLAS | | 007654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30| 10 | ACCOUNTING | NEW YORK | | 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30| 40 | OPERATIONS | BOSTON | | 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30| 30 | SALES | CHICAGO | | 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30| 20 | RESEARCH | DALLAS | | 007698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | NULL | 30| 10 | ACCOUNTING | NEW YORK | | 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10| 40 | OPERATIONS | BOSTON | | 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10| 30 | SALES | CHICAGO | | 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10| 20 | RESEARCH | DALLAS | | 007782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | NULL | 10| 10 | ACCOUNTING | NEW YORK | | 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20| 40 | OPERATIONS | BOSTON | | 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20| 30 | SALES | CHICAGO | | 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20| 20 | RESEARCH | DALLAS | | 007788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | NULL | 20| 10 | ACCOUNTING | NEW YORK | | 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10| 40 | OPERATIONS | BOSTON | | 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10| 30 | SALES | CHICAGO | | 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10| 20 | RESEARCH | DALLAS | | 007839 | KING | PRESIDENT | NULL | 1981-11-17 00:00:00 | 5000.00 | NULL | 10| 10 | ACCOUNTING | NEW YORK | | 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30| 40 | OPERATIONS | BOSTON | | 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30| 30 | SALES | CHICAGO | | 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30| 20 | RESEARCH | DALLAS | | 007844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30| 10 | ACCOUNTING | NEW YORK | | 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20| 40 | OPERATIONS | BOSTON | | 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20| 30 | SALES | CHICAGO | | 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20| 20 | RESEARCH | DALLAS | | 007876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | NULL | 20| 10 | ACCOUNTING | NEW YORK | | 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30| 40 | OPERATIONS | BOSTON | | 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30| 30 | SALES | CHICAGO | | 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30| 20 | RESEARCH | DALLAS | | 007900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | NULL | 30| 10 | ACCOUNTING | NEW YORK | | 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20| 40 | OPERATIONS | BOSTON | | 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20| 30 | SALES | CHICAGO | | 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20| 20 | RESEARCH | DALLAS | | 007902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | NULL | 20| 10 | ACCOUNTING | NEW YORK | | 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10| 40 | OPERATIONS | BOSTON | | 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10| 30 | SALES | CHICAGO | | 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10| 20 | RESEARCH | DALLAS | | 007934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | NULL | 10| 10 | ACCOUNTING | NEW YORK | +--------+--------+-----------+------+---------------------+---------+---------+--------+--------+------------+----------+
但是可以发现结果中 deptno 和后面的deptno 如果不想等,就根本毫无意义。所以我们需要做的就是加上一个限制条件,不过限制条件如果写 where deptno = deptno,mysql 根本无法识别,那需要加上前缀:
select * from emp,dept where emp.deptno=dept.deptno;
我们要的是雇员名,雇员工资以及所在部门的名字:
select ename,sal,dname from emp, dept where emp.deptno=dept.deptno;
-
显示各个员工的姓名、工资及工资级别
select * from emp,salgrade where emp.sal > salgrade.losal and emp.sal < salgrade.hisalorder by salgrade.grade;
但是因为现在 sal 和 hisal losal 都不重复,所以可以不用带上emp. salgrade.
-
显示员工FORD 上级领导的编号和姓名
select empno, ename from emp where empno=(select mgr from emp where ename='FORD'); select leader.ename, leader.empno from emp worker,emp leader where worker.ename='FORD'and worker.mgr=leader.empno;
子查询
单行字查询是指的是字查询只返回单列,单行数据;多行字查询指的是返回单列多行数据,都是针对单列而言。
-
in关键字:用来查询其中的一员
查询和10号部门的工作岗位相同的雇员名字,岗位,工资,部门号,但是不包含10号自己的。
select ename,job,sal,deptno from emp where job in (select distinct job from emp wheredeptno=10) and deptno!=10;
-
all 关键字:我比你们所有字段都要XXX
显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号。
select ename,sal,deptno from emp where sal>(select max(distinct sal) from emp wheredeptno=30); --2-- select ename,sal,deptno from emp where sal> all(select distinct sal from emp wheredeptno=30);
-
any 关键字:比任意一个字段XXX
显示工资比部门30 的任意员工的工资高的员工的姓名、工资和部门号(包括自己部门的员工)。
select ename,sal,deptno from emp where sal > any(select sal from emp where deptno=30)order by sal;
多列子查询指的是查询返回多个列数据的子查询语句。
-
查询和SMITH 的部门和岗位完全相同的所有雇员,不含SMITH 本人。
select * from emp where (ename != 'SMITH') and (job=(select job from emp where ename='SMITH')) and (deptno=(select deptno from emp where ename='SMITH')); --2-- select * from emp where (ename != 'SMITH') and (deptno,job)=(select deptno,job from emp where ename='SMITH');
用from
因为我们说可以把一条select 语句看成一个表,所以我们可以在from 后加select语句。
-
显示每个高于自己部门平均工资的员工的姓名,部门,工资和平均工资。
--平均工资 select deptno, avg(sal) avg from emp group by deptno; --高于自己部门的平均工资: select ename,emp.deptno,sal,avg from emp,(select deptno, avg(sal) avg from emp group bydeptno) avg_dept where emp.deptno=avg_dept.deptno and emp.sal>avg_dept.avg;
-
查找每个部门工资最高的人的姓名、工资、部门和最高工资。
-- 每个部门的最高工资 select deptno, max(sal) from emp group by deptno; -- 找出最高工资的人的姓名和工资部门 select ename, sal, emp.deptno, max_sal from emp, (select deptno, max(sal) max_sal fromemp group by deptno) maxsal_dept where emp.deptno=maxsal_dept.deptno and sal=max_sal;
-
显示每个部门的信息(部门名、编号、地址)和人员数量
-- 部门名dname 部门编号deptno 部门地址loc 都在 dept表中 -- 人员的数量可以使用count 统计,在dept中。 -- 二表通过相同的deptno 来进行统一。 select dname, dept.deptno, loc, count from dept, (select deptno, count(*) count fromemp group by deptno) cnt_tb where dept.deptno=cnt_tb.deptno;
合并查询
-
union 取并集,会自动去重
select ... union select ...;
-
union all 取并集,不会去重
表的内外连接
表的连接分为内连和外连。
内连接
内连接实际上就是利用where 子句对两种表形成的笛卡尔积进行筛选,我们前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。
select 字段 from table1 inner join table2 on 连接条件 and 其他条件;
-
显示SMITH 的名字和部门名称
select * from emp, dept where emp.deptno=dept.deptno and ename='SMITH'; select * from emp inner join dept on emp.deptno=dept.deptno where ename='SMITH';
外连接
-
左外连接: 将inner 换成left
select * from table1 left join table2 on ...
就是把 table1 放到 table2 的后面,如果找得到对应的table2 的数据,就拼到table1 的右边,否则就拼NULL
-
右外连接:inner 换成right
示例
-
列出部门名称和这些部门的员工信息和没有员工的部门
select * from dept left join emp on dept.deptno=emp.deptno;