Mysql安装步骤
点击next进行安装
用户自定义安装
在“Developer Components(开发者部分)”上左键单击,
选择“This feature, and all subfeatures, will be installed on local hard drive.”
点击change按钮 修改安装目录
这里是询问你是否要注册一个mysql.com的账号,或是使用已有的账号登陆mysql.com,一般不需要了,点选“Skip Sign-Up”,按“Next”略过此步骤
将 “Configure the Mysql Server now”前面的勾打上,点“Finish”结束软件的安装并启动mysql配置向导
选择安装模式
安装成功
使用Navicat操作Mysql数据库
创建数据库
右键点击创建的数据库连接,选择新建数据库
数据库名没有固定要求,字符集选择UTF-8
使用SQL语句的方式
CREATE DATABASE [IF NOT EXISTS] 数据库名
使用IF NOT EXISTS关键字,则当指定的数据库名存在时,不创建数据库。
如果不使用IF NOT EXISTS关键字,当创建的数据库名存在时,将产生错误。
创建表
create table 表明(
列名 数据类型 [约束] [默认值],
列名 数据类型 [约束] [默认值],
)
练习
创建学生表(Student) 学号-变长字符型(10),姓名-变长字符型(30)
性别-定长字符型(2),出生日期-日期类型
创建班级表(classes) ,班级编号-定长字符(4),班级名称-变长字符(30)
Mysql中常用的数据类型
- 数据类型: 数字型: int,bigint
- 变长字符串: varchar
- 定长字符串:char
- 小数型: float, double
- 日期型: date(年月日)
- datatime(年月日时分秒)
Mysql中的约束
对表中的数据加以限制,保证数据的安全性和严谨
- 主键约束(primary key):主键约束相当于 唯一约束 + 非空约束 的组合,主键约束列中的数据不允许重复,也不允许出现空值,每个表最多只允许一个主键。
建表是在列上添加主键约束
create table temp(
id int primary key,
name varchar(20)
);
建表后添加主键约束
alter table temp add primary key(id);
- 非空约束(not null):非空约束用于确保当前列的值不为空值
非空约束只能定义在列上
create table temp(
id int primary key,
name varchar(255) not null,
);
- 唯一性约束(unique):该列中的数据不能有重复
create table temp(
id int primary key ,
name varchar(20) not null,
password varchar(10), unique(name,password)
);
- 外键约束 (foreign key):外键约束是保两个表之间的参照完整性
--主表
create table temp(
id int primary key,
name varchar(20)
);
-- 副表
create table temp2(
id int,
name varchar(20),
classes_id int,foreign key(id) references temp(id)
);
插入数据
insert into table_name [ (列名1,列2...) ] values(值1,值2,...)
- 如果列名部分不写任何内容,表示默认对所有列插入数据
- values中值的顺序必须与列对应相同
- 插入字符和日期类型数据时,必须使用单引号括起来
练习:向学生表插入数据
1. s01 ,张三,男,1999-9-9
2. s02 ,李四,男,1997-5-9
3. s03 ,霸王龙,男,1989-4-7
4. s01 ,虞姬,女,1979-2-6
5. s01 ,花木兰,女
批量插入数据
INSERT INTO 表名[(字段列表)] VALUES
(值列表1),
(值列表2),
…
(值列表n);
修改数据
update 表名 set 列 = 修改后的值,[ 列 =修改后的值 ]
[ where 限制条件 ]
1.将修改张三的性别改为女
2.将学号s03学生的出生日期加两天
删除数据
delete [ from ] 表名 [where 限制条件]
练习
使用如下语句,创建学生表student和班级表class
create table student ( --学生表
xh char(4),--学号
xm varchar(10),--姓名
sex char(2),--性别
birthday date,--出生日期
sal double(7,2), --奖学金
studentcid int(2), --学生班级号
foreign key(studentcid) references classes(classid)
)
Create table classes ( --班级表
classid in(2), --班级编号
cname varchar(20),--班级名称
ccount int(3) --班级人数
)
基于上述学生表和班级表,完成如下问题
(1)添加三个班级信息为:1,JAVA1班,null
2,JAVA2班,null
3,JAVA3班,null
(2)添加学生信息如下:‘A001’,‘张三’,‘男’,‘01-5月-05’,100,1
(3)添加学生信息如下:'A002','MIKE','男','1905-05-06',10
(4)插入部分学生信息: 'A003','JOHN','女’
(5)将A001学生性别修改为'女‘
(6)将A001学生信息修改如下:性别为男,生日设置为1980-04-01
(7)将生日为空的学生班级修改为Java3班
(8)请使用一条SQL语句,使用子查询,更新班级表中每个班级的人数字段
使用如下语句,建立以下表
CREATE TABLE copy_emp (
empno int(4),
ename varchar(20),
hiredate date,
deptno int(2),
sal double(8,2)
)
.在第三题表的基础上,完成下列问题
(1)在表copy_emp中插入数据,要求sal字段插入空值,部门号50,参加工作时间为2000年1月1日,其他字段随意
(2)在表copy_emp中插入数据,要求sal字段插入5000,部门号20,参加工作时间为2000年1月1日,姓名张三,编号1001
(3)修改copy_emp表中数据,要求10号部门所有员工涨20%的工资
(4)修改copy_emp表中sal为空的记录,工资修改为1000
(5)另外打开窗口2查看以上修改
(6)窗口1执行commit,窗口2中再次查看以上信息
(7)删除工资为空的员工信息
(8)执行rollback
TRUNCATE和DELETE区别
TRUNCATE是DDL,只能删除表中所有记录,释放存储空间,使用ROLLBACK不可以回滚。
DELETE是DML,可以删除指定记录,不释放存储空间,使用ROLLBACK可以回滚
事务
事务:也称工作单元,是由一个或多个SQL语句所组成的操作序列
这些SQL语句作为一个完整的工作单元,要么全都执行成功,要么全都执行失败。在数据库中,通过事务来保证数据的一致性。
事务的四个特性
原子性:组成事务的DML操作语句要么全成功,要么全失败,不可能出现部分成功部分失败的情况。
一致性:一旦事务完成,不管是成功的,还是失败,整个系统处于数据一致的状态
隔离性:一个事务的执行不会被另一个事务所干扰
持久性:事务一旦提交,对数据的改变就是永久的,不可以再被回滚
隐式提交:当下列任意一种情况发生时,会发生隐式提交
- 执行一个DDL(CREATE、ALTER、DROP、TRUNCATE、RENAME)语句;
隐式回滚:当下列任意一种情况发生时,会发生隐式回滚
- 客户端强行退出
- 客户端连接到服务器端异常中断
- 系统崩溃
MySQL默认是自动提交的,也就是你提交一个sql,就直接执行!
可以通过 set autocommit = 0 禁止自动提交
set autocommit = 1 开启自动提交 来实现事务的处理。
但要注意当用set autocommit = 0 的时候,以后所有的sql都将作为事务处理
直到用commit确认或 rollback结束
简单查询
CREATE TABLE `emp` (
`EMPNO` int(4) NOT NULL,
`ENAME` varchar(10) DEFAULT NULL,
`JOB` varchar(9) DEFAULT NULL,
`MGR` int(4) DEFAULT NULL,
`HIREDATE` date DEFAULT NULL,
`SAL` int(7) DEFAULT NULL,
`COMM` int(7) DEFAULT NULL,
`DEPTNO` int(2) DEFAULT NULL,
PRIMARY KEY (`EMPNO`),
KEY `FK_DEPTNO` (`DEPTNO`),
CONSTRAINT `FK_DEPTNO` FOREIGN KEY (`DEPTNO`) REFERENCES `dept` (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', null, '20');
INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', null, '20');
INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', null, '30');
INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', null, '10');
INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', null, '20');
INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', null, '1981-11-17', '5000', null, '10');
INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN','7698', '1981-09-08', '1500', '0', '30');
INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', null, '20');
INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', null, '30');
INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', null, '20');
INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', null, '10');
CREATE TABLE `dept` (
`DEPTNO` int(2) NOT NULL,
`DNAME` varchar(14) DEFAULT NULL,
`LOC` varchar(13) DEFAULT NULL,
PRIMARY KEY (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON');
查询所有列的数据
select * from 表名
select 列1,列2,列3... from 表名
查询指定列的数据
select 列1 [ ,列2] from 表名
运算符
+ , - ,* ,/
运算符的优先级
- 乘除优先于加减
- 相同优先权的表达式按照从左至右的顺序依次计算
- 括弧可以提高优先权,并使表达式的描述更为清晰
空值(NULL)是指一种无效的、未赋值、未知的或不可用的值。
空值不同于零或者空格。
- 任何包含空值的算术表达式运算后的结果都为空值NULL。
列别名 :用来对列重新命名,简化列名
列名的使用规则
方式1:列名 列别名
方式2:列名 AS 列别名
以下三种情况列别名两侧需要添加双引号
- 列别名中包含有空格
- 列别名中要求区分大小写
- 列别名中包含有特殊字符
DISTINCT关键字消除重复数据
限制条件
--限制数据
--实际就是对检索的数据加上限制条件
--只有符合条件的数据才会显示在结果集中
--不符合条件的数据则不会显示
--语法 WHERE + 限制条件
-- select name ,身高
-- from emp
-- where 身高>180
--身高>180 逻辑表达式/条件表达式
-- 条件表达式 :> , < ,>=, <= ,<> != ,=
--查询部门号为10的员工姓名和薪资
select ename,sal,deptno
from emp
where deptno=10
SQL语句分析方式
-- 需要检索的列有哪些
-- 这些列来自于那张表
-- 是否存在限制条件
-- 查询薪资大于等于1500的员工编号和姓名以及薪资
-- 员工编号 姓名 薪资
-- EMP
-- 薪资大于等于1500
select empno ,ename ,sal
from emp
where sal>=1500;
特殊比较操作符
-- between 数值1 and 数值2
-- 表示某个列的值是否在数值1和数值2之间
select ename ,sal from emp where sal between 1500 and 3000;
--查询入职日期在81年2月22号之后入职的员工有哪些
-- 姓名/*
-- emp
-- 入职日期在81年2月22号之后 hiredate>81年2月22号
select * from emp
where hiredate>'02-4月-81'
--查询员工SMITH的薪资是多少
--检索薪资
--emp
--员工smith的薪资
select sal from emp
where ename='SMITH ';
--数值类型直接进行比较
--日期类型 需要写在单引号中 注意日期类型的数据书写格式 DD-MMM-YY
--字符类型 需要写在单引号中 区分大小写
--查询在81年2月20号 到 81年9月28号期间入职的员工有哪些
-- */ename
-- emp
-- between .. and
select ename ,hiredate
from emp
where hiredate between '20-2月-81' and '28-9月-81';
-- In()
-- 判断要比较的值是否于集合列表中的任意一个数据相同
--集合列表 表示括号中放入的值
select ename,deptno
from emp
where deptno in(10,30);
--查询薪资等于1500 或者等于3000的员工姓名和薪资
-- ename ,sal
--emp
-- sal=1500或者=3000
select ename,sal
from emp
where sal in(3000);
--is null 表示为空
判断要比较的值是不是为空
-- is not null 表示不为空
select ename ,comm
from emp
where comm is null
select ename ,comm
from emp
where comm is not null
--查询那些员工没有上级领导
select ename ,mgr
from emp
where mgr is null;
-- LIKE
-- 表示部分匹配
-- % 表示任意个字符 _ 表示一个字符
--查询员工姓名第一个字母是A的有哪些
select ename from emp
where ename like 'A%';
--查询员工姓名中第二个字母是A的有哪些
select ename from emp
where ename like '_A%';
逻辑比较符
-- and
-- 将多个条件表达式进行合并
-- 条件表达式1 and 条件表达式2
-- 只有1和2同时成立 整个结果才成立
-- 只要1和2当中有一个不成立 整个结果则不成立
select ename ,sal
from emp
where sal>=1500
and sal<=3000;
-- 查询部门号为10并且薪资大于1500的员工姓名,薪资,部门号
select ename,sal ,deptno
from emp
where deptno=10
and sal>1500;
--查询部门号为20,薪资大于800并且职位是SALESMAN
--的员工姓名,职位及薪资
select ename,sal,job
from emp
where deptno=30 AND sal>800 AND job='SALESMAN';
-- OR
-- 条件表达式1 OR 条件表达式2
-- 要求1或2中只要有一个成立 则整个结果成立
--查询薪资大于1500或者部门号为10的员工姓名和薪资以及部门
select ename ,sal ,deptno
from emp
where sal > 1500 or deptno=10;
--查询部门号不等于20的员工姓名
select ename from emp
where deptno<>20;
select ename from emp
where deptno!=20;
- 逻辑运算符 AND 的优先级高于 OR
-- 可以适用括号改变逻辑表达式的优先级
SELECT ename, job, sal
FROM emp
WHERE
( job='SALESMAN' OR job='PRESIDENT') AND sal>1500;
--排序 order by
-- ASC 表示升序 DESC 降序
--默认就是升序
select ename ,sal
from emp
order by sal desc;
排序规则(以升序为例)
数字升序排列小值在前,大值在后。即按照数字大小顺序由小到大排列。
日期升序排列相对较早的日期在前,较晚的日期在后。
字符升序排列按照字母由小到大的顺序排列。即由A-Z排列;中文升序按照字典顺序排列。
空值在升序排列中排在最前面,在降序排列中排在最后。
--多字段排序规则
先以第一个列进行排序 当第一个列中
出现重复记录时 再以后面列进行排序
order by 子句永远写在select语句的最后
使用select语句时,经常要返回前几条或者中间某几行记录,可以使用关键字limit。语法格式如下:
select 字段列表
from 数据源
limit [start,]length;
说明:
1.limit接受一个或两个整数参数。start表示从第几行记录开始输出,length表示输出的记录行数。
2.表中第一行记录的start值为0(不是 1)。
练习
1.使用两种方式查询所有员工(EMP)信息
2.查询(EMP)员工编号、员工姓名、员工职位、员工月薪、工作部门编号。
3.员工转正后,月薪上调20%,请查询出所有员工转正后的月薪。
4.员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作第一年的年薪所得
(不考虑奖金部分,年薪的试用期6个月的月薪+转正后6个月的月薪)
5.查询员工表中一共有哪几种岗位类型。
6.查询职位为SALESMAN的员工编号、职位、入职日期。
7.查询1985年12月31日之前入职的员工姓名及入职日期。
8.查询部门编号不在10部门的员工姓名、部门编号。
9.查询入职日期在82年至85年的员工姓名,入职日期。
10.查询月薪在3000到5000的员工姓名,月薪。
11.查询部门编号为10或者20的员工姓名,部门编号。
12.查询经理编号为7902, 7566, 7788的员工姓名,经理编号。
13.查询员工姓名以W开头的员工姓名。
14.查询员工姓名倒数第2个字符为T的员工姓名。
15.查询奖金为空的员工姓名,奖金。
16.查询工资超过2000并且职位是MANAGER,或者职位是SALESMAN的员工姓名、职位、工资
17.查询工资超过2000并且职位是 MANAGER或SALESMAN的员工姓名、职位、工资。
18.查询部门在10或者20,并且工资在3000到5000之间的员工姓名、部门、工资。
19.查询入职日期在81年,并且职位不是SALES开头的员工姓名、入职日期、职位。
20.查询职位为SALESMAN或MANAGER,部门编号为10或者20,姓名包含A的员工姓名、职位、部门编号。
21.查询部门在20或30的员工姓名,部门编号,并按照工资升序排序。
22.查询工资在2000-3000之间,部门不在10号的员工姓名,部门编号,工资,
并按照部门升序,工资降序排序。
23.查询入职日期在82年至83年之间,职位以SALES或者MAN开头的员工姓名,入职日期,职位,
并按照入职日期降序排序。
24.查询入职时间在1982-7-9之后,并且不从事SALESMAN工作的员工姓名、入职时间、职位。
25.查询员工姓名的第三个字母是a的员工姓名。
26.查询除了10、20号部门以外的员工姓名、部门编号。
27.查询部门号为30号员工的信息,先按工资降序排序,再按姓名升序排序。
28.查询没有上级的员工(经理号为空)的员工姓名。
29.查询工资大于等于4500并且部门为10或者20的员工的姓名\工资、部门编号
30.查询入职日期最早的前5名员工姓名,入职日期。
Mysql 单行函数
数值函数
ABS(x):返回x的绝对值;
SQRT(x):返回非负数x的平方根;
PI():返回圆周率;
MOD(x,y)或%:返回x被y除的余数;
CEIL(x)、CEILING(x):返回大于或者等于x的最小整数值;
FLOOR(x):返回小于或者等于x的最大整数值;
ROUND(x,y):返回保留小数点后面y位,四舍五入的整数;
TRUNCATE(x,y):返回被舍弃的小数点后y位的数字x;
RAND():每次产生不同的随机数;
POW(x,y)和POWER(x,y): 返回x的y次乘方的结果值;
练习
1.写一个查询,分别计算100.456 四舍五入到小数点后第2位,第1位,整数位的值。
2.写一个查询,分别计算100.456 从小数点后第2位,第1位,整数位截断的值。
字符函数
CHAR_LENGTH(str):返回字符串str的所包含字符个数;
LENGTH(str):返回字符串str的长度;
CONCAT(s1,s2,...): 字符串连接;
CONCAT_WS(x,s1,s2,…):字符串连接, x是其它参数的分隔符;
INSERT(s1,x,len,s2) :返回字符串s1,s1中插入字符串s2;
LOWER (str)|LCASE (str):将字符串全部转换成小写字母;
UPPER(str)|UCASE(str):将字符串全部转换成大写字母;
LEFT(s,n):返回最左边指定长度的字符;
RIGHT(s,n):返回最右边指定长度的字符;
LPAD(s1,len,s2) | RPAD(s1,len,s2) :填充字符串函数;
TRIM(s1 FROM s) | LTRIM(s)|RTRIM(s):删除空格函数;
REPEAT(s,n):重复生成字符串函数;
SPACE(n):返回一个由n个空格组成的字符串;
REPLACE(s,s1,s2):字符串替换函数;
STRCMP(s1,s2):比较字符串大小函数;
SUBSTRING(s,n,len):获取子串函数;
LOCATE(str1,str) | POSITION(str1 IN str) | INSTR(str, str1):匹配子串开始位置函数;
REVERSE(s):将字符串s反转;
练习
1.显示所有员工姓名的前三个字符
2.显示正好为5个字符的员工的姓名,工资,部门号
3.写一个查询,用首字母大写,其它字母小写显示雇员的 ename,显示名字的长度,.
并给每列一个适当的标签,条件是满足所有雇员名字的开始字母是J、A 或 M 的雇员,
并对查询结果按雇员的ename升序排序。(提示:使用length、substr)
4.查询员工姓名中中包含大写或小写字母A的员工姓名。
5.显示所有员工的姓名,用a替换所有"A"
6.查询部门编号为10或20,入职日期在81年5月1日之后,并且姓名中包含大写字母A的员工姓名,员工姓名长度
7.查询每个职工的编号,姓名,工资要求将查询到的数据按照一定的格式合并成一个字符串.
前10位:编号,不足部分用*填充,左对齐
中间10位:姓名,不足部分用*填充,左对齐
后10位:工资,不足部分用*填充,右对齐
日期函数
CURDATE()和CURRENT_DATE() :获取当前日期函数;
NOW():返回服务器的当前日期和时间;
CURTIME():返回当前时间,只包含时分秒;
TIMEDIFF(expr1, expr2):返回两个日期相减相差的时间数;
DATEDIFF(expr1, expr2):返回两个日期相减相差的天数;
DATE_ADD(date,INTERVAL expr type):日期加上一个时间间隔值;
DATE_SUB(date,INTERVAL expr type):日期减去一个时间间隔值;
DATE(date)、TIME(date)、YEAR(date):选取日期时间的各个部分:
EXTRACT(unit FROM date):从日期中抽取出某个单独的部分或组合;
DAYOFWEEK(date) 、DAYOFMONTH(date) 、DAYOFYEAR(date):返回日期在一周、一月、一年中是第几天
DAYNAME、MONTHNAME:返回日期的星期和月份名称;
DATE_FORMAT(date,format):格式化日期;
TIME_FORMATE(time,formate):格式化时间;
type
YEAR ,MONTH,DAY ,HOUR,MINUTE,SECOND
格式码 format
%a 缩写星期名
%b 缩写月名
%c 月,数值
%D 带有英文前缀的月中的天
%d 月的天,数值(00-31)
%e 月的天,数值(0-31)
%f 微秒
%H 小时 (00-23)
%h 小时 (01-12)
%I 小时 (01-12)
%i 分钟,数值(00-59)
%j 年的天 (001-366)
%k 小时 (0-23)
%l 小时 (1-12)
%M 月名
%m 月,数值(00-12)
%p AM 或 PM
%r 时间,12-小时(hh:mm:ss AM 或 PM)
%S 秒(00-59)
%s 秒(00-59)
%T 时间, 24-小时 (hh:mm:ss)
%U 周 (00-53) 星期日是一周的第一天
%u 周 (00-53) 星期一是一周的第一天
%V 周 (01-53) 星期日是一周的第一天,与 %X 使用
%v 周 (01-53) 星期一是一周的第一天,与 %x 使用
%W 星期名
%w 周的天 (0=星期日, 6=星期六)
%X 年,其中的星期日是周的第一天,4 位,与 %V 使用
%x 年,其中的星期一是周的第一天,4 位,与 %v 使用
%Y 年,4 位
%y 年,2 位
转换函数
if 函数:IF(expr1,expr2,expr3)
如果表达式1成立,返回结果是表达式2的值,否则返回表达式3的值
返回结果可以是数值,也可以是字符串
SELECT IF(1>2,1,2) from dual; - - 2
SELECT IF(1<2,1,2) from dual; - -1
IFNULL函数:IFNULL(n,m)
如果n的不为null则返回n的值,否则返回m的值
select IFNULL(1,2) FROM dual; - -1
select IFNULL(null,2) FROM dual - -2
练习
1.查询服务器当前时间
2.查询部门10,20的员工截止到2000年1月1日,工作了多少个月,入职的月份。
3.如果员工试用期6个月,查询职位不是MANAGER的员工姓名,入职日期,
转正日期,入职日期是第多少月,第多少周
4.计算2000年1月1日到现在有多少月,多少周(四舍五入)。
5.查询员工ENAME的第三个字母是A的员工的信息(使用2个函数)。
6.使用trim函数将字符串‘hello’、‘ Hello ’、‘bllb’、‘ hello ’
分别处理得到下列字符串ello、Hello、ll、hello。
7.将员工工资按如下格式显示:123,234.00 RMB 。
8.查询员工的姓名及其经理编号,要求对于没有经理的显示“No Manager”字符串。
9.将员工的参加工作日期按如下格式显示:月份/年份
10.创建一个查询显示所有雇员的 ename和 sal。格式化sal为 15 个字符长度,用 $ 左填充,列标签 SALARY
CREATE TABLE SALGRADE(
GRADE int,
LOSAL int,
HISAL int
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO SALGRADE VALUES (1,700,1200);
INSERT INTO SALGRADE VALUES (2,1201,1400);
INSERT INTO SALGRADE VALUES (3,1401,2000);
INSERT INTO SALGRADE VALUES (4,2001,3000);
INSERT INTO SALGRADE VALUES (5,3001,9999);
多表连接
在多个表之间通过一定的连接条件,使表之间发生关联,进而能从多个表之间获取数据
select table1.colum ,table2.colum from table1,table2
以上SQL已经实现了两个的连接,但是查询的结果集中会存在大量的重复数据
笛卡尔积:第一个表中的所有行和第二个表中的所有行都发生连接。
select table1.colum ,table2.colum from table1,table2
where 表之间的关联条件
等值连接
查询员工姓名,薪资,部门地点
查询员工编号,职位,工作地点,部门号,部门名称
使用and 添加其他限制条件
多表关联时,如何使用了两个表中相同名字的列,需要进行区分
通过表别名简化SQL
练习
1.写一个查询,显示所有员工姓名,部门编号,部门名称。
2.写一个查询,显示所有工作在CHICAGO并且奖金不为空的员工姓名,工作地点,奖金
3.写一个查询,显示所有姓名中含有A字符的员工姓名,工作地点。
非等值连接
查询每个员工的姓名,工资,工资等级
三个表关联查询
查询每个员工的编号,姓名,工资,工资等级,所在工作城市,按照工资等级进行升序排序
自连接,是一个表通过某种条件和本身进行连接的一种方式,就如同多个表连接一样
查询每个员工的姓名和直接上级姓名
查询所有工作在NEW YORK和CHICAGO的员工姓名,员工编号,以及他们的经理姓名,经理编号。
SQL99 标准关系型数据库语法
交叉连接会产生连个表的交叉乘积,和两个表之间的笛卡尔积是一样的;
SELECT emp.empno,emp.ename,emp.sal,emp.deptno,dept.loc
FROM emp
CROSS JOIN dept;
多表关联语法
join :两边写需要进行关联的数据表
on : 表的关联条件
SELECT e.empno, e.ename, e.deptno, d.deptno, d.loc
FROM emp e JOIN dept d
ON (e.deptno = d.deptno);
查询所有雇员姓名,部门编号,部门名称,包括没有部门的员工也要显示出来
左外连接 join关键字 左边的表为主表,主表中不满足关联条件的数据也查询出来
SELECT e.empno, e.ename, e.deptno, d.deptno, d.loc
FROM emp e LEFT JOIN dept d
ON (e.deptno = d.deptno);
右外连接 join关键字 右边的表为主表,主表中不满足关联条件的数据也查询出来
SELECT e.empno, e.ename, e.deptno, d.deptno, d.loc
FROM emp e RIGHT JOIN dept d
ON (e.deptno = d.deptno);
练习
1.使用ON子句,显示工作在CHICAGO的员工姓名,部门名称,工作地点,薪资等级
2.使用左连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。
3.使用右连接,查询每个员工的姓名,经理姓名,没有经理的King也要显示出来。
4.显示员工SMITH的姓名,部门名称,直接上级名称
5.显示员工姓名,部门名称,工资,工资级别,要求工资级别大于4级。
6.显示员工KING和FORD管理的员工姓名及其经理姓名。
7.显示员工姓名,参加工作时间,经理名,参加工作时间,要求参加时间比经理早。
8.显示工作在CHICAGO的员工姓名,部门名称,工作地点
9.显示入职日期在81年2月1日之后的员工姓名,部门名称,入职日期
10.显示员工JONSE的部门名称,直接上级名称
11.列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
12.查询所有工作在NEW YORK和CHICAGO的员工姓名,员工编号
13.查询所有工作在NEW YORK和CHICAGO的员工姓名,员工编号,以及他们的经理姓名,经理编号
14.显示所有工作在CHICAGO并且奖金不为空的员工姓名,工作地点,奖金
15.写一个查询,显示所有姓名中含有A字符的员工姓名,工作地点
16.查询部门人数在2人以上的部门名称、最低工资、最高工资,并对求得的工资进行
四舍五入到整数位。
分组函数
--MAX() MIN() SUM() AVG() COUNT()
--MAX() 求一组数据的最大值
--MIN() 求一组数据的最小值
MIN和MAX可以用于任何数据类型
--SUM() 求一组数据的和
--AVG() 求一组数据的平均值
SUM和AVG函数都是只能够对数值类型的列或表达式操作
--COUNT() 统计数 / 记录数
除了COUNT(*)之外,其它所有分组函数都会忽略列中的空值,然后再进行计算
--查询emp表中的薪资的最大值和最小值
--求所有员工薪资和
--求所有员工平均薪资
--查询有多少部门
--查询20部门的最高薪资
--查询部门20的员工,每个月的工资总和及平均工资。
-- 查询工作在CHICAGO的员工人数,最高工资及最低工资。
-- 查询员工表中一共有几种岗位类型。
通过 GROUP BY 子句可将表中满足WHERE条件的记录按照指定的列划分成若干个小组
问题: 求各部门平均工资
在SELECT子句中的列除了分组函数那些项,所有列都必须包含在GROUP BY 子句中。
SELECT ename,deptno, AVG(sal)
FROM emp
GROUP BY deptno;
练习
1.查询每个部门每个岗位的工资总和
2.查询每个部门的部门编号,部门名称,部门人数,最高工资,最低工资,工资总和,平均工资。
3.查询每个部门,每个岗位的部门编号,部门名称,岗位名称,部门人数,最高工资,最低工资,工资总和,平均工资。
4.查询每个经理所管理的人数,经理编号,经理姓名,要求包括没有经理的人员信息
分组函数不能使用在WHERE子句中
SELECT deptno, max(sal)
FROM emp
WHERE max(sal) > 2900
GROUP BY deptno;
使用 having 子句
SELECT deptno, max(sal)
FROM emp
GROUP BY deptno
having max(sal) >2900
练习
1.查询每个部门最高工资大于2900的部门编号,最高工资
2.查询部门人数大于2的部门编号,部门名称,部门人数。
3.查询部门平均工资大于2000,且人数大于2的部门编号,部门名称,部门人数,
部门平均工资,并按照部门人数升序排序
列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数
显示各种职位的最低工资
显示平均工资为>2000的职位
找每个部门的最高和最低的工资
找每个部门中每种职位的最高和最低的工资
显示出平均工资大于2000的部门名称及平均工资
显示每个部门每种工作平均工资大于2500的部门及工作
显示出工作名称中包含"MAN",并且平均工资大于1000的工作名称及平均工资
显示出平均工资最高的的部门平均工资
子查询
思考问题:查询比SMITH工资高的员工有哪些
子查询可以嵌于以下SQL子句中:
- WHERE子句
查询比JONES入职晚的员工姓名以及入职日期
- HAVING子句
查询部门最低工资比20部门最低工资高的部门编号及最低工资
- FROM子句
查询员工工资为其部门最低工资的员工的编号和姓名及工资
子查询只返回一行一列 使用单行运算符
>, < ,>= ,<= ,= ,<>
练习
1.查询入职日期最早的员工姓名,入职日期
2.查询工资比SMITH工资高并且工作地点在CHICAGO的员工姓名,工资,部门名称
3.查询入职日期比20部门入职日期最早的员工还要早的员工姓名,入职日期
4.查询部门人数大于所有部门平均人数的的部门编号,部门名称,部门人数
5.显示工资比'ALLEN'高的所有员工的姓名和工资
6.显示与'SCOTT'从事相同工作的员工的详细信息
7.显示与30号部门'MARTIN'员工工资相同的员工的姓名和工资
8.查询所有工资高于平均工资(平均工资包括所有员工)的销售人员('SALESMAN')
9.显示每个部门名称和人数
什么是视图
视图是逻辑上来自一个或多个表的数据集合
为什么使用视图
限制其它用户对数据库表的访问,因为视图可以有选择性的显示数据库表的一部分;
容易实现复杂的查询;
对于相同的数据可以产生不同的视图;
创建视图
CREATE [OR REPLACE] VIEW view_name [(column_list)]
AS select_statement
OR REPLACE:如果所创建的视图已经存在,该选项表示修改原视图的定义
view_name :视图的名称;
column_list :列名,列名的数量必须和视图所对应查询语句的列数量相等;
select_statement :一条完整的SELECT语句;
创建一个视图v_emp1,通过该视图只能查看10号部门的员工编号,员工姓名,职位。
CREATE VIEW v_emp1
AS SELECT empno, ename, job
FROM emp
WHERE deptno = 10;
练习
1.创建一个视图,通过该视图可以查询到工资在2000-5000内并且姓名中包含有A的员工编号,姓名,工资。
2.通过上述创建的视图查询数据
3.创建一个视图,通过该视图可以查询到工作在NEW YORK和CHICAGO的员工编号,姓名,部门编号,入职日期。
4.创建一个视图,通过该视图可以查询到每个部门的部门名称及最低工资。
视图是执行DML操作
如果定义视图的子查询中包含 分组函数 ,group by 子句和 distinct关键字
则不能对视图进行 增加,修改和删除操作
删除视图
drop view view_name
删除视图 并不会删除基本中的数据
索引简介
索引是一种特殊的数据库结构,可以用来快速查询数据库表中的特定记录。索引是提高数据库性能的重要方式。MySQL中,所有的数据类型都可以被索引。
索引的优点是可以提高检索数据的速度,这是创建索引的最主要的原因;对于有依赖关系的子表和父表之间的联合查询时,可以提高查询速度;使用分组和排序子句进行数据查询时,同样可以显著节省查询中分组和排序的时间。
创建索引
CREATE TABLE 表名(
id int PRIMARY KEY,
tname varchar(29),
INDEX(id)
)
创建新用户
1.CREATE USER '用户名'@'localhost' IDENTIFIED BY '密码';
此时新用户没有权限对数据库执行任何操作
为用户提供访问他们将需要的信息的权限
2.GRANT ALL PRIVILEGES ON * . * TO '用户名'@'localhost';
重新加载所有权限才会生效
3.FLUSH PRIVILEGES;
通过SQL 查询表结构
SELECT COLUMN_NAME, COLUMN_TYPE,
COLUMN_COMMENT FROM information_schema.`COLUMNS`
WHERE TABLE_NAME = 'xxx';
删除列的SQL
lter table table_name drop column column_name
删除表(撤销表)
DROP TABLE table_name
自动增长 AUTO_INCREMENT
建表后添加一个列默认设置默认值
Alter table table_name add colunm 数据类型 default 默认值
mysql 使用like '%A'的形式进行模糊查询,不会使用索引
解决办法:
将数据以倒序的方式存入数据库,再使用liek 'A%'进行查询即可
例如:
将网址url存入数据库,并且使用模糊查询
1.将网址倒序 www.baidu.com -> moc.udiab.www
2.like 'moc.%'
mysql的事务隔离级别
1.读未提交 (read uncommited)
age字段的原始值为7,事务A修改了age字段的值为12,但事务A处于未提交事务状态。
这时事务B在读取age字段值也是12.
事务B读取到了事务A未提交的数据,出现脏读。
2.读已提交 (read commited)
age字段的原始值为7,事务A修改了age字段的值为12,但事务A处于未提交事务状态。
这时事务B在读取age字段值仍然是7.
但是在事务A提交事务后,这时事务B再查询到的值就是12了,极短时间内两次相同的查询,
但是结果却不一样,这种情况是,不可重复读、幻读
3.可重复读 (repeatable read) mysql默认的隔离级别
age字段的原始值为7,事务A修改了age字段的值为12,事务A处于未提交事务状态。
这时事务B在读取age字段值仍然是7.但是事务A提交事务后,这时事务B再一次读取age字段值仍然还是7
这种情况解决了读已提交模式出现的不可重复读、幻读问题
读已提交 (read commited)这种隔离级别,是如何保证每个事务只能读到自己提交的数据的
mysql的每行记录存在一个隐藏列,用于存储最近一次修改这条记录的事务id
这行记录的每一个修改都会保留,以修改时间为顺序进行链式存储(最新修改->上一次修改->...)
事务A进行查询时,mysql会统计当前处于未提交状态的事务有哪些 例:{事务B,事务C,事务D}
将它们排除掉,然后在链式存储中找到最近一次已提交的事务获取它的值
可重复读 (repeatable read)这种隔离级别,是如何保证每个事务只能读到自己提交的数据的
事务A进行查询时,mysql会统计当前处于未提交状态的事务有哪些 例:{事务B,事务C,事务D}。
但是事务A下一次查询时,事务B已经提交了。但是事务A任然以之前的为准,不会更新未提交状态的事务列表,所以每次读取的值是一样的
mysql乐观锁实现:
使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据
1.数据库表设计
task : 有三个字段,分别是id,value、version
先读task表的数据(实际上这个表只有一条记录),得到version的值为versionValue
每次更新task表中的value字段时,为了防止发生冲突,需要这样操作
update task set value = newValue,version = versionValue + 1
where version = versionValue;
只有这条语句执行了,才表明本次更新value字段的值成功
mysql实现悲观锁
要使用悲观锁,我们必须关闭mysql数据库的自动提交属性,因为MySQL默认使用autocommit模式,
也就是说,当你执行一个更新操作后,MySQL会立刻将结果进行提交。
我们可以使用命令设置MySQL为非autocommit模式:
set autocommit=0;
设置完autocommit后,我们就可以执行我们的正常业务了。具体如下:
//0.开始事务
begin;/begin work;/start transaction; (三者选一就可以)
//1.查询出商品信息
select status from t_goods where id=1 for update;
//2.根据商品信息生成订单
insert into t_orders (id,goods_id) values (null,1);
//3.修改商品status为2
update t_goods set status=2 where id = 1;
//4.提交事务
commit;/commit work;
执行select status from t_goods where id=1 for update;后。
我在另外的事务中如果再次执行select status from t_goods where id=1 for update;
则第二个事务会一直等待第一个事务的提交,此时第二个查询处于阻塞的状态,
但是如果我是在第二个事务中执行select status from t_goods where id=1;则能正常查询出数据,不会受第一个事务的影响。