mysql 进阶

一、DML操作

数据操纵语言(DML)DML用于插入、修改、删除数据记录,包括如下SQL语句:

INSERT:添加数据到数据库中

UPDATE:修改数据库中的数据

DELETE:删除数据库中的数据

1.1插入数据

1.1.1语法

insert into 表名称 values(值1,值2,......);
insert into 表名称 values(值1,值2,......),(值1,值2,......);
insert into(字段1,字段2)value(值1,值2,......);
insert into(字段1,字段2)value(值1,值2,......),(值1,值2,......);

1.1.2 说明

1、值列表(值1,值2,......)的顺序、个数与字段列表(字段1,字段2,......) 中字段的顺序、个数一致

(1)如果个数少了就报Column count doesn’t match value count

(2)如果VALUES前面的()中没有列出字段,那么默认就是为表中的所有字段赋值,那么个数与顺序与表结构中字段定义的一致

2、关于自增长列、默认值列、允许为NULL列的赋值

(1)如果字段列表列出了字段名,那么值列表中就要为其赋值,哪怕它是自增长列,有默认值列,可以为NULL值的列。

  • InnoDB表的自动增长列可以手动插入合适的值,但是插入的值如果是NULL或者0,则实际插入的将是自动增长后的值;

  • 如果列声明了“默认约束”那么对应的位置可以赋值具体的值,也可以使用“DEFAULT”,表示使用默认值;

  • 如果列允许了NULL值,那么可以为对应的字段可以赋值为具体值也可以赋值为NULL

(2)对于没有列出的字段,像自增列就自动赋值,像默认值列就自动赋默认值,像允许NULL的列就自动赋NULL值,但是非空列又没有提供默认值会自动赋值为对应数据类型的默认值,例如字符串赋值为空字符串,int赋值为0;

3、VALUES也可以写成VALUE,但是VALUES是标准写法

4、可以同时插入多行

5、如果插入从表的数据,要注意查看主表参照字段的值是否存在

6、值的位置可以是常量值、表达式、函数

1.2 修改数据

1.21语法

UPDATE 表名称 SET 字段名1 = 值1, 字段名2=值2,...... 【WHERE 条件】;
UPDATE 表1,表2,...... SET 表1.字段名1 = 值1, 表1.字段名2=值2,表2.字段1 = 值1, 表2.字段2=值2...... 【WHERE 条件】;

1.2.2 说明

1、如果不写where条件,会修改所有行

2、值可以是常量值、表达式、函数

3、可以同时更新多张表

如果两个表没有建立外键,但逻辑上有外键关系

4、如果修改从表外键字段的数据,要注意查看主表参照字段的值是否存在

5、如果修改主表的被参考的字段的值,要注意查看从表的外键是否有依赖该值,如果有

(1)如果外键是on update RESTRICT或on update NO ACTION,那么要先处理从表的数据,才能修改

(2)如果外键是on update SET NULL 或 on update CASCADE,那么直接修改,从表的外键字段会自动处理

1.3 删除数据

1.31语法

delete from 表名()[where 条件];
delete 表1,表2,....... from 表1,表2,...... 【where 条件】;

1.3.2 说明

1、如果不加where条件,表示删除整张表的数据,表结构保留

delete from 表名;

删除整张表的数据还可以使用truncate 表名;

区别:

truncate相当于删除表再重建一张同名结构的表,操作后得到一张全新表,而delete是在原有表中删除数据。如果决定清空一张表的数据,truncate速度更快一些。

TRUNCATE语句不能回滚

2、如果删除主表的记录,要注意查看从表的外键是否有依赖该行的值,如果有

(1)如果外键是on delete RESTRICT或on delete NO ACTION,那么要先处理从表的数据,才能删除

(2)如果外键是on delete SET NULL 或 on delete CASCADE,那么删除时从表的对应记录也会被置空或跟着删除

3、可以一次删除多个表的数据

例如:两个表没有建立外键,但逻辑上有外键关系,也可以通过删除多个表的数据来实现级联删除1.

1.4查询

1.4.1语法

SELECT 查询列表
  FROM 表名或视图列表
  【WHERE 条件表达式】
  【GROUP BY 字段名 【HAVING 条件表达式】】
  【ORDER BY 字段 【ASC|DESC】】
  【LIMIT m,n】;

说明:

(1)如果SELECT后面是*,那么表示查询所有字段

(2)SELECT后面的查询列表,可以是表中的字段,常量值,表达式,函数

(3)查询的结果是一个虚拟的表

select语句,可以包含5种子句:依次是where、 group by、having、 order by、limit必须照这个顺序

1.4.2别名AS

语法:AS 别名

说明:

(1)可以给字段取别名、可以给表名取别名

(2)AS 可以省略

(3)如果给字段取别名,如果别名中包含特殊符号,例如“空格”等,建议给别名加上双引号或单引号

(4)如果是给表名取别名,那么不能加双引号或单引号,也不能有特殊符号,例如“空格”等

(5)建议别名简短,见名知意

1.4.3 去重DISTINCT

#查询员工表的部门编号
SELECT DISTINCT dept_id FROM t_employee;

#统计员工表中员工有几个部门
SELECT COUNT(DISTINCT dept_id) FROM t_employee;  

1.4.4 着重号

例如:select name from t_stu;

可以给字段或表名加着重号

如果字段名或表名与关键字一样更要加着重号了

二、MySQL的运算符

(1)算术运算符:+ - * /(除也可以写成div,div取整) %(取模可以写成mod)

(2)比较运算符:= > >= < <= !=(不等于还可以写成<>) <=>(安全等于)

(3)逻辑运算符:&&(逻辑与也可以写成and) ||(逻辑或也可以写成or) not(逻辑非) xor(逻辑异或)

(4)范围:表达式 between ... and ... (也可以写成 表达式>=... and 表达式 <=...)

? 表达式 not between ... and ...(也可以写成 表达式<... || 表达式 >...)

(5)集合:in (值,值,值...) not in(值,值,值...)

(6)模糊查询:LIKE NOT LIKE,通配符:%表示0-n个字符,_下划线代表一个字符

(7)位运算符:&(按位与) |(按位或)^(按位异或)~(按位取反)>>(右移)<<(左移)

(8)NULL值判断,is null 或 is not null,如果使用null=null,null<>null,null=0,null<>0,null=false等都不对

不过xxx is null 可以使用xxx <=> null ,xxx is not null 可以写成 not xxx <=> null

结论:所有的运算符遇到NULL结果都是NULL,除了<=>

2.1 算术运算符

#+,-,*,/(div),%(mod)
#筛选出eid是偶数的员工
SELECT * FROM t_employee WHERE eid % 2 = 0; 
SELECT * FROM t_employee WHERE eid MOD 2 = 0; 

#查看每天的基本工资值,每个月按22天算
SELECT eid,basic_salary/12 AS "日薪"
FROM t_salary;

#div也表示除,但是只保留整数部分
SELECT eid,basic_salary DIV 12 AS "日薪"
FROM t_salary;

#关于+,在Java中,+的左右两边如果有字符串,那么表示字符串的拼接,但是在MySQL中+只表示数值相加,
#如果遇到非数值类型,先尝试转成数值,如果转失败,就按0计算
SELECT eid+ename FROM t_employee;
SELECT eid+birthday FROM t_employee;

#MySQL中字符串拼接要使用字符串函数实现
SELECT CONCAT(eid,":",ename) AS result FROM t_employee;

2.2 比较运算符

#=,>, <,>=, <=, !=(不等于<>),<=>(安全等于)
#查询basic_salary!=10000
SELECT eid,basic_salary FROM t_salary WHERE basic_salary != 10000;
SELECT eid,basic_salary FROM t_salary WHERE basic_salary <> 10000;

#查询basic_salary=10000,注意在Java中比较是==
SELECT eid,basic_salary FROM t_salary WHERE basic_salary = 10000;

#查询commission_pct等于0.40
SELECT eid,commission_pct FROM t_salary WHERE commission_pct = 0.40;
SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> 0.40;

#查询commission_pct等于NULL
SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NULL;
SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> NULL;

#查询commission_pct不等于NULL
SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NOT NULL;
SELECT eid,commission_pct FROM t_salary WHERE NOT commission_pct <=> NULL;

2.3 逻辑运算符

#与&&,或||,非!
#与 AND,或 OR ,非 NOT,异或 XOR

#查询性别男,并且在90以前出生的员工
SELECT * FROM t_employee WHERE gender=‘男‘ AND birthday<‘1990-01-01‘; 

#查询职位编号job_id是1或2的员工
SELECT * FROM t_employee WHERE job_id =1 OR job_id = 2;

#查询基本薪资是在9000-12000之间的员工编号和基本薪资
SELECT eid,basic_salary FROM t_salary WHERE basic_salary >=9000 AND basic_salary<=12000;

#查询基本薪资不在9000-12000之间的员工编号和基本薪资
SELECT eid,basic_salary FROM t_salary WHERE NOT (basic_salary >=9000 AND basic_salary<=12000);
SELECT eid,basic_salary FROM t_salary WHERE basic_salary <9000 OR basic_salary>12000;

2.4 范围和集合

#between ... and ... 和 not between ... and ... 
#in(集合)  和 not in(...)

#查询基本薪资是在9000-12000之间的员工编号和基本薪资
SELECT eid,basic_salary FROM t_salary WHERE basic_salary BETWEEN 9000 AND 12000;

#查询eid是1,3,5的基本工资
SELECT eid,basic_salary FROM t_salary WHERE eid IN (1,3,5);

2.5 模糊查询

#like 和 通配符 一起使用
#like _ 匹配单个字符
#like % 匹配任意个字符

#查询名字中有‘冰‘字的员工信息
SELECT * FROM t_employee WHERE ename LIKE ‘%冰%‘;

#查询姓李的员工信息
SELECT * FROM t_employee WHERE ename LIKE ‘李%‘;

#查询姓李,名字就一个字的员工信息
SELECT * FROM t_employee WHERE ename LIKE ‘李_‘;

#查询李冰冰的信息
SELECT * FROM t_employee WHERE ename LIKE ‘李冰冰‘;



通常情况,可以使用FIND_IN_SET()函数或LIKE操作符搜索SET值:

? mysql> SELECT * FROM tbl_name WHERE FIND_IN_SET(‘value‘,set_col)>0;

? mysql> SELECT * FROM tbl_name WHERE set_col LIKE ‘%value%‘;

? 第1个语句找出SET_col包含value set成员的行。第2个类似,但有所不同:它在其它地方找出set_col包含value的行,甚至是在另一个SET成员的子字符串中。

? 下面的语句也是合法的:

? mysql> SELECT * FROM tbl_name WHERE set_col & 1;

? mysql> SELECT * FROM tbl_name WHERE set_col = ‘val1,val2‘;

? 第1个语句寻找包含第1个set成员的值。第2个语句寻找一个确切匹配的值。应注意第2类的比较。将set值与‘val1,val2‘比较返回的结果与同‘val2,val1‘比较返回的结果不同。指定值时的顺序应与在列定义中所列的顺序相同。

如果想要为SET列确定所有可能的值,使用SHOW COLUMNS FROM tbl_name LIKE set_col并解析输出中第2列的SET定义。

有什么实际应用呢?

? 比如我们设定用户的权限控制,一个用户可能会有多种权限,我们使用所有权限创建一个SET类型的字段,我们不需要用一系列int来定义各种权限了,直接使用一个SET字段即可:

/*
    用户权限permission表
    */
    create table user_permission(
    id int UNSIGNED not null auto_increment,
    user_id int not null ,
    permission set(‘阅读‘,‘评论‘,‘发帖‘) not null,
    primary key(id),
    unique (user_id)
    );
    desc user_permission;
    insert into user_permission values (0,1,‘阅读‘),(0,2,‘阅读‘),(0,3,‘阅读,评论‘);
    insert into user_permission values (0,4,‘阅读,评论,发帖‘);
    select *,permission+0 from user_permission;
    select permission from user_permission where user_id=1;
    select * from user_permission where permission & 10;
    SELECT * FROM user_permission WHERE FIND_IN_SET(‘评论‘,permission)>0;

2.6 NULL值判断与计算处理

#NULL值判断与处理
#查询奖金百分比不为空的员工编号
SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NOT NULL;

#查询奖金百分比为空的员工编号
SELECT eid,commission_pct FROM t_salary WHERE commission_pct IS NULL;

#关于null值计算
#所有运算符遇到null都是null

#计算实际的薪资:  basic_salary + salary * 奖金百分比
#函数:IFNULL(表达式,用什么值代替)
SELECT eid,basic_salary + performance_salary *(1+ commission_pct) FROM t_salary;#错误的
SELECT eid,basic_salary + performance_salary *(1+ IFNULL(commission_pct,0)) FROM t_salary;

#<=>安全等于
#查询奖金百分比为空的员工编号
SELECT eid,commission_pct FROM t_salary WHERE commission_pct <=> NULL;

三、关联查询,联合查询

mysql 进阶

作用:从2张或多张表中,取出有关联的数据.

关联查询一共有几种情况:

  • 内连接:INNER JOIN 、CROSS JOIN
  • 外连接:左外连接(LEFT OUTER JOIN)、右外连接(RIGHT OUTER JOIN)、全外连接(FULL OUTER JOIN)
  • 自连接:当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义

说明:

(1)连接 n个表,至少需要 n-1个连接条件。 例如:连接三个表,至少需要两个连接条件。

(2)当两个关联查询的表如果有字段名字相同,并且要查询中涉及该关联字段,那么需要使用表名前缀加以区分

(3)当如果表名比较长时,可以给表取别名,简化SQL语句

mysql 进阶

3.1 笛卡尔积

定义:将两(或多)个表的所有行进行组合,连接后的行数为两(或多)个表的乘积数.

在MySQL中如下情况会出现笛卡尔积,主要是因为缺少关联条件或者关联条件不准确

注:外连接必须写关联条件,否则报语法错误

#笛卡尔积
#查询员工姓名和所在部门名称
SELECT ename,dname FROM t_employee,t_department;
SELECT ename,dname FROM t_employee INNER JOIN t_department;
SELECT ename,dname FROM t_employee CROSS JOIN t_department;
SELECT ename,dname FROM t_employee JOIN t_department;

3.2关联条件

表连接的约束条件可以有三种方式:WHERE, ON, USING

  • WHERE:适用于所有关联查询

  • ON:只能和JOIN一起使用,只能写关联条件。虽然关联条件可以并到WHERE中和其他条件一起写,但分开写可读性更好。

  • USING:只能和JOIN一起使用,而且要求两个关联字段在关联表中名称一致,而且只能表示关联字段值相等

#关联条件
#把关联条件写在where后面
SELECT ename,dname FROM t_employee,t_department WHERE t_employee.dept_id=t_department.did;

#把关联条件写在on后面,只能和JOIN一起使用
SELECT ename,dname FROM t_employee INNER JOIN t_department ON t_employee.dept_id=t_department.did;
SELECT ename,dname FROM t_employee CROSS JOIN t_department ON t_employee.dept_id=t_department.did;
SELECT ename,dname FROM t_employee JOIN t_department ON t_employee.dept_id=t_department.did;

#把关联字段写在using()中,只能和JOIN一起使用
#而且两个表中的关联字段必须名称相同,而且只能表示=
#查询员工姓名与基本工资
SELECT ename,basic_salary FROM t_employee INNER JOIN t_salary USING(eid);

#n张表关联,需要n-1个关联条件
#查询员工姓名,基本工资,部门名称
SELECT ename,basic_salary,dname FROM t_employee,t_department,t_salary 
WHERE t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;

SELECT ename,basic_salary,dname FROM t_employee INNER JOIN t_department INNER JOIN t_salary 
ON t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;

3.3 内连接(INNER JOIN)

有两种,显式的和隐式的,返回连接表中符合连接条件和查询条件的数据行

格式:

隐式:SELECT [cols_list] from 表1,表2 where [condition]

显式:SELECT [cols_list] from 表1 INNER JOIN 表2 ON [关联条件] where [其他筛选条件]

? SELECT [cols_list] from 表1 CROSS JOIN 表2 ON [关联条件] where [其他筛选条件]

? SELECT [cols_list] from 表1 JOIN 表2 ON [关联条件] where [其他筛选条件]

#内连接
#查询员工姓名和所在部门名称
SELECT ename,dname FROM t_employee,t_department WHERE t_employee.dept_id=t_department.did;
SELECT ename,dname FROM t_employee INNER JOIN t_department ON t_employee.dept_id=t_department.did;
SELECT ename,dname FROM t_employee CROSS JOIN t_department ON t_employee.dept_id=t_department.did;
SELECT ename,dname FROM t_employee JOIN t_department ON t_employee.dept_id=t_department.did;

#查询员工姓名,基本工资,部门名称
SELECT ename,basic_salary,dname FROM t_employee,t_department,t_salary 
WHERE t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;

SELECT ename,basic_salary,dname FROM t_employee INNER JOIN t_department INNER JOIN t_salary 
ON t_employee.dept_id=t_department.did AND t_employee.eid=t_salary.eid;

mysql 进阶

3.4 外连接(OUTER JOIN)

外连接分为:

左外连接(LEFT OUTER JOIN),简称左连接(LEFT JOIN)

右外连接(RIGHT OUTER JOIN),简称右连接(RIGHT JOIN)

全外连接(FULL OUTER JOIN),简称全连接(FULL JOIN)。

左连接(LEFT JOIN)

mysql 进阶

右外连接(RIGHT JOIN)

mysql 进阶

外连接(FULL JOIN)

mysql不支持FULL JOIN,但是可以用 left join **union **right join代替

mysql 进阶

自连接

当table1和table2本质上是同一张表,只是用取别名的方式虚拟成两张表以代表不同的意义。然后两个表再进行内连接,外连接等查询

自连接
#查询员工姓名以及领导姓名,仅显示有领导的员工
SELECT emp.ename,mgr.ename 
FROM t_employee AS emp, t_employee AS mgr
WHERE emp.mid = mgr.eid;

#查询员工姓名以及领导姓名,仅显示有领导的员工
SELECT emp.ename,mgr.ename 
FROM t_employee AS emp INNER JOIN t_employee AS mgr
ON emp.mid = mgr.eid;

#查询所有员工姓名及其领导姓名
SELECT emp.ename,mgr.ename 
FROM t_employee AS emp LEFT JOIN t_employee AS mgr
ON emp.mid = mgr.eid;

四、select的5个子句

4.1 where条件查询

从原表中的记录中进行筛选

4.2 group by 分组查询

很多情况下,用户都需要进行一些汇总操作,比如统计整个公司的人数或者统计每一个部门的人数等。

4.2.1聚合函数

  • AVG(【DISTINCT】 expr) 返回expr的平均值
  • COUNT(【DISTINCT】 expr)返回expr的非NULL值的数目
  • MIN(【DISTINCT】 expr)返回expr的最小值
  • MAX(【DISTINCT】 expr)返回expr的最大值
  • SUM(【DISTINCT】 expr)返回expr的总和
#聚合函数
#AVG(【DISTINCT】 expr) 返回expr的平均值
SELECT AVG(basic_salary) FROM t_salary;

#COUNT(【DISTINCT】 expr)返回expr的非NULL值的数目
#统计员工总人数
SELECT COUNT(*) FROM t_employee;#count(*)统计的是记录数
#统计员工表的员工所在部门数
SELECT COUNT(dept_id) FROM t_employee;#统计的是非NULL值
SELECT COUNT(DISTINCT dept_id) FROM t_employee;#统计的是非NULL值,并且去重

#MIN(【DISTINCT】 expr)返回expr的最小值
#查询最低基本工资值
SELECT MIN(basic_salary) FROM t_salary;

#MAX(【DISTINCT】 expr)返回expr的最大值
#查询最高基本工资值
SELECT MAX(basic_salary) FROM t_salary;

#查询最高基本工资与最低基本工资的差值
SELECT MAX(basic_salary)-MIN(basic_salary) FROM t_salary;

#SUM(【DISTINCT】 expr)返回expr的总和
#查询基本工资总和
SELECT SUM(basic_salary) FROM t_salary;

4.2.2 group by + 聚合函数

#group by + 聚合函数
#统计每个部门的人数
SELECT dept_id,COUNT(*) FROM t_employee
GROUP BY dept_id;

#统计每个部门的平均基本工资
SELECT emp.dept_id,AVG(s.basic_salary )
FROM t_employee AS emp,t_salary AS s
WHERE emp.eid = s.eid
GROUP BY emp.dept_id;

#统计每个部门的年龄最大者
SELECT dept_id,MIN(birthday) FROM t_employee GROUP BY dept_id;

#统计每个部门基本工资最高者
SELECT emp.dept_id,MAX(s.basic_salary )
FROM t_employee AS emp,t_salary AS s
WHERE emp.eid = s.eid
GROUP BY emp.dept_id;

#统计每个部门基本工资之和
SELECT emp.dept_id,SUM(s.basic_salary )
FROM t_employee AS emp,t_salary AS s
WHERE emp.eid = s.eid
GROUP BY emp.dept_id;

注意:****

用count(*),count(1),谁好呢?

其实,对于myisam引擎的表,没有区别的.

这种引擎内部有一计数器在维护着行数.

Innodb的表,用count(*)直接读行数,效率很低,因为innodb真的要去数一遍.

关于mysql的group by的特殊:

注意:在SELECT 列表中所有未包含在组函数中的列都应该是包含在 GROUP BY 子句中的,换句话说,SELECT列表中最好不要出现GROUP BY子句中没有的列。

对于标准语句来说,这个语句是错误的,但是mysql可以这么干,出于可移植性和规范性,不推荐这么写。

4.3 having 筛选

having与where类似,可筛选数据

having与where不同点

  • where针对表中的列发挥作用,查询数据;having针对查询结果中的列发挥作用,筛选数据
  • where后面不能写分组函数,而having后面可以使用分组函数
  • having只用于group by分组统计语句
#按照部门统计员工人数,仅显示部门人数少于3人的
SELECT dept_id,COUNT(*) AS c 
FROM t_employee 
WHERE dept_id IS NOT NULL
GROUP BY dept_id
HAVING c <3;

#查询每个部门的平均工资,并且仅显示平均工资高于10000
SELECT emp.dept_id,AVG(s.basic_salary ) AS avg_salary
FROM t_employee AS emp,t_salary AS s
WHERE emp.eid = s.eid AND dept_id IS NOT NULL
GROUP BY emp.dept_id
HAVING avg_salary >10000;

4.4 order by 排序

  • 按一个或多个字段对查询结果进行排序

用法:order by col1,col2,col3...

说明:先按col1排序如果col1相同就按照col2排序,依次类推

col1,col2,col3可以是select后面的字段也可以不是

  • 默认是升序,也可以在字段后面加asc显示说明是升序,desc为降序

例如:order by click_count desc;

? 如果两个字段排序不一样,例如:

? order by 字段1 asc ,字段2 desc;

  • order by 后面除了跟1个或多个字段,还可以写表达式,函数,别名等

mysql 进阶

上一篇:PostgreSQL libpq 客户端接口(一)


下一篇:oracle 序列如何建同义词