MySQL常用语句
列:字段
行:一条记录
表中一行记录对应一个Java对象的数据
SQL:Structure Query Language。(结构化查询语言)
SQL被美国国家标准局(ANSI)确定为关系型数据库语言的美国标准,后来被国际化标准组织(ISO)采纳为关系数据库语言的国际标准。
各数据库厂商都支持ISO的SQL标准。普通话
各数据库厂商在标准的基础上做了自己的扩展。方言
DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等; CREATE、 ALTER、DROP
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据); INSERT、 UPDATE、 DELETE
DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别;
DQL(Data Query Language):数据查询语言,用来查询记录(数据)。
注意:sql语句以;结尾
操作数据库
create {database|schema} [if not exists] db_name
[create_specification[,create_specification]...]
create_specification:
[default] character set charset_name //指定字符集
|[default] collate collation_name //指定数据库字符集的比较方式(校验规则)
字符集,character set,就是一套表示字符的符号和这些的符号的底层编码;而校验规则,则是在字符集内用于比较字符的一套规则。下面我简单举个例子来说明一下:如在某个字符集“X”的A与a,他们的底层编码分别是A=0,a=100。这里符号“A”“a”和底层编码“0”“100”就是字符集的概念范围。假设我们要比较A与a的大小,我们得到a>A,因为我们是根据其底层编码进行比较的,这就是这个字符集“X”的一种校验规则“Z”(根据底层编码来比较)。假设,现在有另外一种校验规则,是先取其相反数,然后再比较大小,那么就很显然的得到a < A,这就是字符集“X”的另外一种校验规则“Z1”。由此可见,一种字符集可能存在多个与之对应的校验规则。
创建数据库
create databse mydb1;
创建数据库并设置编码格式为gbk。不指定的话默认为utf-8,这个在安装的时候设置了
create database mydb2 character set gbk;
设置校验规则
create database mydb3 character set gbk collate gbk_chinese_ci;
查看当前数据库服务器中的所有数据库
show databases;
查看前面创建的mydb2数据库的定义信息
show create database mydb2;
删除前面创建的mydb3数据库
drop database mydb3;
把mydb2的字符集修改为utf8
alter database mydb2 set utf8;
查看当前使用的数据库
select database();
切换数据库
use mydb2;
注释
敲完两个短线之后要敲一个空格
select * from student;-- 注释
操作数据库表
常用数据类型
- int :整型,4个字节
- double:浮点型,例如double(5,2)表示最多5位,其中2位为小数,即最大值为999.99。
- varchar:可变长度字符串类型。varchar(10) ‘aaa’ 占3位
- datetime:日期时间类型。yyyy-MM-dd hh:mm:ss
- char:固定长度字符串类型。char(10) ‘aaa ’ 占10位
- text:大文本字符串类型
- blob:字节类型
- date:日期类型,格式为:yyyy-MM-dd
- time:时间类型,格式为:hh:mm:ss
- timestamp:时间戳类型 yyyy-MM-dd hh:mm:ss 会自动赋值
字符串类型和日期类型都要用单引号括起来。
空值:null
创建表
create table 表名(
字段名 类型(长度) [约束],
字段名 类型(长度) [约束]
);
字符类型:varchar(n)
单表约束
主键约束:primary key,要求被修饰的字段:唯一和非空
唯一约束:unique,要求被修饰的字段:唯一
非空约束:not null,要求被修饰的字段:非空
查看表
查看数据库中的所有表:show tables;
查看表结构:desc 表名;
查看表的创建细节:show create table 表名;
删除表
drop table 表名;
修改表
alter table 表名 add 列名 类型(长度) [约束]; --添加列
alter table 表名 modify 列名 类型(长度) [约束]; --修改列的类型长度及约束
alter table 表名 change 旧列名 新列名 类型(长度) [约束]; --修改表列名
alter table 表名 drop 列名; --删除列
alter table 表名 character set 字符集; --修改表的字符集
rename table 表名 to 新表名; --修改表名
对表的增删改
插入记录:insert
insert into 表(列名1,列名2,列名3..) values(值1,值2,值3..);--向表中插入某些列
insert into 表 values(值1,值2,值3..); --向表中插入所有列
列名与列值的类型,个数,顺序要一一对应。可以把列名当做Java中的形参,把列值当做实参。
值不要超出列定义的长度。值如果是字符串或者日期需要加单引号。
在cmd中敲代码插入中文数据会报错,解决方案查看
ERROR 1366 (HY000): Incorrect string value-解决方案 - 杨钊 - CSDN博客
http://blog.csdn.net/zsx157326/article/details/77012242
更新记录:update
update 表名 set 字段名=值,字段名=值...; --这个会修改所有的数据,把一列的值都变了
update 表名 set 字段名=值,字段名=值... where 条件;
删除记录:delete
delete from 表名 --删除表中所有记录
delete from 表名 where 条件
truncate table 表名;
delete删除表中的数据,是一条一条删除,不清空auto_increment记录数;删除后的数据如果在一个事务中还可以找回。
truncate删除是把表直接drop掉,重新建表,auto_increment将置为零。删除的数据不能找回。执行速度比delete快。
数据查询语言DQL
简单查询
查询所有列
select * from stu;
查询指定列
select sid,sname,age from stu;
别名查询
as可以省略
表别名
select * from product as p;
列别名
select pname as pn from product;
去掉重复值
用来去除重复数据,是对整个结果集(结果集就是查出来的那些数据)进行数据重复抑制的,而不是针对某一列。
select distinct Department,SubCompany from Employee;
计算字段
字段间计算
select age*salary,name from employee;
运算查询
select pname,price+10 from product;
comm列有很多记录的值为NULL,因为任何东西与NULL相加结果还是NULL,所以结算结果可能会出现NULL。下面使用了把NULL转换成数值0的函数IFNULL
select *,sal+ifnull(comm,0) from emp;
条件查询
where后的条件写法
- = != <> < <= > >=
- between…and
- in(set)
- and
- or
- not
- is null
- like,_代表任意一个字符,%代表任意0-n个字符
select * from stu where gender='female' and age<50;
select * from stu where sid='S_1001' and sname='lisi';
select * from stu where sid in('S_1001','S_1002','S_1003');
select * from stu where sid not in('S_1001','S_1002','S_1003');
select * from stu where age is null;
select * from stu where age>=20 and age<=40;
select * from stu where age between 20 and 40;
select * from stu where stu where gender!='male';
select * from stu where gender<>'male';
select * from stu where not gender='male';
select * from stu where not sname is null;
select * from stu where sname is not null;
select * from stu where sname like '_____'; -- 查询姓名由5个字母构成的学生记录
select * from stu where sname like '____i'; -- 查询姓名由5个字母构成,并且第5个字母为“i”的学生
select * from stu where sname like 'z%'; -- 查询姓名以“z”开头的学生记录
select * from stu where sname like '_i%';-- 查询姓名中第2个字母为“i”的学生记录
select * from stu where sname like '%a%';-- 查询姓名中包括“a”字母的学生记录
排序
select * from stu order by age asc; -- 升序排序,也可以不加asc,默认为升序
select * from stu order by age desc; --降序
select * from emp order by sal desc,empno asc;-- 按月薪降序排序,如果月薪相同时,按编号升序排序。只有在前一个条件相同时,后一个条件才会起作用。
聚合函数
聚合函数是用来做纵向运算的函数
- count():统计指定列不为null的记录行数
- max():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算
- min():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算
- sum():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0。求和的时候忽略null,如果都是null,则算出来的结果为null。
- avg():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0.
select count(*) as cnt from emp;-- 计算emp表中记录数
select count(comm) cnt from emp;-- 查询emp表中拥有佣金的人数,因为count()函数中给出的是comm列,那么只统计comm列非null的行数。
select count(*) from emp where sal>2500;-- 查询emp表中月薪大于2500的人数
select count(comm),count(mgr) from emp; -- 查询有佣金的人数,以及由领导的人数
select sum(sal) from emp; -- 查询所有雇员的佣金和
select sum(sal),sum(comm) from emp; -- 查询所有雇员月薪和,以及所有雇员佣金和
select sum(sal+ifnumm(comm,0)) from emp; -- 查询所有雇员月薪+佣金和
select avg(sal) from emp;
select max(sal),min(sal) from emp;-- 查询最高工资和最低工资
分组查询
当需要分组查询时需要使用group by子句,例如查询每个部分的工资和,就需要使用部门来分组。
注:凡是和聚合函数同时出现的列名,则一定要写在group by之后
select deptno,sum(sal) from emp group by deptno;-- 查询每个部门的编号和每个部门的工资和
select deptno,count(*) from emp group by deptno;-- 查询每个部门的部门编号以及每个部门的人数
select deptno,count(*) from emp where sal>1500 group by deptno;-- 查询每个部门的编号以及每个部门工资大于1500的人数
执行了select deptno,sum(sal) from emp group by deptno;之后
执行了select deptno,count(*) from emp where sal>1500 group by deptno;之后
这句话是先把sal>1500的都查出来,然后再从查出来的这里边查
having子句
where是在分组前对数据进行过滤,having是在分组后对数据进行过滤。
having后面可以使用聚合函数,where不可以使用聚合函数。
select deptno,sum(sal) from emp group by deptno having sum(sal)>9000;
limit(方言,MySQL特有的)
limit用来限制查询结果的起始行,以及总行数
select * from emp limit 0,5; -- 查询5行记录,起始行从0开始。起始行从0开始,即从第一行开始
select * from emp limit 3,10;-- 查询10行记录,起始行从3开始。就是从第4行开始查
分页查询
如果一页记录为10条,希望查看第3页应该怎么查呢?
- 第一页记录起始行为0,一共查询10行
- 第二页记录起始行为10,一共查询10行
- 第三页记录起始行为20,一共查询10行
查询语句的执行顺序
查询语句书写顺序:select-from-where-group by-having-order by-limit
查询语句执行顺序:from-where-group by-having-select-order by-limit
from决定从哪儿获取数据,where,group by,having决定决定显示那几行,select决定显示的列,order by对列进行排序,limit觉得获取哪些数据。
一步一步的筛选数据。
数据的完整性
数据的完整性只对增删改有作用,对查询数据没有限制。
作用:保证用户输入的数据保存到数据库中是正确的
确保数据的完整性=在创建表时给表中添加约束
完整性的分类:
- 实体完整性
- 域完整性
- 引用完整性
实体完整性
实体:即表中的一行(一条记录)代表一个实体
实体完整性的作用:标识每一行数据不重复
约束类型:主键约束(primary key) 唯一约束(unique) 自动增长列(auto_increment)
主键约束
每个表都要有一个主键。数据唯一,且不能为null。
第一种添加方式
create table student(
id int primary key,
name varchar(50)
);
第二种添加方式:此种方式优势在于,可以创建联合主键。但一般都不用联合主键
create table student(
id int,
name varchar(50),
primary key(id)
);
create table student(
classid int,
stuid int,
name varchar(50),
primary key(classid,stuid)
);
第三种添加方式
create table student(
id int,
name varchar(50)
);
alter table student add primary key(id);
唯一约束
特点:数据不能重复
create table student(
id int,
name varchar(50) unique
);
自动增长列
给主键添加自动增长的数值,列只能是整数类型
create table student(
id int primary key auto_increment,
name varchar(50)
);
insert into student(name) values('tom');
域完整性
域完整性的作用,限制此单元格的数据正确,不对照此列的其他单元格比较
域代表当前单元格
域完整性约束:
- 数据类型
- 非空约束(not null)
- 默认值约束(default)
create table student(
id int primary key,
name varchar(50) not null
);
create table student(
id int primary key,
name varchar(50) not null,
sex varchar(10) default '男'
);
引用完整性(参照完整性)
外键约束:foreign key
create table student(
id int primary key,
name varchar(50) not null
);
create table score(
id int primary key,
score int,
sid int,-- 外键,student表的id,数据类型要和student表中的一样
courseid,--外键
constraint fk_student_score_sid foreign key(sid) references student(id)
);
-- 另一种添加方式
alter table score add constraint fk_student_score_sid foreign key(sid) references student(id);
student表是主表,score是从表。从表中的数据参照主表里的数据。
- 先建立主表,后建立从表
- 从表中的数据是从主表中获得的, 从表不能够添加主表中不存在的数据。
- 主表不能够删除从表中已经使用的数据。如果要删除表的话,要先删除从表,再删除主表。
如果没有外键约束的话,score表中sid的值可以随意写。但这样不符合逻辑。现在添加约束,让这两张表有联系,添加完之后,score表中的sid的值只能是student表中的id值,不能写其他的。
- 从表外键的值是对主表主键的引用。
- 从表外键类型,必须与主表主键类型一致。
表与表之间的关系
-
一对多关系
- 常见实例,部门和员工。
- 建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键。
-
多对多关系
- 常见实例:学生和课程
- 多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这个两个字段分别作为外键指向各自一方的主键。(就是将一个多对多拆分成两个一对多)
- 两张表分别都是主表,第三张表为从表,提供两个字段,都是外键。
-
一对一关系(了解)
- 例如人和身份证。这种情况需要找出主从关系,即谁是主表,谁是从表。人可以没有身份证,但身份证必须要有人才行,所以人是主表,而身份证是从表。
- 在实际开发中应用不多,因为一对一可以创建成一张表
- 两种建表原则
- 外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一unique。(就是给从表的添加上唯一约束和外键约束)
- 外键是主键:主表的主键和从表的主键,形成主外键关系。(就是给从表添加上主键约束和外键约束)
-- 主表
create table QQ(
qqid int primary key,
password varchar(50)
);
-- 从表
create table QQDetail(
qqid int primary key,-- 设置主键
name varchar(50),
address varchar(200)
);
-- 给从表设置外键
alter table QQDetail add constraint fk_QQ_QQDetail_qqid foreign key(qqid) references QQ(qqid);
多表查询
合并结果集
create table A(
name varchar(10),
score int
);
create table B(
name varchar(10),
score int
);
insert into A values('a',10),('b',20),('c',30);-- 这种语法可以插入三条数据
insert into B values('a',10),('b',20),('d',40);
先建立两个表,各插入一条数据。
union,合并两个或多个select语句的结果集。条件:每个结果集必须有相同的列数,相容的数据类型。
union运算符合并了两个查询结果结果集,其中完全重复的数据被合并为了一条。如果要返回所有记录,在后边添加all。
select * from A
union
select * from B;
select * from A
union all
select * from B;
连接查询
一对一的例子
-- 创建数据库
create database shop;
-- 使用数据库
use shop;
-- 分类表
create table category(
cid varchar(32) primary key,
cname varchar(100)
);
-- 商品表
create table product(
pid varchar(32) primary key,
name varchar(40),
price double
);
-- 添加外键字段 category_id
alter table product add column category_id varchar(32);
-- 添加约束
alter table product add constraint product_fk foreign key (category_id) references category (cid);
-- 分类表
insert into category(cid,cname) values('c001','家电');
insert into category(cid,cname) values('c002','服饰');
insert into category(cid,cname) values('c003','化妆品');
-- 商品
insert into product(pid,name,price,category_id) values('p001','联想',5000,'c001');
insert into product(pid,name,price,category_id) values('p002','海尔',3000,'c001');
insert into product(pid,name,price,category_id) values('p003','雷神',5000,'c001');
insert into product(pid,name,price,category_id) values('p004','JACK JONES',800,'c002');
insert into product(pid,name,price,category_id) values('p005','真维斯',200,'c002');
insert into product(pid,name,price,category_id) values('p006','花花公子',440,'c002');
insert into product(pid,name,price,category_id) values('p007','劲霸',2000,'c002');
insert into product(pid,name,price,category_id) values('p008','香奈儿',800,'c003');
insert into product(pid,name,price,category_id) values('p009','相宜本草',200,'c003');
多对多的例子
-- 订单表
create table orders(
oid varchar(32) primary key,
totalprice double
);
-- 订单项表
create table orderitem(
oid varchar(50),-- 订单id
pid varchar(50) -- 商品id
);
-- 联合主键(可省略)
alter table orderitem add primary key(oid,pid);
-- 订单表和订单项表的主外键关系
alter table orderitem add constraint orderitem_orders_fk foreign key(oid) references orders(oid);
-- 商品表和订单项表的主外键关系
alter table orderitem add constraint orderitem_product_fk foreign key(pid) references product(pid);
现在主要看分类表和商品表,一个分类对应很多商品
1.交叉连接查询(基本不会使用-得到的是两个表的乘积)
- 语法:select * from A,B;
select * from category,product;
category有3行数据,product有9行数据,最终结果有27行数据。
类似这样的我用红线勾出的数据,cid和category_id对应不上,这样的数据没啥用。
连接查询会产生笛卡尔积,假设A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。
产生这样的结果并不是我们想要的,可以通过条件过滤去除重复。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。
2.内连接查询(使用关键字inner join – inner可省略)
select * from category,product where cid=category_id;
- 隐式内连接:select * from A,B where 条件;
- 显示内连接:select * from A inner join B on 条件;(这种方式是标准写法)
-- 1.查询那些分类的商品已经上架
-- 隐式内连接
select * from category,product where cid=category_id;
select * from category c,product where c.cid=product.category_id;
select cname from category c,product p where c.cid=p.category_id;
select distinct cname from category c,product p where c.cid=p.category_id;
-- 内连接
select * from category inner join product on cid=category_id;
select * from category join product on cid=category_id where price>3000;
select * from category join product on cid=category_id;
select
c.cid,c.cname,p.name
from
category c
join product p on c.cid=p.category_id;
这是这句话select * from category join product on cid=category_id;查出来的数据,之后可以添加各种条件再对这个结果集进行筛选。
3.外连接查询(使用关键字outer join –outer可以省略)
select * from category left join product on cid=category_id;
- 左外连接:left outer join
- select * from A left outer join B on 条件
- 右外连接:right outer join
- select * from A right outer join B on 条件
左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示null.
比如我现在在category表中添加一条数据
insert into category values('c004','生活用品');
然后执行
select * from category left join product on cid=category_id;
而用内连接的话
select * from category join product on cid=category_id;
显示结果还是
如果这时候我想查询每类商品的数量,这时候只能用左连接查询。
select
cname,count(category_id)
from
category
left join product on cid=category_id group by cname;
查询结果为
如果用内连接的话,会少一行数据
select
cname,count(category_id)
from
category
join product on cid=category_id group by cname;
连接查询不限与两张表,连接查询也可以是三张、四张,甚至N张表的连接查询。通常连接查询不可能需要整个笛卡尔积,而只是需要其中一部分,那么这时就需要使用条件来去除不需要的记录。这个条件大多数情况下都是使用主外键关系去除。多表连接,至少要有n-1个条件。
两张表的连接查询一定有一个主外键关系,三张表的连接查询就一定有两个主外键关系,当不是很熟悉连接查询时,首先要学会去除笛卡尔积,那么就是用主外键关系作为条件来处理。如果两张表的查询,那么至少有一个主外键条件,三张表连接至少有两个主外键条件。
先添加三条数据
-- 向订单表中添加数据
insert into orders(oid,totalprice) values('o001',3800);
-- 向订单和产品的中间表添加数据
insert into orderitem(oid,pid) values('o001','p002');
insert into orderitem(oid,pid) values('o001','p002');
select
orders.oid,orders.totalprice,product.name,product.price
from
orders
join orderitem on orders.oid=orderitem.oid
join product on orderitem.pid=product.pid;
-- 也可以写成
select
orders.oid,orders.totalprice,product.name,product.price
from
orders,orderitem,product
where orders.oid=orderitem.oid and orderitem.pid=product.pid;
自然连接
大家也都知道,连接查询会产生无用笛卡尔积,我们通常使用主外键关系等式来去除它。而自然连接无需你去给出主外键等式,它会自动找到这一等式:
两张连接的表中名称和类型完全一致的列作为条件,例如emp和dept表都存在deptno列,并且类型一致,所以会被自然连接找到!
select * from emp natural join dept;-- 内连接
select * from emp natural left join dept;-- 左连接
select * from emp natural right join dept;-- 右连接
子查询
SQL语句允许将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询。
若结果集为单行单列(标量子查询),则可放在select或where语句中
若结果集为多行单列,可放在where语句中,配合in使用
若结果集中有多行多列(就相当于一个表,派生表),一般作为数据源进行再一次检索。
-- 查询与SCOTT同一个部门的员工
select * from emp where deptno=(select deptno from emp where ename='SCOTT');
-- 查询工作和工资与MARTIN完全相同的员工信息
select * from emp where (job,sal) in (select job,sal from emp where ename='MARTIN');
-- 查询有2个以上直接下属的员工信息
select * from emp where empno in (select mgr from emp group by mgr having count(mgr)>=2);
-- 查询员工编号为7788的员工名称、员工工资、部门名称、部门地址
select e.ename,e.sal,d.dname,d.loc from emp e,(select dname,loc,deptno from dept) d where e.deptno=d.deptno and e.empno=7788;