数据库(DataBase,简称DB):长期存储数据的仓库
数据库分类:层次式数据库、网络式数据库、关系型数据库
1.实现数据共享,减少数据冗余
2.采用特定的数据类型
3.具有较高的独立性
4.具有统一的数据控制功能
表:二维数组的集合
在保存应用实体数据时,通常会在数据库中创建多个表,以保存应用程序实体数据。一般来说应用程序中的一个javabean类可以对应一张数据库表。
行:记录
表中以一行记录保存一条信息,这样的一条记录称为表记录。可以认为一个javabean对象对应一条表记录。
列:字段
主键:Primary Key——不能为空、唯一标识记录
Oracle – 甲骨文公司开发,市场占有率第一
SQLServer – 微软公司开发,.Net技术中常用
DB2 – IBM公司开发
Sybase – Sybase公司开发
MySql – 瑞典MySql AB研发,非常受欢迎,已经被Oracle收购
SQLite – 小型轻量级开源关系型数据库,常用作嵌入式设备数据库
数据库服务器
指的就是一个数据库管理程序,这个程序可以管理多个数据库。
1.运行速度快
2.(社区版)免费
3.容易使用,易于学习
4.可移植性
5.丰富的接口:提供了C、C++、Java、PHP、Python等语言的API
6.支持查询语言:可以利用标准SQL语法,支持ODBC(Open Database Connectivity开放式数据库连接)的应用程序
7.安全性和连接性:十分灵活和安全的权限和密码系统,网络化——可以在Internet上访问,提高数据共享效率。
安装的路径不要有中文和空格
默认的端口3306,不要更改。
MySQL安装目录
MySQL的数据存储目录为data,data目录通常在C:\ProgramData\MySQL\MySQL Server 5.7\Data位置。在data下的每个目录都代表一个数据库。
ProgramData是隐藏文件。需更改文件夹显示设置才能看见。
MySQL的安装目录下:
bin目录中都是可执行文件;
my.ini文件是MySQL的配置文件;
方法一:
进入MySQL安装目录bin文件下,在地址栏输入cmd,Enter(也可以直接打开cmd输入地址)→mysql -h localhost -u root -p
提示:配好置环境变量,日后就可以在cmd界面直接输入运行命令(mysql -h localhost -u root -p )打开MySQL了。
步骤:计算机右键属性→高级系统设置→环境变量→点击Path→选中下方的path→编辑→新建→输入C:\Program Files\MySQL\MySQL Server 5.7\bin→确定
方法二:
菜单【开始】→所有程序→MySQL→MySQL Server 5.7→MySQL 5.7 Command Line Client→输入密码→Enter
方法三:(常用)
cmd→mysql -uroot -p输入密码→Enter
在登录成功后,打开windows任务管理器,会有一个名为mysql.exe的进程运行,所以mysql.exe是客户端程序。
退出:quit或exit
通过命令启动、停止、删除服务
启动:net start mysql;
启动:net stop mysql;
启动:sc delete 服务名称
如果服务吗中间有空格,就需要前后加引号
常用图形化管理工具:SQLyog——特点:简洁高效,功能强大
mysqldump -uroot -p test > test.sql
1.需先进入数据库客户端,创建空数据库
mysql>create database test
2.进入存储数据脚本的地方执行导入操作
mysql -uroot -p test < test.sql
3.输入密码,按Enter键完成。
步骤2也可以替换为如下操作:
mysql>use test;
mtsql>source /root/test.sql
SQL:Structured Query Language结构化查询语言,用于存取数据以及查询、更新和管理关系数据库系统。
语言特点
1.一体化:SQL集数据定义DDL、数据操纵DML和数据控制DCL于一体,可以完成数据库中的全部工作。
2.使用方式灵活:它具有两种使用方式,即可以直接以命令方式交互使用;也可以嵌入使用,嵌入到C、C++、FORTRAN、COBOL、JAVA等主语言中使用。
3.非过程化:只提操作要求,不必描述操作步骤,也不需要导航。使用时只需要告诉计算机“做什么”,而不需要告诉它“怎么做”。 [2]
4.语言简洁,语法简单,好学好用:在ANSI标准中,只包含了94个英文单词,核心功能只用6个动词,语法接近英语口语。
注意:语句结尾处一定要加(英文输入状态下的半角)分号;
库级别database
后续用db_name表示数据库名,用户可自定义命名。
create database db_name (默认采用数据库服务器编码)
create database db_name default character set utf8;(创建时指定编码)
要创建的数据库名不能与已经存在的数据库重名。
需要使用中文的话,创建数据库时,一定要记得指定字符集为gbk。
show databases;
show create database db_name;
查看数据库版本:
status;
drop database [if exists] db_name;
use db_name;
没有退出数据库的命令,如果想退出当前数据库进入另一个数据,直接use 另一个数据库 就可以了。
select database();
ALTER DATABASE db_name [alter_specification [, alter_specification] ...]
alter_specification:
[DEFAULT] CHARACTER SET charset_name | [DEFAULT] COLLATE collation_name
查看当前数据库中字符集配置:
show variables like’character%’;
其中:
client是客户端使用的字符集。
connection是连接数据库的字符集设置类型,如果程序没有指明连接数据库使用的字符集类型就按照服务器端默认的字符集设置。
database是数据库服务器中某个库使用的字符集设定,如果建库时没有指明,将使用服务器安装时指定的字符集设置。
results是数据库给客户端返回时使用的字符集设定,如果没有指明,使用服务器默认的字符集。
server是服务器安装时指定的默认字符集设定。
system是数据库系统使用的字符集设定。(utf-8不可修改)
set names xxx; 命令是客户端通知服务器和当前客户端交互时使用什么编码,但是这种方式每次新开客户端都需要通知服务器 很麻烦
我们可以修改mysql/my.ini,将default-character-set=gbk,这是修改服务器默认认为的客户端的字符集编码
这样一来,大部分人都是gbk的客户端,不需要设置任何东西,连进来就没乱码.如果有个别的人客户端不是gbk,也可以通过set names xxx;的方式声明自己的编码集,也没有乱码。
(1)字符串型:
VARCHAR:声明字段能存储的最大字符数。真实占用的空间取决于存入的字符数。mysql 5.0以前0255字节,之后是065535字节。
CHAR:固定长度
(2)数值类型
TINYINT:占用1个字节,相对于java中的byte
SMALLINT:占用2个字节,相对于java中的short
INT:占用4个字节,相对于java中的int
BIGINT:占用8个字节,相对于java中的long
FLOAT:4字节单精度浮点类型,相对于java中的float
DOUBLE:8字节双精度浮点类型,相对于java中的double
(3)大数据类型
BLOB:(Binary Large Object)大二进制类型,最大4GB,可以将图片、音频、视频等数据以二进制的形式存入数据库
TEXT:大文本,最大4GB。建议超过5000字以上使用。
注意:text属于mysql的方言,在其他数据库中为clob类型
(4)逻辑型
BIT:位类型,可以存储指定位的值,可以指定位的个数,如果不指定则默认值为1位,即只能保存0或1,对应到java中可以是boolean型。
(5)日期时间类型
date:日期,不能存时间 2018-7-16
time:时间,不能存日期 18:25:00
datetime:日期+时间 2018-7-16 18:25:00,年份范围1000~9999
timestamp:时间戳 时间戳 2015-11-05 19:19:19 年份范围:1970~2037
datetime和timestamp的区别:
相同点:显示结果一直,都是一样的格式。
不同点:
① 长度不同,时间范围不同
② timestamp可以通过设置实现自动更新
③ timestamp可以设置默认值
后续用tb_name表示表名,用户可自定义命名。
1.主键约束 primary key
(1)表数据的唯一标识
(2)非空(不能为null)且唯一
(3)可以使用多个字段组合作为当前表的主键
(4)可以搭配自增使用auto_increment
2.唯一约束 unique
(1)表示该字段的值彼此不能重复
(2)该字段的值可以为null,而且可以插入多个null值。对于mysql而要,null和任意值的比较结果都为false
3.非空约束 not null
(1)表中的字段不可以为null
4.外键约束
create table db_name(
field_name1 datatype,field_name2 datatype,field_name2 datatype
)[character set gbk] [collate 校对规则]
// 设定使用的字符集。[]里的内容可省略,默认是系统的字符集。
// field_name:指定列名 datatype:指定列类型
show tables;
show create table tabName;
desc 表名;
drop tb_name;
增加列:
ALTER TABLE tabname ADD (column datatype [DEFAULT expr][, column datatype]…);
修改列:
ALTER TABLE tabname MODIFY (column datatype [DEFAULT expr][, column datatype]…);
删除列:
ALTER TABLE tabname DROP (column);
修改表名:
ALTER TABLE old_tabname RENAME TO new_tabname;
或
RENAME TABLE old_tabname TO new_tabname;
修改列名称:
ALTER TABLE tabname CHANGE [column] old_col_name new_col_name datatype
修改列的顺序:
ALTER TABLE tabname MODIFY col_name1 datatype AFTER col_name2;
修改表的字符集:
ALTER TABLE tabname CHARACTER SET character_name;
修改存储引擎,默认InnoDB,改为:MyISAM
alter table form engine=MyISAM;
表中的记录
insert into
语法:
INSERT INTO tb_name [(column [, column…])] VALUES (value [, value…]);
方法一: insert into employee (id,name,gender,job,resume)
values (null,‘Winyar’,0,‘singing’,‘I like sing’);
方法二: insert into employee values
(null,‘Luthing’,1,‘singing’,‘He like Winyar’);
注意:
① 插入的数据应与字段的数据类型相同
② 数据的大小应在列的规定范围内
③ 在values中列出的数据位置必须与被加入的列的排列位置相对应
④ 字符串和日期格式的数据要用单引号引起来
⑤ 如果要插入所有字段可以省写列列表,直接按表中字段顺序写值列表
delete from
语法:
delete from tab_name [where_definition]
例:delete from employee where name=‘Linter’;
where用来筛选要删除的记录,如果不使用where子句,将删除表中所有数据。
delete语句不能删除某一列的值(可使用update)
delete语句仅删除记录,不删除表本身。如要删除表,使用drop table语句。
TRUNCATE TABLE tab_name语句也可以删除表中数据,它和delete有所不同。delete是一条条删除记录,truncate是摧毁整表再重建相同结构的表,truncate效率更高。
其中Where子句中支持:
Like语句中,% 代表零个或多个任意字符,_ 代表一个字符,例first_name like ‘_a%’;
update set
语法:
UPDATE tab_name SET col_name1=expr1 [, col_name2=expr2 …] [WHERE where_definition]
例:update employee set job=‘doctor’ where name=‘Winyar’;
UPDATE语法可以用新值更新原有表行中的各列。
SET子句指示要修改哪些列和要给予哪些值。
WHERE子句指定应更新哪些行。如没有WHERE子句,则更新所有的行。
select from
语法:
SELECT [DISTINCT] *|{column1, column2. column3…} FROM table;
例:select id,name,gender,job,resume from employee;
select 指定查询哪些列的数据。
column指定列名。
*号代表查询所有列。
from指定查询哪张表。
DISTINCT可选,指显示结果时,是否剔除重复数据
语法:
select *|列名 from tablename [WHERE where_definition]
例:select * from employee where name=‘Winyar’;
~查询英语成绩大于90分的同学
select * from exam where english > 90;
~查询总分大于230分的所有同学
select name 姓名,english+math+chinese 总分 from exam where english+math+chinese>230;
~查询语文分数在 80-100之间的同学。
select name,chinese from exam where chinese between 80 and 100;
~查询数学分数为75,76,77的同学。再查询分数不在这个范围内的同学
select name,math from exam where math in (75,76,77);
select name,math from exam where math not in (75,76,77);
~查询所有姓张的学生成绩。
select * from exam where name like ‘张%’;
select * from exam where name like ‘张_’;
select * from exam where name like ‘张__’;
~查询数学分>70,语文分>80的同学。
select * from exam where math>70 and chinese>80;
语法:
SELECT column1, column2. column3… FROM table order by column asc|desc;
Order by 指定排序的列,排序的列即可是表中的列名,也可以是select 语句后指定的列名。
Asc 升序、Desc 降序
ORDER BY 子句应位于SELECT语句的结尾。
SQL提供的聚合函数有计数函数COUNT()、求和函数SUM()、平均值函数AVG()、最大值函数用()、最小值函数MIN()等。如下表:
函数名称 | 函数功能 |
---|---|
COUNT() | 返回选取结果集中行的数目 |
SUM() | 返回选取结果集中所有值的总和 |
AVG() | 返回选取结果集中所有值的平均值 |
MAX() | 返回选取结果集中所有值的最大值 |
MIN() | 返回选取结果集中所有值的最小值 |
语法:
求符合条件的记录中指定列的记录数
select count(列名)… from tablename [WHERE where_definition]
求符合条件的记录中指定列的和值
select sum(列名)… from tablename [WHERE where_definition]
求符合条件的记录中指定列的平均值
select avg (列名)… from tablename [WHERE where_definition]
求符合条件的记录中指定列的最大值
select max(列名)… from tablename [WHERE where_definition]
求符合条件的记录中指定列的最小值
select min(列名)… from tablename [WHERE where_definition]
练习:
~统计一个班级共有多少学生?
select count() from exam;
~统计数学成绩大于75的学生有多少个?
select count() from exam where math>75;
~统计总分大于230的人数有多少?
select count(name) from exam
where ifnull(english,0)+ifnull(math,0)+ifnull(chinese,0) >230;
~统计一个班级数学总成绩?
select sum(math) from exam;
~统计一个班级语文、英语、数学各科的总成绩
select sum(math) ,sum(english),sum(chinese) from exam;
~统计一个班级语文、英语、数学的成绩总和
select sum(ifnull(math,0)+ifnull(english,0)+ifnull(chinese,0)) from exam;
~统计一个班级语文成绩平均分
select sum(chinese)/count(*) from exam;
~求一个班级数学平均分?
select avg(math) from exam;
~求一个班级总分平均分?
select avg(ifnull(math,0)+ifnull(english,0)+ifnull(chinese,0)) from exam;
~求班级最高分和最低分
select max(ifnull(math,0)+ifnull(english,0)+ifnull(chinese,0)) from exam;
select min(ifnull(math,0)+ifnull(english,0)+ifnull(chinese,0)) from exam;
语法:
SELECT column1, column2. column3… FROM table group by column having …
练习:
create table orders(
id int,
product varchar(20),
price float
);
insert into orders(id,product,price) values(1,‘电视’,900);
insert into orders(id,product,price) values(2,‘洗衣机’,100);
insert into orders(id,product,price) values(3,‘洗衣粉’,90);
insert into orders(id,product,price) values(4,‘桔子’,9);
insert into orders(id,product,price) values(5,‘洗衣粉’,90);
~对订单表中商品归类后,显示每一类商品的总价
select product ,sum(price) from orders group by product;
~查询购买了几类商品,并且每类总价大于100的商品
select product ,sum(price)
from orders group by product having sum(price) >100;
~查询单价小于100而总价大于100的商品的名称.
select product
from orders
where price < 100 group by product having sum(price)>100;
【例7.27】根据s_id对fruits表中的数据进行分组,将每个供应商的水果名称显示出来,SQL语句如下:
SELECT s_id, GROUP_CONCAT(f_name) AS Names FROM fruits GROUP BY s_id;
【例7.29】根据s_id对fruits表中的数据进行分组,并显示记录数量,SQL语句如下:
SELECT s_id, COUNT(*) AS Total
FROM fruits
GROUP BY s_id WITH ROLLUP;
【例7.32】显示fruits表查询结果的前4行,SQL语句如下:
SELECT * From fruits LIMIT 4;
【例7.33】在fruits表中,使用LIMIT子句,返回从第5个记录开始的,行数长度为3的记录,SQL语句如下:
SELECT * From fruits LIMIT 4, 3;
group_concat(column_name):合并(按指定列名)分组里面的内容
WITH ROLLUP:结合GROUP BY使用,可以将所有分组数据再进行一次合计,显示在最后一行。
**where子句和having子句都可以进行过滤器,但是使用场景有所不同:
cmd窗口中使用mysqldump 备份数据库
mysqldump -u root -p db_name > c:/xxx.sql
例如:mysqldump -u root -p mydb2 > c:/mydb2.sql
方式1:cmd窗口中使用mysql命令 恢复数据库,注意,只能恢复数据库中的数据,不能恢复数据库本身!所以要提前建好数据库.
mysql -u root -p db_name < c:/xxx.sql
例如:mysql -u root -p mydb2 < c:/mydb2.sql
方式2:在mysql命令下,source xxx.sql,这个命令的作用就是,在当前位置执行sql文件中的所有的sql.首先新建出数据库,进入数据库,在source执行备份的sql文件即可。
例如:source c:/xxx.sql
注意:如果在cmd窗口下,执行出现“拒绝访问”提示,用管理员打开cmd窗口即可。
外键概念
数据库用表来保存数据,但是现实中,数据和数据之间往往具有一定的关系,在设计表时应该如何来保存这种关系呢?我们来看如下图。
一个部门可以具有多个员工,而一个员工只能属于一个部门。对于这种类型的关系我们称之为1对多的关系。
那么我们该如何保存他们之间的关系呢?
可不可以在dept表中设计一张表记录部门中员工的信息呢?
我们发现这是不可行的,因为一个部门中可能有多个员工,这就导致emp_id中一个字段可能需要保存多个值,这是不可行的。
那么反过来,可否在emp表保存员工所属部门id呢?
这种方式是可行的,因为一个员工只能属于一个部门,dept_id中只需存储一个值即可。
虽然我们设计了这样的字段保存两表之间的关系,但是数据库并不知道这样的关系。我们可以设想,如下的情况。
“公司老总发现科技部不挣钱,决定解散科技部”,对应到数据库时,就是如下的sql
delete from dept where id = 004;
正确的执行后,数据库中的数据变为如下
我们发现“555 郭德纲”人还在,所属部门却没有了,数据之间的对应关系出现了问题,我们称为违反了数据库的“完整性”。
之所以产生这样的问题,是因为虽然我们知道dept_id要参考dept表的id列,但是数据库并不知道,所以在删除数据造成违反“不完整”性的情况下数据库没有任何提示。
为了防止这样的问题产生,可以通过外键明确的通知数据库维系这种关系。
一旦任何操作违反了这种关系,数据库会阻止并报错。
建表时增加外键:
foreign key(ordersid) references orders(id)
例: FK_user_id
FOREIGN KEY (user_id
) REFERENCES t_user
(user_id
)
修改方式增加外键:
alter table book add [constraint FK_BOOK] foreign key(pubid) references pub_com(id) [on delete restrict] [on update restrict];
例: 外键名fk,当有关联表存在时不能删除
ALTER TABLE student CONSTRAINT fk ADD FOREIGN KEY(cla_id) REFERENCES class(id) ON DELETE RESTRICT;
例: 外键名fk,删除表时一并删除关联表
ALTER TABLE student CONSTRAINT fk ADD FOREIGN KEY(cla_id) REFERENCES class(id) ON DELETE CASCADE;
可以明确指定外键的名称,如果不指定外键的名称,mysql会自动为你创建一个外键名称。
RESTRICT : 只要本表格里面有指向主表的数据, 在主表里面就无法删除相关记录。
CASCADE : 如果在foreign key 所指向的那个表里面删除一条记录,那么在此表里面的跟那个key一样的所有记录都会一同删掉。
删除外键
alter table 表名 drop foreign key 外键名
实验外键
略
多表设计概念
在讲解外键时,我们提到了表和表之间往往存在着一定的关系,那么除了上述的1对多关系外还有哪些种关系呢?又如何设计外键来保存这些不同的关系呢?下面,我们一起来讨论表和表中的三种关系。
三种关系及外键设计
一对一表和表之间的关系分为三种,分别是1对1、1对多、多对多,下面就用具体的例子讲解这三种关系
班级表和教室表之间的关系,一个班级只能在一个教室上课,一个教室也只能放下一个班级,这种关系就称为一对一的关系,对于一对一的关系,可以在任意一方保存另一方的主键作为外键保存两表之间的关系。
一对多
学生表和班级表的关系,一个班级可以有多个学生而一个学生只能属于一个班级,这种关系称为一对多的关系,对于一对多的关系,可以在多的一方设计外键保存一的一方的主键作为外键保存两表之间的关系。
多对多:
学生表和教师表的关系,一个学生可以由多个老师教授,一个老师也可以教授多个学生,这种关系称为多对多的关系,对于多对多的关系,需要设计一张第三方关系表保存两张表主键之间的对应关系。
多表查询
多表查询概念
表和表之间往往是存在关系的,而有时我们需要的数据在多张表中,如何跨着多张表查询数据呢?这就涉及到多表查询了
准备数据:
create table dept(
id int primary key auto_increment,
name varchar(20)
);
insert into dept values
(null,‘财务部’),(null,‘人事部’),(null,‘科技部’),(null,‘销售部’);
create table emp(
id int key auto_increment,
name varchar(20),
dept_id int
);
insert into emp values
(null,‘张飞’,1),(null,‘关羽’,2),(null,‘刘备’,3),(null,‘赵云’,5);
需求:查询所有部门名称和对应的员工名称。
这是一种最原始的查询方式,其实就是两张表相乘的结果,如果左表有m条记录,右表有n条记录,则查询出来m*n条记录.虽然查出数据了,但是其中包含了大量错误的数据,所以这种查询我们通常不使用。
select * from dept,emp;
内连接查询:只查询左边表有且右边表也有的数据,本质上是依据外键关系,在笛卡尔积查询的基础上过滤出正确的数据。通过观察结果,我们发现结果中只有两边都有对应数据的数据才能被查出来。
以下两个语句实现功能一样,内连接等同于where条件查询。
select * from dept ,emp where dept.id = emp.dept_id;
select * from dept inner join emp on dept.id = emp.dept_id;
自连接是一种特殊的内连接,在连接查询中的两个表都是同一个表。
【例】列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称。
select e1.empno, e1.empname, d.deptname
from emp e1, emp e2, dept d
where e1.hiredate
内连接查询只能查找出两边表都有对应数据的数据,如果两边冗余的数据也需要查询时该怎么办呢?
(1)左外连接查询:在内连接的基础上增加上左边表有而有边表没有的记录。对应右表没有的记录显示为null。
select * from dept left join emp on dept.id = emp.dept_id;
#其中,left join 也可以写成 left outer join;
(2)右外连接查询:在内连接的基础上增加上右边表有而左边表没有的记录。对应左表没有的记录显示为null。
select * from dept right join emp on dept.id = emp.dept_id;
#其中,right join 也可以写成 right outer join;
(3)全外连接查询:在内连接的基础上增加左边表有而右边表没有的记录和右边表有而左边表没有的记录
注意:mysql 不支持全外连接,但是其他的数据库支持,比如SQL Server
select * from dept full join emp on dept.id = emp.dept_id;
但我们可以在mysql中使用union关键字模拟全外连接。union将两个查询结果(按自上而下的顺序)拼接到一个表格。
select * from dept left join emp on dept.id = emp.dept_id
union
select * from dept right join emp on dept.id = emp.dept_id;
指一个查询语句嵌套在另一个查询语句内部的查询。可以多层嵌套。
常用查询操作符:ANY(SOME)、ALL、IN、EXISTS
子查询可以添加SELECT、UPDATE、DELETE语句。
可以使用比较运算符:< <= > >= !=
1.带ANY、SOME关键字的子查询
ANY和SOME关键字是同义词,表示满足其中任一条件,它们允许创建一个表达式对子查询的返回值列表进行比较,只要满足内层子查询中的任何一个比较条件,就返回一个结果作为外层查询的条件。
下面定义两个表tbl1和tbl2:
CREATE table tbl1 ( num1 INT NOT NULL);
CREATE table tbl2 ( num2 INT NOT NULL);
分别向两个表中插入数据:
INSERT INTO tbl1 values(1), (5), (13), (27);
INSERT INTO tbl2 values(6), (14), (11), (20);
ANY关键字接在一个比较操作符的后面,表示若与子查询返回的任何值比较为TRUE,则返回TRUE。
【例7.53】返回tbl2表的所有num2列,然后将tbl1中的num1的值与之进行比较,只要大于num2的任何1个值,即为符合查询条件的结果。
SELECT num1 FROM tbl1 WHERE num1 > ANY (SELECT num2 FROM tbl2);
【例7.54】返回tbl1表中比tbl2表num2 列所有值都大的值,SQL语句如下:
【例7.56】查询suppliers表中是否存在s_id=107的供应商,如果存在,则查询fruits表中的f_price大于10.20的记录,SQL语句如下:
SELECT * FROM fruits
WHERE f_price>10.20 AND EXISTS
(SELECT s_name FROM suppliers WHERE s_id = 107);
【例7.58】在orderitems表中查询f_id为c0的订单号,并根据订单号查询具有订单号的客户c_id,SQL语句如下:
SELECT c_id FROM orders WHERE o_num IN
(SELECT o_num FROM orderitems WHERE f_id = ‘c0’);
正则表达式查询REGEXP:
字符‘^’匹配以特定字符或者字符串开头的文本。
例:在employee表中,查询员工姓名以字母’A’或’S’开头的员工的信息。
SELECT * FROM employee WHERE e_name REGEXP ‘1’;
字符‘$’匹配以特定字符或者字符串结尾的文本。
字符‘.’匹配任意一个字符。
【例7.72】在fruits表中,查询f_name字段值包含字母’a’与’g’且两个字母之间只有一个字母的记录,SQL语句如下,
SELECT * FROM fruits WHERE f_name REGEXP ‘a.g’;
星号‘’匹配前面的字符任意多次,包括0次。
【例7.73】在fruits表中,查询f_name字段值以字母’b’开头,且’b’后面出现字母’a’的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP '^ba’;
加号‘+’匹配前面的字符至少一次。
多个字符串之间使用分隔符‘|’隔开。
【例7.76】在fruits表中,查询f_name字段值包含字符串“on”或者“ap”的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘on|ap’;
对比LIKE运算符:
SELECT * FROM fruits WHERE f_name LIKE ‘on’;
f_name字段没有值为“on”的记录,返回结果为空(Empty set (0.00 sec))。
方括号“[]”指定一个字符集合,只匹配其中任何一个字符,即为所查找的文本。方括号“[]”还可以指定数值集合。
【例7.79】在fruits表,查询s_id字段中数值中包含4、5或者6的记录,SQL语句如下:
SELECT * FROM fruits WHERE s_id REGEXP ‘[456]’;
对比IN运算符:
SELECT * FROM fruits WHERE s_id IN (4,5,6);
匹配集合“[456]”也可以写成“[4-6]”即指定集合区间。例如“[a-z]”表示集合区间为从a~z的字母,“[0-9]”表示集合区间为所有数字。
“[^字符集合]”匹配不在指定集合中的任何字符。
【例7.80】在fruits表中,查询f_id字段包含字母ae和数字05以外的字符的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_id REGEXP ‘[^a-e0-5]’;
过滤条件:选定字段所有字符不在a-e范围且不在0-5范围
“字符串{n,}”表示至少匹配n次前面的字符。“字符串{n,m}”表示匹配前面的字符串不少于n次,不多于m次。
6.2 数学函数
6.2.1 绝对值函数ABS(x)和返回圆周率的函 数PI()
6.2.2 平方根函数SQRT(x)和求余函数MOD(x,y)
6.2.3 获取整数的函数CEIL(x)、CEILING(x)和
FLOOR(x)
6.2.4 获取随机数的函数RAND()和RAND(x)
6.2.5 四舍五入函数ROUND(x)、ROUND(x,y)和TRUNCATE(x,y)
6.2.6 符号函数SIGN(x)
6.2.7 幂运算函数POW(x,y)、POWER(x,y)和EXP(x)
6.2.8 对数运算函数LOG(x)和LOG10(x)
6.2.9 角度与弧度相互转换的函数RADIANS(x)和DEGREES(x)
6.2.10 正弦函数SIN(x)和反正弦函数ASIN(x)
6.2.11 余弦函数COS(x)和反余弦函数ACOS(x)
6.2.12 正切函数、反正切函数和余切函数
6.3 字符串函数
6.3.1 计算字符串字符数的函数和字符串长度的函数
6.3.2 合并字符串函数CONCAT(s1,s2,…)、CONCAT_WS(x,s1,s2,…)
6.3.3 替换字符串的函数INSERT(s1,x,len,s2)
6.3.4 字母大小写转换函数
6.3.5 获取指定长度的字符串的函数LEFT(s,n)和RIGHT(s,n)
6.3.6 填充字符串的函数LPAD(s1,len,s2)和
RPAD(s1,len,s2)
6.3.7 删除空格的函数LTRIM(s)、RTRIM(s)和TRIM(s)
6.3.8 删除指定字符串的函数TRIM(s1 FROM s)
6.3.9 重复生成字符串的函数REPEAT(s,n)
6.3.10 空格函数SPACE(n)和替换函数REPLACE(s,s1,s2)
6.3.11 比较字符串大小的函数STRCMP(s1,s2)
6.3.12 获取子串的函数SUBSTRING(s,n,len)和
MID(s,n,len)
6.3.13 匹配子串开始位置的函数
6.3.14 字符串逆序的函数REVERSE(s)
6.3.15 返回指定位置的字符串的函数
6.3.16 返回指定字符串位置的函数FIELD(s,s1,s2,…)
6.3.17 返回子串位置的函数FIND_IN_SET(s1,s2)
6.3.18 选取字符串的函数MAKE_SET(x,s1,s2,…)
6.4 日期和时间函数
6.4.1 获取当前日期的函数和获取当前时间的函数
6.4.2 获取当前日期和时间的函数 CURTIME()、NOW()
6.4.3 UNIX时间戳函数
6.4.4 返回UTC日期的函数和返回UTC时间的函数
6.4.5 获取月份的函数MONTH(date)和
MONTHNAME(date)
6.4.6 获取星期的函数DAYNAME(d)、
DAYOFWEEK(d)和WEEKDAY(d)
6.4.8 获取天数的函数DAYOFYEAR(d)和
DAYOFMONTH(d)
6.4.9 获取年份、季度、小时、分钟和秒钟的函数
6.4.10 获取日期的指定值的函数
EXTRACT(type FROM d)
6.4.11 时间和秒钟转换的函数
6.4.12 计算日期和时间的函数
6.4.13 将日期和时间格式化的函数
例1: 修改为指定日期2014-04-05,但不改变原来的时分秒。
UPDATE teacher SET hiredate=ADDTIME(DATE(‘2014-04-05’)+INTERVAL 0 HOUR,TIME(hiredate)) WHERE id=3;
例2: 在原来的日期上增加2天
UPDATE teacher SET hiredate=DATE_ADD(hiredate,INTERVAL 2 DAY) WHERE id=4;
增加2小时
DATE_ADD(hiredate,INTERVAL 2 HOUR)
增加2分钟
DATE_ADD(hiredate,INTERVAL 2 MINUTE)
增加2秒
DATE_ADD(hiredate,INTERVAL 2 SECOND)
减少2毫秒
DATE_SUB(hiredate,INTERVAL 2 MICROSECOND)
减少2周
DATE_SUB(hiredate,INTERVAL 2 WEEK)
减少2月
DATE_SUB(hiredate,INTERVAL 2 MONTH)
减少2季
DATE_SUB(hiredate,INTERVAL 2 QUARTER)
减少2年
DATE_SUB(hiredate,INTERVAL 2 YEAR)
6.5 条件判断函数
6.5.1 IF(expr,v1,v2)函数
6.5.2 IFNULL(v1,v2)函数
6.5.3 CASE函数
6.6 系统信息函数
6.6.1 获取MySQL版本号、连接数和数据库名的函数
6.6.2 获取用户名的函数
6.6.3 获取字符串的字符集和排序方式的函数
6.6.4 获取最后一个自动生成的ID值的函数
6.7 加密函数
6.7.1 加密函数PASSWORD(str)
6.7.2 加密函数MD5(str)
6.7.3 加密函数ENCODE(str,pswd_str)
6.7.4 解密函数DECODE(crypt_str,pswd_str)
6.8 其他函数
6.8.1 格式化函数FORMAT(x,n)
6.8.2 不同进制的数字进行转换的函数
6.8.3 IP地址与数字相互转换的函数
6.8.4 加锁函数和解锁函数
6.8.5 重复执行指定操作的函数
6.8.6 改变字符集的函数
6.8.7 改变数据类型的函数
create 增
update 改
delete 删
read 查
索引是一个单独的、存储在磁盘上的数据库结构,它们包含着对数据表里所有记录的引用指针。
索引的设计原则
索引并非越多越好。
避免对经常更新的表进行过多的索引,并且索引中的列尽可能少。
数据量小的表最好不要使用索引。
在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引。
当唯一性是某种数据本身的特征时,指定唯一索引。
在频繁进行排序或分组(即进行group by或order by操作)的列上建立索引
1.创建表的时候创建索引
CREATE TABLE
table_name [col_name data_type]
[UNIQUE|FULLTEXT|SPATIAL] [INDEX|KEY]
[index_name] (col_name [length])
[ASC | DESC]
2.在已经存在的表上创建索引
步骤①:使用ALTER TABLE语句创建索引
ALTER TABLE teacher ADD INDEX (remark(10));
步骤②:使用CREATE INDEX创建索引
CREATE FULLTEXT INDEX remark_index ON teacher(remark);
删除索引
1.使用ALTER TABLE删除索引
ALTER TABLE table_name
DROP INDEX index_name;
2.使用DROP INDEX语句删除索引
DROP INDEX index_name ON table_name;
DROP INDEX remark_index ON teacher;
MySQL优化一方面是找出系统的瓶颈,提高MySQL数据库整体的性能;另一方面,需要合理的结构设计和参数调整,以提高用户操作响应的速度;同时还要尽可能的节省系统资源,以便系统可以提供更大负荷的服务。
通过对查询语句的分析,可以了解查询语句执行情况,找出查询语句执行的瓶颈,从而优化查询语句。
EXPLAIN [EXTENDED] SELECT select_options
DESCRIBE SELECT select_options
MySQL中提高性能的一个最有效的方式就是对数据表设计合理的索引。索引提供了高效访问数据的方法,并且加快查询的速度,因此,索引对查询的速度有着至关重要的影响。
对于字段较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。
对于需要经常联合查询的表,可以建立中间表以提高查询效率。
合理地加入冗余字段可以提高查询速度。
影响插入速度的主要是索引、唯一性校验和一次插入记录条数等。根据这些情况,可以分别进行优化。
① 禁用索引
② 禁用唯一性检查
③ 使用批量插入
④ 使用LOAD DATA INFILE 批量导入
(5)分析表、检查表和优化表
MySQL提供了分析表、检查表和优化表的语句。
① 分析表
分析表主要是分析关键字的分布。
② 检查表
主要是检查表是否存在错误。
③ 优化表
主要是消除删除或者更新造成的空间浪费。
服务器的硬件性能直接决定着MySQL数据库的性能。硬件的性能瓶颈,直接决定MySQL数据库的运行速度和效率。
通过优化MySQL的参数,可以提高资源利用率,从而达到提高MySQL服务器性能的目的。
key_buffer_size、table_cache、query_cache_size
……
怎么查出每个月倒数第二天入职的员工?
SELECT * FROM employee WHERE hiredate=last_day(hiredate)-1;
在employee表中,查询到目前为止,工龄大于等于10年的员工信息。
SELECT * FROM employee where YEAR(CURDATE()) -YEAR(hireDate) >= 10;
在employee表中,查询员工姓名以字母’A’或’S’开头的员工的信息。
SELECT * FROM employee WHERE e_name REGEXP ‘2’;
查找所有以’b’字母开头的水果,SQL语句如下:
SELECT f_id, f_name
FROM fruits
WHERE f_name LIKE ‘b%’;
在fruits表中,查询f_name字段以字符串“rry”结尾的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘rry$’;
用符号".“来替代字符串中的任意一个字符
字符’.’匹配任意一个字符。
在fruits表中,查询f_name字段值包含字母’a’与’g’且两个字母之间只有一个字母的记录,SQL语句如下,
SELECT * FROM fruits WHERE f_name REGEXP ‘a.g’;
±-----±-----±-------±--------+
| f_id | s_id | f_name | f_price |
±-----±-----±-------±--------+
| bs1 | 102 | orange | 11.20 |
| m1 | 106 | mango | 15.60 |
±-----±-----±-------±--------+
使用”“和”+"来匹配多个字符
星号’’匹配前面的字符任意多次,包括0次。加号’+’匹配前面的字符至少一次。
在fruits表中,查询f_name字段值以字母’b’开头,且’b’后面出现字母’a’的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘^ba*’;
±-----±-----±-----------±-----------+
| f_id | s_id | f_name | f_price |
±-----±-----±-----------±-----------+
| b1 | 101 | blackberry | 10.20 |
| b2 | 104 | berry | 7.60 |
| t1 | 102 | banana | 10.30 |
±-----±-----±-----------±-------------+
星号’*’可以匹配任意多个字符,blackberry和berry中字母b后面并没有出现字母a,但是也满足匹配条件。
在fruits表中,查询f_name字段值包含字符串“on”或者“ap”的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘on|ap’;
±-----±-----±---------±--------+
| f_id | s_id | f_name | f_price |
±------±------±----------±--------+
| a1 | 101 | apple | 5.20 |
| a2 | 103 | apricot | 2.20 |
| bs2 | 105 | melon | 8.20 |
| l2 | 104 | lemon | 6.40 |
| o2 | 103 | coconut | 9.20 |
| t2 | 102 | grape | 5.30 |
±------±------±---------±---------+
在fruits表中,使用LIKE运算符查询f_name字段值为“on”的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name LIKE ‘on’;
Empty set (0.00 sec)
在fruits表,查询s_id字段中数值中包含4、5或者6的记录,SQL语句如下:
SELECT * FROM fruits WHERE s_id REGEXP ‘[456]’;
±-----±-----±--------±---------+
| f_id | s_id | f_name | f_price |
±------±------±--------±--------+
| b2 | 104 | berry | 7.60 |
| bs2 | 105 | melon | 8.20 |
| l2 | 104 | lemon | 6.40 |
| m1 | 106 | mango | 15.60 |
| m2 | 105 | xbabay | 2.60 |
| m3 | 105 | xxtt | 11.60 |
±------±------±--------±---------+
匹配集合“[456]”也可以写成“[4-6]”即指定集合区间。例如“[a-z]”表示集合区间为从a~z的字母,“[0-9]”表示集合区间为所有数字。
“[^字符集合]”匹配不在指定集合中的任何字符。
在fruits表中,查询f_name字段值出现字母’x’至少2次的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘x{2,}’;
±-----±-----±-------±--------+
| f_id | s_id | f_name | f_price |
±-----±-----±-------±--------+
| b5 | 107 | xxxx | 3.60 |
| m3 | 105 | xxtt | 11.60 |
±-----±------±-------±--------+
在fruits表中,查询f_name字段值出现字符串“ba”最少1次,最多3次的记录,SQL语句如下:
SELECT * FROM fruits WHERE f_name REGEXP ‘ba{1,3}’;
在fruits表中,查询f_name中包含字母’g’的记录,SQL语句如下:
SELECT f_id, f_name
FROM fruits
WHERE f_name LIKE ‘%g%’;
查询以’b’开头,并以’y’结尾的水果的名称,SQL语句如下:
SELECT f_name
FROM fruits
WHERE f_name LIKE ‘b%y’;
在fruits表中,查询以字母’y’结尾,且’y’前面只有4个字母的记录,SQL语句如下:
SELECT f_id, f_name FROM fruits WHERE f_name LIKE '___y’; (注意此处是4个下划线“”)
查询customers表中c_email为空的记录的c_id、c_name和c_email字段值,SQL语句如下:
SELECT c_id, c_name,c_email FROM customers WHERE c_email IS NULL;
查询customers表中c_email不为空的记录的c_id、c_name和c_email字段值,SQL语句如下:
SELECT c_id, c_name,c_email FROM customers WHERE c_email IS NOT NULL;
查询s_id=101或者s_id=102的水果供应商的f_price和f_name,SQL语句如下:
SELECT s_id,f_name, f_price FROM fruits WHERE s_id = 101 OR s_id = 102;
SELECT s_id,f_name, f_price FROM fruits WHERE s_id IN(101,102);
查询fruits表中的f_name和f_price字段,先按f_name降序排列,再按f_price升序排列,SQL语句如下:
SELECT f_name, f_price FROM fruits ORDER BY f_name DESC, f_price;
根据s_id对fruits表中的数据进行分组,并显示水果种类大于1的分组信息,SQL语句如下:
SELECT s_id, GROUP_CONCAT(f_name) AS Names
FROM fruits
GROUP BY s_id HAVING COUNT(f_name) > 1;
根据s_id对fruits表中的数据进行分组,并显示记录数量,SQL语句如下:
SELECT s_id, COUNT() AS Total
FROM fruits
GROUP BY s_id WITH ROLLUP;
查询订单价格大于100的订单号和总订单价格,并按总订单价格排序显示结果,SQL语句如下:
SELECT o_num, SUM(quantity * item_price) AS orderTotal
FROM orderitems
GROUP BY o_num
HAVING SUM(quantityitem_price) >= 100
ORDER BY orderTotal;
显示fruits表查询结果的前4行,SQL语句如下:
SELECT * From fruits LIMIT 4;
在fruits表中,使用LIMIT子句,返回从第5个记录开始的,行数长度为3的记录,SQL语句如下:
SELECT * From fruits LIMIT 4, 3;
返回tbl2表的所有num2列,然后将tbl1中的num1的值与之进行比较,只要大于num2的任何1个值,即为符合查询条件的结果。
SELECT num1 FROM tbl1 WHERE num1 > ANY (SELECT num2 FROM tbl2);
返回tbl1表中比tbl2表num2 列所有值都大的值,SQL语句如下:
SELECT num1 FROM tbl1 WHERE num1 > ALL (SELECT num2 FROM tbl2);
查询suppliers表中是否存在s_id=107的供应商,如果存在,则查询fruits表中的f_price大于10.20的记录,SQL语句如下:
SELECT * FROM fruits
WHERE f_price>10.20 AND EXISTS
(SELECT s_name FROM suppliers WHERE s_id = 107);
在suppliers表中查询s_city等于“Tianjin”的供应商s_id,然后在fruits表中查询所有该供应商提供的水果的种类,SQL语句如下:
SELECT s_id, f_name FROM fruits
WHERE s_id =
(SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = ‘Tianjin’);
在suppliers表中查询s_city等于“Tianjin”的供应商s_id,然后在fruits表中查询所有非该供应商提供的水果的种类,SQL语句如下:
SELECT s_id, f_name FROM fruits
WHERE s_id <>
(SELECT s1.s_id FROM suppliers AS s1 WHERE s1.s_city = ‘Tianjin’);
查询所有价格小于9的水果的信息,查询s_id等于101和103所有的水果的信息,使用UNION连接查询结果,SQL语句如下:
SELECT s_id, f_name, f_price
FROM fruits
WHERE f_price < 9.0
UNION ALL
SELECT s_id, f_name, f_price
FROM fruits
WHERE s_id IN(101,103);
查询suppliers表中字段s_name和s_city,使用CONCAT函数连接这两个字段值,并取列别名为suppliers_title。
SELECT CONCAT(TRIM(s_name) , ’ (’, TRIM(s_city), ‘)’)
AS suppliers_title
FROM suppliers
ORDER BY s_name;
±-------------------------+
| suppliers_title |
±-------------------------+
| ACME (Shanghai) |
| DK Inc. (Zhengzhou) |
| FastFruit Inc. (Tianjin) |
| FNK Inc. (Zhongshan) |
| Good Set (Taiyuang) |
| Just Eat Ours (Beijing) |
| LT Supplies (Chongqing) |
±-------------------------+
as ↩︎
as ↩︎