ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'this0' at line 1
(5)重名
同一个mysql软件中,数据库不能同名,同一个库中,表不能重名,同一个表中,字段不能重名
1 2 3 4 5 6 7 8 9 10 11 12 13 14
mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | buxianxiandb | | mysql | | performance_schema | | sys | +--------------------+ 5 rows in set (0.00 sec)
mysql> select * from student; +------+------+ | id | name | +------+------+ | 1 | 张三 | | 2 | 李四 | +------+------+ 2 rows in set(0.00 sec)
mysql> select id "学号",name "姓名" from student; +------+------+ | 学号 | 姓名 | +------+------+ | 1 | 张三 | | 2 | 李四 | +------+------+ 2 rows in set(0.00 sec)
mysql> select id 学号,name 姓名 from student; +------+------+ | 学号 | 姓名 | +------+------+ | 1 | 张三 | | 2 | 李四 | +------+------+ 2 rows in set(0.00 sec)
mysql> select id 学 号,name 姓 名 from student; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use n ear '号,name 姓 名 from student' at line 1
#查询薪资正好是9000的员工姓名和薪资 select ename,salary from t_employee where salary = 9000; select ename,salary from t_employee where salary == 9000;#错误,不支持== #注意Java中判断用==,mysql判断用=
mysql> select ename,salary from t_employee where salary == 9000; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '== 9000' at line 1 #查询籍贯native_place不是北京的 select * from t_employee where native_place != '北京'; select * from t_employee where native_place <> '北京';
#查询员工表中部门编号不是1 select * from t_employee where did != 1; select * from t_employee where did <> 1;
#查询奖金比例是NULL select * from t_employee where commission_pct = null;
mysql> select * from t_employee where commission_pct = null; #无法用=null判断 Empty set (0.00 sec) #mysql中只要有null值参与运算和比较,结果就是null,底层就是0,表示条件不成立。
#查询奖金比例是NULL select * from t_employee where commission_pct <=> null; select * from t_employee where commission_pct is null;
#查询“李冰冰”、“周旭飞”、“李易峰”这几个员工的信息 select * from t_employee where ename in ('李冰冰','周旭飞','李易峰');
#查询部门编号为2、3的员工信息 select * from t_employee where did in(2,3);
#查询部门编号不是2、3的员工信息 select * from t_employee where did not in(2,3);
#查询薪资在[10000,15000]之间 select * from t_employee where salary between 10000 and 15000;
#查询姓名中第二个字是'冰'的员工 select * from t_employee where ename like '冰'; #这么写等价于 ename='冰' select * from t_employee where ename like '_冰%'; #这么写匹配的是第二个字是冰,后面可能没有第三个字,或者有好几个字
update t_employee set ename = '王冰' where ename = '李冰冰';
select * from t_employee where ename like '_冰_'; #这么写匹配的是第二个字是冰,后面有第三个字,且只有三个字
#查询员工的姓名、薪资、奖金比例、实发工资 #实发工资 = 薪资 + 薪资 * 奖金比例 select ename as 姓名, salary as 薪资, commission_pct as 奖金比例, salary + salary * commission_pct as 实发工资 from t_employee;
#NULL在mysql中比较和计算都有特殊性,所有的计算遇到的null都是null。 #实发工资 = 薪资 + 薪资 * 奖金比例 select ename as 姓名, salary as 薪资, commission_pct as 奖金比例, salary + salary * ifnull(commission_pct,0) as 实发工资 from t_employee;
实发工资 = 薪资 + 薪资 * 奖金比例 select ename as 姓名, salary as 薪资, commission_pct as 奖金比例, salary + salary * ifnull(commission_pct,0) as 实发工资 from t_employee;
3. 区间或集合范围比较运算符(掌握)
1 2 3 4
区间范围:between x and y [x,y] not between x and y 集合范围:in (x,x,x) not in(x,x,x)
1 2 3 4 5 6 7 8 9 10 11 12
#查询薪资在[10000,15000] select * from t_employee where salary>=10000 && salary<=15000; select * from t_employee where salary between 10000 and 15000;
#查询籍贯在这几个地方的 select * from t_employee where native_place in ('北京', '浙江', '江西');
#查询薪资不在[10000,15000] select * from t_employee where salary not between 10000 and 15000;
#查询籍贯不在这几个地方的 select * from t_employee where native_place not in ('北京', '浙江', '江西');
4. 模糊匹配比较运算符(掌握)
%:代表任意个字符
_:代表一个字符,如果两个下划线代表两个字符
1 2 3 4 5 6 7 8 9 10 11
#查询名字中包含'冰'字 select * from t_employee where ename like '%冰%';
#查询名字以‘雷'结尾的 select * from t_employee where ename like '%雷';
#查询名字以’李'开头 select * from t_employee where ename like '李%';
#查询名字有冰这个字,但是冰的前面只能有1个字 select * from t_employee where ename like '_冰%';
1 2
#查询当前mysql数据库的字符集情况 show variables like '%character%';
#查询当前mysql数据库的字符集情况 show variables like ‘%character%’;
5 .逻辑运算符(掌握)
1 2 3 4
逻辑与:&& 或 and 逻辑或:|| 或 or 逻辑非:! 或 not 逻辑异或: xor
逻辑异或: xor select * from t_employee where salary>15000 & gender=’男’;#错误 &按位与 select * from t_employee where (salary>15000) && (gender=’男’); #查询薪资高于15000,或者did为1的员工,两者只能满足其一 select * from t_employee where salary>15000 xor did = 1; select * from t_employee where (salary>15000) ^ (did = 1);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
#查询薪资高于15000,并且性别是男的员工 select * from t_employee where salary>15000 and gender='男'; select * from t_employee where salary>15000 && gender='男';
select * from t_employee where salary>15000 & gender='男';#错误 &按位与 select * from t_employee where (salary>15000) & (gender='男');
#查询薪资高于15000,或者did为1的员工 select * from t_employee where salary>15000 or did = 1; select * from t_employee where salary>15000 || did = 1;
#查询薪资不在[15000,20000]范围的 select * from t_employee where salary not between 15000 and 20000; select * from t_employee where !(salary between 15000 and 20000);
#查询薪资高于15000,或者did为1的员工,两者只能满足其一 select * from t_employee where salary>15000 xor did = 1; select * from t_employee where (salary>15000) ^ (did = 1);
6.关于null值的问题(掌握)
#(1)判断时 xx is null xx is not null xx <=> null
#(2)计算时 ifnull(xx,代替值) 当xx是null时,用代替值计算
1 2 3 4 5 6 7
#(1)判断时 xx is null xx is not null xx <=> null
#(2)计算时 ifnull(xx,代替值) 当xx是null时,用代替值计算
1 2 3 4 5 6 7
#查询奖金比例为null的员工 select * from t_employee where commission_pct = null; #失败 select * from t_employee where commission_pct = NULL; #失败 select * from t_employee where commission_pct = 'NULL'; #失败
select * from t_employee where commission_pct is null; #成功 select * from t_employee where commission_pct <=> null; #成功 <=>安全等于
-- 用户表 CREATE TABLE t_user ( id int(11) NOT NULL AUTO_INCREMENT, uname varchar(40) DEFAULT NULL, age int(11) DEFAULT NULL, sex int(11) DEFAULT NULL, PRIMARY KEY (id) );
insert into t_user values (null,'zs',18,1); insert into t_user values (null,'ls',20,0); insert into t_user values (null,'ww',23,1); insert into t_user values (null,'zl',24,1); insert into t_user values (null,'lq',15,0); insert into t_user values (null,'hh',12,0); insert into t_user values (null,'wzx',60,null); insert into t_user values (null,'lb',null,null);
-- 用户表 CREATE TABLE t_user ( id INT(11) NOT NULL AUTO_INCREMENT, uname VARCHAR(40) DEFAULTNULL, age INT(11) DEFAULTNULL, sex INT(11) DEFAULTNULL, PRIMARY KEY (id) );
INSERT INTO t_user VALUES (NULL,'zs',18,1); INSERT INTO t_user VALUES (NULL,'ls',20,0); INSERT INTO t_user VALUES (NULL,'ww',23,1); INSERT INTO t_user VALUES (NULL,'zl',24,1); INSERT INTO t_user VALUES (NULL,'lq',15,0); INSERT INTO t_user VALUES (NULL,'hh',12,0); INSERT INTO t_user VALUES (NULL,'wzx',60,NULL); INSERT INTO t_user VALUES (NULL,'lb',NULL,NULL);
#找出t_employee表中最高的薪资值 SELECTMAX(salary) FROM t_employee;
#找出t_employee表中最低的薪资值 SELECTMIN(salary) FROM t_employee;
#统计t_employee表中平均薪资值 SELECTAVG(salary) FROM t_employee;
#统计所有人的薪资总和,财务想看一下,一个月要准备多少钱发工资 SELECTSUM(salary) FROM t_employee; #没有考虑奖金 #运算符和null运算为null,如果不加IFNULL(commission_pct,0),当commission_pac为null时,不管salary为多少,整体结果都为null SELECTSUM(salary+salary*IFNULL(commission_pct,0)) FROM t_employee;
#找出年龄最小、最大的员工的出生日期 SELECTMAX(birthday),MIN(birthday) FROM t_employee;
#查询最新入职的员工的入职日期 SELECTMAX(hiredate) FROM t_employee;
#(1)在“t_employee”表中查询薪资在[8000,10000]之间的员工姓名和薪资并给每一行记录编序号 SELECT ROW_NUMBER() OVER () AS "row_num",ename,salary FROM t_employee WHERE salary BETWEEN 8000 AND 10000;
#(2)计算每一个部门的平均薪资与全公司的平均薪资的差值。 SELECT did,AVG(salary) OVER() AS avg_all, AVG(salary) OVER(PARTITION BY did) AS avg_did, ROUND(AVG(salary) OVER()-AVG(salary) OVER(PARTITION BY did),2) AS deviation FROM t_employee;
#(3)在“t_employee”表中查询女员工姓名,部门编号,薪资,查询结果按照部门编号分组后在按薪资升序排列,并分别使用ROW_NUMBER()、RANK()、DENSE_RANK()三个序号函数给每一行记录编序号。 SELECT ename,did,salary,gender, ROW_NUMBER() OVER (PARTITION BY did ORDER BY salary) AS "row_num", RANK() OVER (PARTITION BY did ORDER BY salary) AS "rank_num" , DENSE_RANK() OVER (PARTITION BY did ORDER BY salary) AS "ds_rank_num" FROM t_employee WHERE gender='女';
#或
SELECT ename,did,salary, ROW_NUMBER() OVER w AS "row_num", RANK() OVER w AS "rank_num" , DENSE_RANK() OVER w AS "ds_rank_num" FROM t_employee WHERE gender='女' WINDOW w AS (PARTITION BY did ORDER BY salary);
#(4)在“t_employee”表中查询每个部门最低3个薪资值的女员工姓名,部门编号,薪资值。 SELECT ROW_NUMBER() OVER () AS "rn",temp.* FROM(SELECT ename,did,salary, ROW_NUMBER() OVER w AS "row_num", RANK() OVER w AS "rank_num" , DENSE_RANK() OVER w AS "ds_rank_num" FROM t_employee WHERE gender='女' WINDOW w AS (PARTITION BY did ORDER BY salary))temp WHERE temp.rank_num<=3;
#或 SELECT ROW_NUMBER() OVER () AS "rn",temp.* FROM(SELECT ename,did,salary, ROW_NUMBER() OVER w AS "row_num", RANK() OVER w AS "rank_num" , DENSE_RANK() OVER w AS "ds_rank_num" FROM t_employee WHERE gender='女' WINDOW w AS (PARTITION BY did ORDER BY salary))temp WHERE temp.ds_rank_num<=3;
#(5)在“t_employee”表中查询每个部门薪资排名前3的员工姓名,部门编号,薪资值。 SELECT temp.* FROM(SELECT ename,did,salary, DENSE_RANK() OVER w AS "ds_rank_num" FROM t_employee WINDOW w AS (PARTITION BY did ORDER BY salary DESC))temp WHERE temp.ds_rank_num<=3;
#(6)在“t_employee”表中查询全公司薪资排名前3的员工姓名,部门编号,薪资值。 SELECT temp.* FROM(SELECT ename,did,salary, DENSE_RANK() OVER w AS "ds_rank_num" FROM t_employee WINDOW w AS (ORDER BY salary DESC))temp WHERE temp.ds_rank_num<=3;
/* (1)凡是联合查询的两个表,必须有“关联字段”, 关联字段是逻辑意义一样,数据类型一样,名字可以一样也可以不一样的两个字段。 比如:t_employee (A表)中did和t_department(B表)中的did。 发现关联字段其实就是“可以”建外键的字段。当然联合查询不要求一定建外键。 (2)联合查询必须写关联条件,关联条件的个数 = n - 1. n是联合查询的表的数量。 如果2个表一起联合查询,关联条件数量是1, 如果3个表一起联合查询,关联条件数量是2, 如果4个表一起联合查询,关联条件数量是3, 两个表的联合查询:有两张表,需要将它们连接在一起。由于只需要一个关联条件来连接这两张表,所以关联条件的数量为 1。 三个表的联合查询:有三张表,需要将它们连接在一起。由于每个表都需要与其他两张表连接,所以需要两个关联条件。因此,关联条件的数量为 2。 四个表的联合查询:有四张表,需要将它们连接在一起。每个表都需要与其他三张表连接,所以需要三个关联条件。因此,关联条件的数量为 3。 以此类推,如果有 n 张表进行联合查询,关联条件的数量将始终为 n - 1。这是为了确保每个表都能与其他表建立连接,并保持查询的一致性和准确性。 。。。。 否则就会出现笛卡尔积现象,这是应该避免的。 (3)关联条件可以用on子句编写,也可以写到where中。 但是建议用on单独编写,这样呢,可读性更好。 每一个join后面都要加on子句 A inner|left|right join B on 条件 A inner|left|right join B on 条件 inner|left|right jon C on 条件
每一个join后面都要加on子句 A inner|left|right join B on 条件 A inner|left|right join B on 条件 inner|left|right jon C on 条件 */
SELECT ename,t_department.did,dname FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did;
SELECT * FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did;
#查询部门编号为1的女员工的姓名、部门编号、部门名称、薪资等情况 SELECT ename,gender,t_department.did,dname,salary FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did WHERE t_department.did = 1 AND gender = '女';
#查询部门编号为1的员工姓名、部门编号、部门名称、薪资、职位编号、职位名称等情况 SELECT ename,gender,t_department.did,dname,salary,job_id,jname FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did INNER JOIN t_job ON t_employee.`job_id` = t_job.`jid` WHERE t_department.did = 1;
#演示左连接 /* (2)A (3)A-A∩B */ /* 观察数据: t_employee 看成A表 t_department 看成B表 此时t_employee (A表)中有 李红和周洲的did是NULL,没有对应部门, t_department(B表)中有 测试部,在员工表中找不到对应记录的。 */ #查询所有员工,包括没有指定部门的员工,他们的姓名、薪资、部门编号、部门名称 SELECT ename,salary,t_department.did,dname FROM t_employee LEFT JOIN t_department ON t_employee.did = t_department.did; #查询的是A结果 A left join B
#查询没有部门的员工信息 SELECT ename,salary,t_department.did,dname FROM t_employee LEFT JOIN t_department ON t_employee.did = t_department.did WHERE t_employee.did IS NULL; #查询的结果是A - A∩B #此时的where条件,建议写子表的关联字段is null,这样更准确一点。 #如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null #因为父表中这个字段一般是主键,不会为null。
/* 右连接 (4)B (5)B - A∩B */ #演示右连接 /* 观察数据: t_employee 看成A表 t_department 看成B表 此时t_employee (A表)中有 李红和周洲的did是NULL,没有对应部门, t_department(B表)中有 测试部,在员工表中找不到对应记录的。 */ #查询所有部门,包括没有对应员工的部门,他们的姓名、薪资、部门编号、部门名称 SELECT ename,salary,t_department.did,dname FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did; #查询的是B结果 A RIGHT join B
#查询没有员工部门的信息 SELECT ename,salary,t_department.did,dname FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did WHERE t_employee.did IS NULL; #查询的结果是B - A∩B #此时的where条件,建议写子表的关联字段is null,这样更准确一点。 #如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null #因为父表中这个字段一般是主键,不会为null。
#查询所有员工,包括没有指定部门的员工,他们的姓名、薪资、部门编号、部门名称 SELECT ename,salary,t_department.did,dname FROM t_department RIGHT JOIN t_employee ON t_employee.did = t_department.did; #查询的是B结果 A RIGHT join B
#查询没有部门的员工信息 SELECT ename,salary,t_department.did,dname FROM t_department RIGHT JOIN t_employee ON t_employee.did = t_department.did WHERE t_employee.did IS NULL; #查询的结果是B - A∩B A right join B #此时的where条件,建议写子表的关联字段is null,这样更准确一点。 #如果要建外键,它们肯定有子表和父表的角色,写子表的关联字段is null #因为父表中这个字段一般是主键,不会为null。
4、union
以下union会报错 SELECT * FROM t_employee UNION SELECT * FROM t_department; /* 错误代码: 1222 The used SELECT statements have a different number of columns 两个Select语句的列数是不同的。 (3)要实现A∪B的结果,那么必须是合并查询。合并A表结果和查询B表结果的select语句。 同样要实现A∪B - A∩B的结果,那么必须是合并查询是A-A∩B结果和查询是B-A∩B的select语句。 */
#查询所有员工和所有部门,包括没有指定部门的员工和没有分配员工的部门。 SELECT * FROM t_employee LEFT JOIN t_department ON t_employee.did = t_department.did
UNION
SELECT * FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did;
#以下union会报错 SELECT * FROM t_employee UNION SELECT * FROM t_department; /* 错误代码: 1222 The used SELECT statements have a different number of columns 两个Select语句的列数是不同的。
column:列,表中的字段。 columns:很多的字段,即字段列表 select 字段列表 from 表名称; */
#联合 查询结果是A表的select 和查询结果是A∩B的select语句,是得不到A∪B SELECT * FROM t_employee LEFT JOIN t_department ON t_employee.did = t_department.did
UNION
SELECT * FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did;
#查询那些没有分配部门的员工和没有指定员工的部门,即A表和B表在对方那里找不到对应记录的数据。 SELECT * FROM t_employee LEFT JOIN t_department ON t_employee.did = t_department.did WHERE t_employee.did IS NULL
UNION
SELECT * FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did WHERE t_employee.did IS NULL;
#查询字段的问题 #查询每一个员工及其所在部门的信息 #要求:显示员工的编号,姓名,部门编号,部门名称 SELECT eid,ename,did,dname FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did; /* 错误代码: 1052 Column 'did' in field list is ambiguous(模糊不清的;引起歧义的) */
SELECT eid,ename,t_employee.did,dname FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did;
#查询每一个员工及其所在部门的信息 #要求,显示员工的编号,姓名,部门表的所有字段 SELECT eid,ename,t_department.* FROM t_employee INNER JOIN t_department ON t_employee.did = t_department.did;
#4、group by分组 #查询所有员工的平均薪资 SELECT AVG(salary) FROM t_employee;
#查询每一个部门的平均薪资 SELECT did,ROUND(AVG(salary),2 ) FROM t_employee GROUP BY did;
#查询每一个部门的平均薪资,显示部门编号,部门的名称,该部门的平均薪资 SELECT t_department.did,dname,ROUND(AVG(salary),2 ) FROM t_department LEFT JOIN t_employee ON t_department.did = t_employee.did GROUP BY t_department.did;
SELECT t_department.did,dname,IFNULL(ROUND(AVG(salary),2),0) FROM t_department LEFT JOIN t_employee ON t_department.did = t_employee.did GROUP BY t_department.did;
#查询每一个部门的女员工的平均薪资,显示部门编号,部门的名称,该部门的平均薪资 #要求,如果没有员工的部门,平均薪资不显示null,显示0 SELECT t_department.did,dname,IFNULL(ROUND(AVG(salary),2),0) FROM t_department LEFT JOIN t_employee ON t_department.did = t_employee.did WHERE gender = '女' GROUP BY t_department.did;
问题1:合计,WITH ROLLUP,加在group by后面
1 2 3 4 5 6 7
#问题1:合计,WITH ROLLUP,加在group by后面 #按照部门统计人数 SELECT did, COUNT(*) FROM t_employee GROUP BY did; #按照部门统计人数,并合计总数 SELECT did, COUNT(*) FROM t_employee GROUP BY did WITH ROLLUP; SELECT IFNULL(did,'合计'), COUNT(*) FROM t_employee GROUP BY did WITH ROLLUP; SELECT IFNULL(did,'合计') AS "部门编号" , COUNT(*) AS "人数" FROM t_employee GROUP BY did WITH ROLLUP;
/* having子句也写条件 where的条件是针对原表中的记录的筛选。where后面不能出现分组函数。 having子句是对统计结果(分组函数计算后)的筛选。having可以加分组函数。 */ #查询每一个部门的女员工的平均薪资,显示部门编号,部门的名称,该部门的平均薪资 #要求,如果没有员工的部门,平均薪资不显示null,显示0 #最后只显示平均薪资高于12000的部门信息 SELECT t_department.did,dname,IFNULL(ROUND(AVG(salary),2),0) FROM t_department LEFT JOIN t_employee ON t_department.did = t_employee.did WHERE gender = '女' GROUP BY t_department.did HAVING IFNULL(ROUND(AVG(salary),2),0) >12000;
#查询每一个部门的男和女员工的人数 SELECT did,gender,COUNT(*) FROM t_employee GROUP BY did,gender;
#查询每一个部门的男和女员工的人数,显示部门编号,部门的名称,性别,人数 SELECT t_department.did,dname,gender,COUNT(eid) FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did GROUP BY t_department.did,gender;
#查询每一个部门薪资超过10000的男和女员工的人数,显示部门编号,部门的名称,性别,人数 #只显示人数低于3人 SELECT t_department.did,dname,gender,COUNT(eid) FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did WHERE salary > 10000 GROUP BY t_department.did,gender HAVING COUNT(eid) < 3;
#6、排序 order by /* 升序和降序,默认是升序 asc代表升序 desc 代表降序 */ #查询员工信息,按照薪资从高到低 SELECT * FROM t_employee ORDER BY salary DESC;
#查询每一个部门薪资超过10000的男和女员工的人数,显示部门编号,部门的名称,性别,人数 #只显示人数低于3人,按照人数升序排列 SELECT t_department.did,dname,gender,COUNT(eid) FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did WHERE salary > 10000 GROUP BY t_department.did,gender HAVING COUNT(eid) < 3 ORDER BY COUNT(eid);
#查询员工的薪资,按照薪资从低到高,薪资相同按照员工编号从高到低 SELECT * FROM t_employee ORDER BY salary ASC , eid DESC;
7 .limit子句
limit子句是用于分页显示结果。
limit m,n n:表示最多该页显示几行 m:表示从第几行开始取记录,第一个行的索引是0 m = (page-1)*n page表示第几页
#查询所有的男员工信息,分页显示,每页显示3条,第2页 #limit m,n n=3,page=2,m=(page-1)*n=3 SELECT * FROM t_employee WHERE gender ='男' LIMIT 3,3
#查询每一个编号为偶数的部门,显示部门编号,名称,员工数量, #只显示员工数量>=2的结果,按照员工数量升序排列, #每页显示2条,显示第1页 SELECT t_department.did,dname,COUNT(eid) FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did WHERE t_department.did%2=0 GROUP BY t_department.did HAVING COUNT(eid)>=2 ORDER BY COUNT(eid) LIMIT 0,2;
不能直接将子查询(SELECT AVG(salary) FROM t_employee)替换为AVG(salary)。 原因是,不能在同一SELECT列表中混合聚合列和非聚合列(除非有GROUP BY),子查询返回的行数必须与外部查询的行数匹配(这里是1对多)
SELECT ename AS "姓名", salary AS "薪资", ROUND((SELECT AVG(salary) FROM t_employee),2) AS "全公司平均薪资", ROUND(salary-(SELECT AVG(salary) FROM t_employee),2) AS "差值" FROM t_employee WHERE ABS(ROUND(salary-(SELECT AVG(salary) FROM t_employee),2))>5000;
#(2)在“t_employee”表中查询每个部门平均薪资和公司平均薪资的差值。
SELECT did,AVG(salary), AVG(salary)-(SELECT AVG(salary) FROM t_employee) FROM t_employee GROUP BY did;
/* 子查询嵌套在where后面。 在where或having后面的子查询结果是: (1)单个值,那么可以用=,>,<,>=,<=,!=这样的运算符和子查询的结果做比较 (2)多个值,那么需要用in,not in, >all,>any....形式做比较 如“<”、“<=”、“>”、“>=”、“=”、“!=”等搭配ANY、SOME、ALL等关键字与查询结果进行比较
*/ #(1)在“t_employee”表中查询薪资最高的员工姓名(ename)和薪资(salary)。 #SELECT ename,MAX(salary) FROM t_employee;#错误 #取表中第一行员工的姓名和全公司最高的薪资值一起显示。
SELECT ename,salary FROM t_employee WHERE salary = (SELECT MAX(salary) FROM t_employee);
#(2)在“t_employee”表中查询比全公司平均薪资高的男员工姓名和薪资。 SELECT ename,salary FROM t_employee WHERE salary > (SELECT AVG(salary) FROM t_employee) AND gender = '男';
#(3)在“t_employee”表中查询和“白露”,“谢吉娜”同一部门的员工姓名和电话。 SELECT ename,tel,did FROM t_employee WHERE did IN(SELECT did FROM t_employee WHERE ename='白露' || ename='谢吉娜');
SELECT ename,tel,did FROM t_employee WHERE did =ANY(SELECT did FROM t_employee WHERE ename='白露' || ename='谢吉娜');
#(4)在“t_employee”表中查询薪资比“白露”,“李诗雨”,“黄冰茹”三个人的薪资都要高的员工姓名和薪资。 SELECT ename,salary FROM t_employee WHERE salary >ALL(SELECT salary FROM t_employee WHERE ename IN('白露','李诗雨','黄冰茹'));
#(5)查询“t_employee”和“t_department”表,按部门统计平均工资, #显示部门平均工资比全公司的总平均工资高的部门编号、部门名称、部门平均薪资, #并按照部门平均薪资升序排列。 SELECT t_department.did,dname,AVG(salary) FROM t_employee RIGHT JOIN t_department ON t_employee.did = t_department.did GROUP BY t_department.did HAVING AVG(salary) >(SELECT AVG(salary) FROM t_employee) ORDER BY AVG(salary);
#(1)查询“t_employee”表中是否存在部门编号为NULL的员工, #如果存在,查询“t_department”表的部门编号、部门名称。 SELECT * FROM t_department WHERE EXISTS(SELECT * FROM t_employee WHERE did IS NULL);
#(2)查询“t_department”表是否存在与“t_employee”表相同部门编号的记录, #如果存在,查询这些部门的编号和名称。 SELECT * FROM t_department WHERE EXISTS(SELECT * FROM t_employee WHERE t_employee.did = t_department.did);
#查询结果等价于下面的sql SELECT DISTINCT t_department.* FROM t_department INNER JOIN t_employee ON t_department.did = t_employee.did;
SELECT t_department.did ,dname,AVG(salary) FROM t_department LEFT JOIN (SELECT did,AVG(salary) FROM t_employee GROUP BY did) temp ON t_department.did = temp.did; #错误,from后面的t_department和temp表都没有salary字段, #SELECT t_department.did ,dname,AVG(salary)出现AVG(salary)是错误的
SELECT t_department.did ,dname,pingjun FROM t_department LEFT JOIN (SELECT did,AVG(salary) AS pingjun FROM t_employee GROUP BY did) temp ON t_department.did = temp.did;
#(2)在“t_employee”表中查询每个部门中薪资排名前2的员工姓名、部门编号和薪资。 SELECT * FROM ( SELECT ename,did,salary, DENSE_RANK() over (PARTITION BY did ORDER BY salary DESC) AS paiming FROM t_employee) temp WHERE temp.paiming <=2;
mysql> desc t_int2; +-------+--------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------------------+------+-----+---------+-------+ | i1 | int | YES | | NULL | | | i2 | int(2) unsigned zerofill | YES | | NULL | | +-------+--------------------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
#添加数据到表格中 insert into 表名称 values(值列表); insert into t_int values(1234,1234); insert into t_int2 values(1234,1234);
#查询数据 select * from 表名称; select * from t_int; select * from t_int2;
#添加数据到表格中 insert into 表名称 values(值列表); insert into t_int values(1,1); insert into t_int2 values(1,1);
insert into t_int values(12222228854225548778455,12222228854225548778455); mysql> insert into t_int values(12222228854225548778455,12222228854225548778455); ERROR 1264 (22003): Out of range value for column 'i1' at row
insert into temp values('尚硅谷真好');#ERROR 1406 (22001): Data too long for column 'name' at row 1
insert into temp values('好');
1 2 3 4 5 6
drop table temp; create table temp( name varchar(65535) ); #ERROR 1074 (42000): Column length too big for column 'name' (max = 21845); use BLOB or TEXT instead 因为当前的表是UTF8,一个汉字占3个字节
mysql> desc t_enum_set; +--------+------------------------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+------------------------------------+------+-----+---------+-------+ | gender | enum('男','女') | YES | | NULL | | | hobby | set('游戏','睡觉','打代码','运动') | YES | | NULL | | +--------+------------------------------------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
#添加数据 insert into t_enum_set values('男','游戏');
#查看数据 select * from t_enum_set;
#添加数据 insert into t_enum_set values('男,女','游戏,睡觉');
mysql> insert into t_enum_set -> values('男,女','游戏,睡觉'); ERROR 1265 (01000): Data truncated for column 'gender' at row 1
#添加数据 insert into t_enum_set values('男','游戏,睡觉');
#添加数据 insert into t_enum_set values('妖','游戏,睡觉'); mysql> insert into t_enum_set -> values('妖','游戏,睡觉'); ERROR 1265 (01000): Data truncated for column 'gender' at row 1
#添加数据 insert into t_enum_set values('男','游戏,睡觉,做饭'); mysql> insert into t_enum_set -> values('男','游戏,睡觉,做饭'); ERROR 1265 (01000): Data truncated for column 'hobby' at row 1
#演示二进制字符串类型binary和varbinary #创建表格 create table t_binary( b1 binary, #没有指定(M),默认是(1) b2 varbinary #没有指定(M),报错,必须指定(M) ); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 4
#演示blob和text #blob系列是大的二进制数据类型 #text系列是大的文本字符串类型 #创建表格 create table t_blob_text( b blob, t text );
#查看表结构 desc t_blob_text; mysql> desc t_blob_text; +-------+------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+------+------+-----+---------+-------+ | b | blob | YES | | NULL | | | t | text | YES | | NULL | | +-------+------+------+-----+---------+-------+ 2 rows in set (0.01 sec)
#添加数据 insert into t_blob_text values('a','a');
insert into t_blob_text values('尚硅谷','尚硅谷');
#查看数据 select * from t_blob_text;
mysql> select * from t_blob_text; +----------------+--------+ | b | t | +----------------+--------+ | 0x61 | a | | 0xC9D0B9E8B9C8 | 尚硅谷 | +----------------+--------+ 2 rows in set (0.00 sec)
insert into temp values('2021-9-2 14:45:52','2021-9-2 14:45:52');
1 2
#修改当前的时区 set time_zone = '+9:00';
1 2
insert into temp values('202192144552','202192144552'); #ERROR 1292 (22007): Incorrect datetime value: '202192144552' for column 'd1' at row 1
1
insert into temp values('20210902144552','20210902144552');
1
insert into temp values('2021&9&2 14%45%52','2021#9#2 14@45@52');
1 2 3
create table temp( d year );
1 2 3 4 5 6
insert into temp values(2021); insert into temp values(85); insert into temp values(22); insert into temp values(69); insert into temp values(0); insert into temp values('0');
1 2 3 4 5 6 7 8 9
mysql> select * from temp; +------+ | d | +------+ | 2021 | | 1985 | | 2022 | +------+ 3 rows in set (0.00 sec)
MySQL 空间类型扩展支持地理特征的生成、存储和分析。这里的地理特征表示世界上具有位置的任何东西,可以是一个实体,例如一座山;可以是空间,例如一座办公楼;也可以是一个可定义的位置,例如一个十字路口等等。现在的应用程序开发中空间数据的存储越来越多了,例如,钉钉的打卡位置是否在办公区域范围内,滴滴打车的位置、路线等。MySQL提供了非常丰富的空间函数以支持各种空间数据的查询和处理。
MySQL中使用Geometry(几何)来表示所有地理特征。Geometry指一个点或点的集合,代表世界上任何具有位置的事物。MySQL的空间数据类型(Spatial Data Type)对应于OpenGIS类,包括GEOMETRY、POINT、LINESTRING、POLYGON等单值类型以及MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、GEOMETRYCOLLECTION存放不同几何值的集合类型。
#演示基本的,简单的DML语句 #基于tempdb数据库演示 create database tempdb; use tempdb; #创建teacher表 create table teacher( id int, name varchar(20), gender enum('m','f'), birthday date, salary double, tel varchar(11) );
#查看teacher表结构 mysql> desc teacher; +----------+---------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+---------------+------+-----+---------+-------+ | id | int | YES | | NULL | | | name | varchar(20) | YES | | NULL | | | gender | enum('m','f') | YES | | NULL | | | birthday | date | YES | | NULL | | | salary | double | YES | | NULL | | | tel | char(18) | YES | | NULL | | +----------+---------------+------+-----+---------+-------+ 6 rows in set (0.01 sec)
#添加数据 #(1)第一种情况,给所有字段赋值 insert into 表名称 values(值列表); #这种情况要求(值列表)的每一个值的类型、顺序与表结构一一对应 #表中有几个字段,(值列表)必须有几个值,不能多也不能少 #值如果是字符串或日期类型,需要加单引号
#例如:添加一条记录到teacher表 insert into teacher values (1,'张三','m','1998-7-8',15000.0,'18256953685');
#例如:添加一条记录到teacher表 insert into teacher values (2,'李四','f','1998-7-8',15000.0); #少了电话号码
mysql> insert into teacher values -> (2,'李四','f','1998-7-8',15000.0); ERROR 1136 (21S01): Column count doesn't match value count at row 1' #(值列表)中值的数量和表结构中column列的数量不一致。
#例如:添加一条记录到teacher表 insert into teacher values (2,'李四','f','北京宏福苑',15000.0,'18256953685'); #把生日写称为地址
mysql> insert into teacher values -> (2,'李四','f','北京宏福苑',15000.0,'18256953685'); ERROR 1292 (22007): Incorrect date value: '北京宏福苑' for column 'birthday' at row 1 #日期格式不对
#(2)第二种情况,给部分字段赋值 insert into 表名称 (部分字段列表) values(值列表); #此时(值列表)中的值的数量、格式、顺序与(部分字段列表)对应即可
#例如:添加一条记录到teacher表,只给id和name字段赋值 insert into teacher (id,name) values (2,'李四');
mysql> select * from teacher; +------+------+--------+------------+--------+-------------+ | id | name | gender | birthday | salary | tel | +------+------+--------+------------+--------+-------------+ | 1 | 张三 | m | 1998-07-08 | 15000 | 18256953685 | | 2 | 李四 | NULL | NULL | NULL | NULL | +------+------+--------+------------+--------+-------------+ 2 rows in set (0.00 sec) #没有赋值的字段都是默认值,此时默认值是NULL #这种情况,当某个字段设置了“非空NOT NULL”约束,又没有提前指定“默认值”, #那么在添加时没有赋值的话,会报错。明天演示非空约束。
#(3)一次添加多条记录 insert into 表名称 values(值列表1),(值列表2)...; insert into 表名称 (部分字段列表) values(值列表),(值列表2)...; #上面一个insert语句有几个(值列表)就表示添加几行记录。 #每一个值列表直接使用逗号分隔
#子查询也可以嵌套在update语句中 #(1)修改“t_employee”表中部门编号(did)和 #“测试部”部门编号(did)相同的员工薪资为原来薪资的1.5倍。 UPDATE t_employee SET salary = salary * 1.5 WHERE did = (SELECT did FROM t_department WHERE dname = '测试部');
#(2)修改“t_employee”表中did为NULL的员工信息, #将他们的did值修改为“测试部”的部门编号。 #子查询select did from t_department where dname = '测试部' #这种子查询必须是单个值,否则无法赋值
UPDATE t_employee SET did = (SELECT did FROM t_department WHERE dname = '测试部') WHERE did IS NULL;
#(3)修改“t_employee”表中“李冰冰”的薪资值等于“孙红梅”的薪资值。 #这里使用子查询先在“t_employee”表中查询出“孙红梅”的薪资。 #select salary from t_employee where ename = '孙红梅';
UPDATE t_employee SET salary = (SELECT salary FROM t_employee WHERE ename = '孙红梅') WHERE ename = '李冰冰'; #You can't specify target table 't_employee' for update in FROM clause'
UPDATE t_employee SET salary = (SELECT salary FROM(SELECT salary FROM t_employee WHERE ename = '孙红梅')temp) WHERE ename = '李冰冰'; #当update的表和子查询的表是同一个表时,需要将子查询的结果用临时表的方式表示 #即再套一层子查询,使得update和最外层的子查询不是同一张表
#(4)修改“t_employee”表“李冰冰”的薪资与她所在部门的平均薪资一样。 #子查询,查询李冰冰的部门编号 #select did from t_employee where ename = '李冰冰';
#子查询第二层,查询李冰冰所在部门的平均薪资 #select avg(salary) from t_employee where did = (select did from t_employee where ename = '李冰冰');
#子查询第三层,把第二层的子查询结果当成临时表再查一下结果 #目的使得和外层的update不是同一张表 SELECT pingjun FROM (SELECT AVG(salary) pingjun FROM t_employee WHERE did = (SELECT did FROM t_employee WHERE ename = '李冰冰') temp)
#update更新 UPDATE t_employee SET salary = (SELECT pingjun FROM (SELECT AVG(salary) pingjun FROM t_employee WHERE did = (SELECT did FROM t_employee WHERE ename = '李冰冰') ) temp) WHERE ename = '李冰冰';
5. DELETE中嵌套子查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
#delete语句中也可以嵌套子查询 #(1)从“t_employee”表中删除“测试部”的员工记录。 DELETE FROM t_employee WHERE did = (SELECT did FROM t_department WHERE dname = '测试部');
#(2)从“t_employee”表中删除和“李冰冰”同一个部门的员工记录。 #子查询 “李冰冰”的部门编号 #select did from t_employee where ename = '李冰冰';
DELETE FROM t_employee WHERE did = (SELECT did FROM t_employee WHERE ename = '李冰冰'); #You can't specify target table 't_employee' for update in FROM clause' #删除和子查询是同一张表
DELETE FROM t_employee WHERE did = (SELECT did FROM (SELECT did FROM t_employee WHERE ename = '李冰冰')temp);
6 .使用子查询复制表结构和数据
演示通过子查询复制表,
(1)复制表结构
仅仅是复制表结构,可以用create语句 CREATE TABLE department LIKE t_department;
(2)复制一条或多条记录
#使用INSERT语句+子查询,复制数据,此时INSERT不用写values INSERT INTO department (SELECT * FROM t_department WHERE did<=3);
(3)同时复制表结构和记录
同时复制表结构+数据 CREATE TABLE d_department AS (SELECT * FROM t_department); 如果select后面是部分字段,复制的新表就只有这一部分字段
#创建一个表格,演示NULL值 create table not_null_demo( id int, name varchar(20), birthday date );
insert into not_null_demo values(null,null,null); insert into not_null_demo(id) values(1); select * from not_null_demo; drop table not_null_demo;
#在创建表的时候,可以指定非空约束
create table 表名称( 字段名 数据类型 not null, 字段名 数据类型 not null, 字段名 数据类型 );
create table not_null_demo( id int not null, name varchar(20) not null, birthday date #没有加not null的,允许为NULL );
#添加NULL值 insert into not_null_demo values(null,null,null);
mysql> insert into not_null_demo values(null,null,null); ERROR 1048 (23000): Column 'id' cannot be null
#指定了id字段的值,但是没有指定name字段和birthday字段的值 insert into not_null_demo(id) values(1);
mysql> insert into not_null_demo(id) values(1); ERROR 1364 (HY000): Field 'name' doesn't have a default value' #此时name设定了NOT NULL,但又没有提前指定默认值, #如果没赋值只能处理为NULL,就违反非空约束
#总结:在insert添加记录时,必须给所有没有提前指定默认值的非空约束字段赋值。
insert into not_null_demo(id,name) values(1,'张三'); insert into not_null_demo(id,name,birthday) values(2,'李四','2000-1-1'); insert into not_null_demo values(3,'王五','2000-2-1'); insert into not_null_demo values(4,'赵六',null);
insert into not_null_demo values(4,'赵六'); #错误,值列表数量与字段数量不匹配 mysql> insert into not_null_demo values(4,'赵六'); ERROR 1136 (21S01): Column count doesn't match value count at row 1'
#在创建表之后,可以给某个字段增加非空约束 #alter table 表名称 modify 【column】 字段名 数据类型 not null;
#例如:给not_null_demo表格的birthday字段加not null约束 alter table not_null_demo modify column birthday date not null;
mysql> alter table not_null_demo modify column birthday date not null; ERROR 1138 (22004): Invalid use of NULL value #失败的原因是因为not_null_demo表中birthday字段现在已经有NULL值。 #所以添加不上非空约束。 #如果要加,必须先将原来的NULL值修改掉
mysql> select * from not_null_demo; +----+------+------------+ | id | name | birthday | +----+------+------------+ | 1 | 张三 | NULL | | 2 | 李四 | 2000-01-01 | | 3 | 王五 | 2000-02-01 | | 4 | 赵六 | NULL | +----+------+------------+ 4 rows in set (0.01 sec)
update not_null_demo set birthday = '2000-5-1' where id=1 || id = 4;
mysql> select * from not_null_demo; +----+------+------------+ | id | name | birthday | +----+------+------------+ | 1 | 张三 | 2000-05-01 | | 2 | 李四 | 2000-01-01 | | 3 | 王五 | 2000-02-01 | | 4 | 赵六 | 2000-05-01 | +----+------+------------+ 4 rows in set (0.00 sec)
mysql> alter table not_null_demo modify column birthday date not null; Query OK, 0 rows affected (0.06 sec) Records: 0 Duplicates: 0 Warnings: 0
mysql> desc not_null_demo; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | id | int | NO | | NULL | | | name | varchar(20) | NO | | NULL | | | birthday | date | NO | | NULL | | +----------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
#删除某个字段的非空约束 alter table 表名称 modify 【column】 字段名 数据类型;
#例如:去掉birthday字段的非空约束 alter table not_null_demo modify column birthday date;
mysql> desc not_null_demo; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | id | int | NO | | NULL | | | name | varchar(20) | NO | | NULL | | | birthday | date | YES | | NULL | | +----------+-------------+------+-----+---------+-------+ 3 rows in set (0.01 sec)
#添加选课成绩信息 insert into xuanke values(1,1,1,89); insert into xuanke values(2,1,2,96); insert into xuanke values(3,2,1,75); insert into xuanke values(4,2,2,96);
alter table 表名称 modify 字段名 数据类型 auto_increment;#给这个字段增加自增约束 alter table 表名称 modify 字段名 数据类型; #去掉auto_increment相当于删除
6、演示错误
1 2 3 4 5
create table employee( eid int auto_increment, ename varchar(20) ); ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
#创建表 mysql> create table emp( -> eid int auto_increment, -> ename varchar(20) -> ); ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must be defined as a key
#如何在建表后添加检查约束,使用add check alter table 表名称 add check(条件);
4、如何查看一个表的约束(了解)
SELECT * FROM information_schema.table_constraints WHERE table_name = ‘表名称’; #information_schema数据库名(系统库) #table_constraints表名称(专门存储各个表的约束) #WHERE条件 #table_name = ‘表名称’条件是指定表名称
5、如何删除检查约束(了解)
1
alter table 表名称 drop check 检查约束名;
6、SQL示例
3、特点: (1)mysql8.0之前,mysql支持检查约束的语法,但是不起作用。 (2)mysql8中检查约束可以定义在字段后面,通常这个只限定单个字段的取值范围 也可以定义在字段下面,通常会限定两个字段之前的取值条件。 (3)就算是定义在字段后面,虽然此时和其他字段没关系,也是当成表级约束对象 create table emp( id int primary key auto_increment, name varchar(20) not null, age int check(age>=18), #列级约束 birthday date not null, #出生日期 hiredate date not null, #入职日期 check( year(hiredate)-year(birthday)>=18) #year(hiredate)表示取出入职日期的年份值 );
#创建表格,限定age>=18 create table emp( id int primary key auto_increment, name varchar(20) not null, age int check(age>=18) );
#mysql5.7上面运行 insert into emp values(null,'张三',8);
mysql> select * from emp; +----+------+------+ | id | name | age | +----+------+------+ | 1 | 张三 | 8 | #mysql5.7检查约束没有起作用 +----+------+------+ 1 row in set (0.00 sec)
#mysql8.0.26上面运行 mysql> insert into emp values(null,'张三',8); ERROR 3819 (HY000): Check constraint 'emp_chk_1' is violated.
create table emp( id int primary key auto_increment, name varchar(20) not null, age int check(age>=18), #列级约束 birthday date not null, #出生日期 hiredate date not null, #入职日期 check( year(hiredate)-year(birthday)>=18) #year(hiredate)表示取出入职日期的年份值 );
#添加数据 insert into emp values(null,'张三',23,'2000-1-1','2021-11-30');#满足条件
mysql> select * from emp; +----+------+------+------------+------------+ | id | name | age | birthday | hiredate | +----+------+------+------------+------------+ | 1 | 张三 | 23 | 2000-01-01 | 2021-11-30 | +----+------+------+------------+------------+ 1 row in set (0.00 sec)
#添加数据 insert into emp values(null,'张三',8,'2013-1-1','2021-11-30');#不满足条件
mysql> insert into emp values(null,'张三',8,'2013-1-1','2021-11-30'); ERROR 3819 (HY000): Check constraint 'emp_chk_1' is violated.
insert into emp values(null,'张三',28,'2013-1-1','2021-11-30');#不满足条件 mysql> insert into emp values(null,'张三',28,'2013-1-1','2021-11-30');#不满足条件 ERROR 3819 (HY000): Check constraint 'emp_chk_2' is violated.
#查看表结构 desc emp;
#查看表的定义 show create table emp;
mysql> show create table emp\G *************************** 1. row *************************** Table: emp Create Table: CREATE TABLE `emp` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `age` int DEFAULT NULL, `birthday` date NOT NULL, `hiredate` date NOT NULL, PRIMARY KEY (`id`), CONSTRAINT `emp_chk_1` CHECK ((`age` >= 18)), CONSTRAINT `emp_chk_2` CHECK (((year(`hiredate`) - year(`birthday`)) >= 18)) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
#查询系统库中约束表查看表的约束 SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';
#查看emp表的约束 SELECT * FROM information_schema.table_constraints WHERE table_name = 'emp'; #只有主键、唯一键、外键、检查约束才能这个这个表中看到,默认值、非空这里是看不到。
mysql> show create table emp\G *************************** 1. row *************************** Table: emp Create Table: CREATE TABLE `emp` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `age` int DEFAULT NULL, `birthday` date NOT NULL, `hiredate` date NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
#如何在建表后添加检查约束 #使用modify?不起作用 alter table 表名称 modify 【column】 字段名 数据类型 check(条件); #列级约束 #给age字段添加检查约束 age>=18 alter table emp modify age int check(age>=18);#这里语法上没问题,但是没有真正起作用 insert into emp values(null,'李四',6,'1998-5-1','2021-1-2');#添加成功,说明检查约束没有起作用
#如何在建表后添加检查约束,使用add check alter table 表名称 add check(条件);
#给age字段添加检查约束 age>=18 alter table emp add check(age>=18);
mysql> alter table emp add check(age>=18); ERROR 3819 (HY000): Check constraint 'emp_chk_1' is violated. #因为表中有违反 (age>=18)的数据,必须先处理
mysql> select * from emp; +----+------+------+------------+------------+ | id | name | age | birthday | hiredate | +----+------+------+------------+------------+ | 1 | 张三 | 23 | 2000-01-01 | 2021-11-30 | | 2 | 李四 | 6 | 1998-05-01 | 2021-01-02 | +----+------+------+------------+------------+ 2 rows in set (0.00 sec)
update emp set age = 26 where id = 2;
#给age字段添加检查约束 age>=18 alter table emp add check(age>=18); insert into emp values(null,'李四',6,'1998-5-1','2021-1-2');
#如何在建表后添加检查约束 #使用modify?不起作用 alter table 表名称 modify 【column】 字段名 数据类型 check(条件); #列级约束 #如何在建表后添加检查约束,使用add check alter table 表名称 add check(条件);
#建表时,指定外键约束 create table dept( did int primary key auto_increment, dname varchar(50) unique key not null );
create table emp( id int primary key auto_increment, name varchar(20) not null, departmentid int, #子表中外键约束的字段名和父表的被引用字段名不要求一致,但是数据类型和逻辑意义要一样 #外键约束只能在字段列表下面单独定义,不能在字段后面直接定义 foreign key(departmentid) references dept(did) );
#查看表结构 desc dept; desc emp;
mysql> desc dept; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | did | int | NO | PRI | NULL | auto_increment | | dname | varchar(50) | NO | UNI | NULL | | +-------+-------------+------+-----+---------+----------------+ 2 rows in set(0.01 sec)
mysql> desc emp; +--------------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+-------------+------+-----+---------+----------------+ | id | int | NO | PRI | NULL | auto_increment | | name | varchar(20) | NO | | NULL | | | departmentid | int | YES | MUL | NULL | | +--------------+-------------+------+-----+---------+----------------+ 3 rows in set(0.00 sec)
#查看表的定义 show create table dept; show create table emp;
mysql> show create table dept\G *************************** 1. row *************************** Table: dept Create Table: CREATE TABLE `dept` ( `did` int NOT NULL AUTO_INCREMENT, `dname` varchar(50) NOT NULL, PRIMARY KEY(`did`), UNIQUE KEY `dname` (`dname`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set(0.00 sec)
mysql> show create table emp\G *************************** 1. row *************************** Table: emp Create Table: CREATE TABLE `emp` ( `id` int NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `departmentid` int DEFAULT NULL, PRIMARY KEY(`id`), KEY `departmentid` (`departmentid`), CONSTRAINT `emp_ibfk_1` FOREIGN KEY(`departmentid`) REFERENCES `dept` (`did`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci 1 row in set(0.00 sec)
#查看系统库的约束表 SELECT * FROM information_schema.table_constraints WHEREtable_name='表名称';
SELECT * FROM information_schema.table_constraints WHEREtable_name='emp';
#添加子表信息,有影响,受到约束 insert into emp values(null,'张三',1);#成功 insert into emp values(null,'李四',1);#成功 insert into emp values(null,'王五',2);#成功 insert into emp values(null,'赵六',6); #失败 #因为departmentid=1或2,在父表dept中可以找到对应记录 #因为departmentid=6,在父表dept中找不到对应记录
mysql> insert into emp values(null,'赵六',6); ERROR 1452 (23000): Cannot add(添加) or update(修改) a child(子表) row(记录/行): a foreign key constraint fails (`this0`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`departmentid`) REFERENCES `dept` (`did`))
on update No action | Restrict | Set null | Cascade on delete No action | Restrict | Set null | Cascade 如果没有写on update 或on delete字句,表示选择了No action | Restrict。
*/ #父表 create table dept( did int primary key auto_increment, dname varchar(50) unique key not null );
insert into dept values(null,'财务'),(null,'教学'),(null,'咨询'),(null,'后勤');
mysql> select * from dept; +-----+-------+ | did | dname | +-----+-------+ | 4 | 后勤 | | 3 | 咨询 | | 2 | 教学 | | 1 | 财务 | +-----+-------+ 4 rows in set (0.00 sec)
#子表 create table emp( id int primary key auto_increment, name varchar(20) not null, departmentid int, foreign key (departmentid) references dept(did) on update cascade on delete set null #on delete set null要求departmentid字段没有not null约束 );
#添加子表时记录和 定义on update cascade on delete set null无关。还是要在主表能找到对应的记录。 insert into emp values(null,'张三',1); insert into emp values(null,'李四',2); insert into emp values(null,'王五',1);
mysql> select * from emp; +----+------+--------------+ | id | name | departmentid | +----+------+--------------+ | 1 | 张三 | 1 | | 2 | 李四 | 2 | | 3 | 王五 | 1 | +----+------+--------------+ 3 rows in set (0.00 sec)
#修改子表, 和定义on update cascade on delete set null无关。还是要在主表能找到对应的记录。 update emp set departmentid = 6 where name = '王五'; #失败,因为departmentid = 6在父表dept中找不到对应部门
#修改父表被引用的did值, 和定义on update cascade on delete set null有关。 update dept set did = 6 where did = 1; #此时did=1的记录被子表引用了,可以修改,并且会同时修改子表的departmentid=1的字段值为6,级联修改
mysql> select * from dept; +-----+-------+ | did | dname | +-----+-------+ | 4 | 后勤 | | 3 | 咨询 | | 2 | 教学 | | 6 | 财务 | +-----+-------+ 4 rows in set (0.00 sec)
mysql> select * from emp; +----+------+--------------+ | id | name | departmentid | +----+------+--------------+ | 1 | 张三 | 6 | | 2 | 李四 | 2 | | 3 | 王五 | 6 | +----+------+--------------+ 3 rows in set (0.00 sec)
#删除父表dept被引用的did的记录, 和定义on update cascade on delete set null有关。 delete from dept where did = 6; #did=6的部门在子表中有引用
mysql> select * from dept; +-----+-------+ | did | dname | +-----+-------+ | 4 | 后勤 | | 3 | 咨询 | | 2 | 教学 | +-----+-------+ 3 rows in set (0.00 sec)
mysql> select * from emp; +----+------+--------------+ | id | name | departmentid | +----+------+--------------+ | 1 | 张三 | NULL | | 2 | 李四 | 2 | | 3 | 王五 | NULL | +----+------+--------------+ 3 rows in set (0.00 sec)
/* 1.创建用户 CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码'; 2.关键字介绍 a.用户名:创建的用户名 b.主机名:指定该用户在哪个主机上可以登录,如果是本地用户,可以用'localhost', 如果想让该用户可以任意远程主机登录,可以使用通配符% c.密码:该用户登录的密码,密码可以为空,如果为空,该用户可以不输入密码就可以登录mysql */ -- user1用户只能在localhost这个IP登录mysql服务器 CREATE USER 'user1'@'localhost' IDENTIFIED BY '123'; -- user2用户可以在任何电脑上登录mysql服务器 CREATE USER 'user2'@'%' IDENTIFIED BY '123';
/* 分配用户的权限: GRANT 权限1, 权限2... ON 数据库名.表名 TO '用户名'@'主机名'; 关键字介绍: a.GRANT:授权关键字 b.授予用户的权限,比如 'select' 'insert' 'update'等,如果要授予所有的权限,使用 'ALL' c.数据库名.表名:该用户操作哪个数据库的哪些表, 如果要授予该用户对所有数据库和表的相关操作权限,就可以用*表示: *.* d.'用户名'@'主机名':给哪个用户分配权限 */ GRANT CREATE,ALTER,DROP,UPDATE,DELETE,SELECT ON 220212_java2.* TO 'user1'@'localhost';
GRANT ALL ON *.* TO 'user2'@'%';
/* 删除用户: DROP USER '用户名'@'主机名'; 删除用户的时候,用户名要对应 主机名也要对象 */ DROP USER 'user2'@'%';-- 正确 DROP USER 'user2'@'localhost';-- 错误,因为创建user2的时候,主机名写的是%不是localhost
6 修改用户密码
1 修改管理员密码
1
mysqladmin -uroot -p password 新密码 -- 新密码不需要加上引号
注意:需要在未登陆MySQL的情况下操作。
具体操作:
1 2
mysqladmin -uroot -p password root 输入老密码
2 修改普通用户密码
1
set password for'用户名'@'主机名'= password('新密码');
注意:需要在登陆MySQL的情况下操作。
具体操作:
1
set password for'user1'@'localhost'= password('666666');
第18章 MySQL8的部分新特性
1、系统表全部为InnoDB表
从 MySQL 8.0 开始,mysql 系统表和数据字典表使用 InnoDB 存储引擎,存储在 MySQL 数据目录下的 mysql.ibd 表空间文件中。在 MySQL 5.7 之前,这些系统表使用 MyISAM 存储引擎,存储在 mysql 数据库文件目录下各自的表空间文件中。关于数据库存储引擎的详细内容,在MySQL高级课程讲解。
在MySQL5.7版本中查看系统表类型,结果如下: mysql> #查看系统表类型 mysql> SELECT DISTINCT(ENGINE) FROM information_schema.tables;
#(1)在“t_employee”表中查询每个人薪资和公司平均薪资的的差值。 WITH temp AS (SELECT ROUND(AVG(salary),2) AS pingjun FROM t_employee) SELECT ename AS "员工姓名", salary AS "薪资", pingjun "公司平均薪资", ROUND(salary - pingjun,2) "差值" FROM t_employee,temp HAVING ABS(差值)>5000;
#(2)查询薪资低于9000的员工编号,员工姓名,员工薪资,领导编号,领导姓名,领导薪资 WITH emp AS (SELECT eid,ename,salary,`mid` FROM t_employee WHERE salary <9000), mgr(meid,mename,msalary) AS (SELECT eid,ename,salary FROM t_employee) SELECT eid AS "员工薪资", ename AS "员工姓名", salary AS "员工薪资", meid AS "领导编号", mename AS "领导姓名", msalary AS "领导薪资" FROM emp INNER JOIN mgr ON emp.mid = mgr.meid;
#(3)查询eid为21的员工,和他所有领导,直到最高领导。 CREATE TABLE emp AS (SELECT eid,ename,salary,tel,`mid` FROM t_employee WHERE salary < 10000); UPDATE emp SET MID=19 WHERE eid=21; UPDATE emp SET MID=17 WHERE eid=19; UPDATE emp SET MID=16 WHERE eid=17; UPDATE emp SET MID=15 WHERE eid=16; UPDATE emp SET MID=4 WHERE eid=15; UPDATE emp SET MID=NULL WHERE eid=4; SELECT * FROM emp;
WITH RECURSIVE cte AS ( SELECT eid,ename,`mid` FROM emp WHERE eid = 21
UNION ALL
SELECT emp.eid,emp.ename,emp.mid FROM emp INNER JOIN cte ON emp.eid = cte.mid WHERE emp.eid IS NOT NULL ) SELECT * FROM cte;