sql基础
1.数据库的三大范式(规范)
window+r cmd进入命令输入显示窗口 登录数据库后 mysql -u root -p 123456
输入show variables like 'version'; 显示数据库版本
原子性1.无重复的列
唯一性2.要求数据库表中的每个实例或者每一行都可被唯一的区分。
直接性3.要求数据库表中不包含已在其他表中以存在的非主关键字信息。
SQL:Structure Query Language(结构化查询语言)
Create, Read, Update, and Delete 通常称为CRUD操作
SQL语句分类
DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等。
DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据的)增删改
DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别。
DQL(Data Query Language):数据查询语言,用来查询记录(数据)查询。
修改数据库名称
修改时候确保没有用户连接数据库,不然会报错
sp_renamedb @dbname='Test_1', @newname='Test';
DDL操作数据库
创建数据库
CREATE DATABASE语句用于创建新的数据库:
编码方式:gb2312,utf-8,gbk,iso-8859-1
//create database 数据库名
CREATE DATABASE mydb1;
//create database 数据库名 character set 编码方式
CREATE DATABASE mydb2 character SET GBK;
//create database 数据库名 set 编码方式 collate 排序规则
CREATE DATABASE mydb3 character SET GBK COLLATE gbk_chinese_ci;
查看数据库
查看当前数据库服务器中的所有数据库 show databases;
查看前面创建的mydb2数据库的定义信息 Show CREATE DATABASE mydb2; //show create database 数据库名;
修改数据库
alter database 数据库名 character set 编码方式 // ALTER DATABASE mydb2 character SET utf8;
删除数据库
drop database 数据库名
查看当前使用的数据库
Select database();
切换数据库: use 数据库名
USE mydb2;
CREATE TABLE语句用于创建新表
CREATE TABLE 表名(
列名1 数据类型 [约束],
列名2 数据类型 [约束],
列名n 数据类型 [约束]
);
例子:
create table student(
garde varchar(10) not null comment '年级',
name varchar(10) default null comment '学生姓名',
xueshi int default null comment '学时',
isexam char(1) default null comment '是否参加考试 1表示参加',
subject varchar(10) default null comment '学科',
score int default null comment '分数'
)engine =InnoDB default charset =utf8 comment '学生表';
说明:表名,列名是自定义,多列之间使用逗号间隔,最后一列的逗号不能写
[约束] 表示可有可无
其他表操作
删除表 DROP TABLE table_name;
当前数据库中的所有表 SHOW TABLES;
查看表的字段信息 DESC employee;
在存在的表中新加列 ALTER TABLE employee ADD image blob; // alter table 表名 add 新列名 新的数据类型
修改列 alter table 表名 change 旧列名 新列名 新的数据类型
修改字段类型 alter table 表名 modify 列名 新的数据类型
modify关键字修改样式只能修改字段的类型,不能进行字段的重命名
删除列,一次只能删除一列 alter table 表名 drop 列名
修改表名 alter table 旧表名 rename 新表名;
查看表格的创建细节 show create table 表名;
修改表的字符集为gbk alter table 表名 character set 编码方式
DML操作
INSERT 、UPDATE、 DELETE
在mysql中,字符串类型和日期类型都要用单引号括起来。
注意:1多列和多个列值之间使用逗号隔开 2.列名要和列值一一对应 3.可以省略列名,但value顺序要一一对应
(1)插入操作:INSERT:
insert into 表名(列名) values(数据值);
例子:
insert into student(stuname,stuage,stusex,birthday)
values('张三3',18,'a','2000-1-1'),
('张三4',18,'a','2000-1-1'),
('张三5',18,'a','2000-1-1');
(2)修改(更新)操作:UPDATE:
UPDATE 表名 SET 列名1=列值1,列名2=列值2 ... WHERE 列名=值 多条件语句用and连接 where后面没有条件时默认更新整个表的set 列
(3)删除操作:DELETE:
DELETE from 表名 【WHERE 列名=值】 delete from emp;删除表中的所有数据;
DELETE 删除表中的数据,表结构还在;删除后的数据可以rollback找回
truncate删除是把表直接DROP掉,然后再创建一个同样的新表 删除的数据不能找回,执行速度比delete快。
DCL操作
需要登录root 才能设置用户以及用户权限
1、创建用户:
create user 用户名@指定ip identified by 密码; create user test123@localhost IDENTIFIED by 'test123'
create user 用户名@客户端ip identified by 密码; 指定IP才能登陆 create user test456@10.4.10.18 IDENTIFIED by 'test456'
create user 用户名@‘% ’ identified by 密码 任意IP均可登陆 create user test7@'%' IDENTIFIED by 'test7'
创建用户后,要赋予用户的对数据库的操作权限
2、用户授权:
grant 权限1,权限2,........,权限n on 数据库名.* to 用户名@IP;
grant select,insert,update,delete,create on chaoshi.* to 'test456'@'127.0.0.1';
grant all on *.* to 用户名@IP 给指定用户授予所有数据库所有权限
grant all on *.* to 'test456'@'127.0.0.1';
3、用户权限查询:
show grants for 用户名@IP;
4、撤销用户权限:
revoke 权限1,权限2,........,权限n on 数据库名.* from 用户名@IP;
5、删除用户:
drop user 用户名@IP; 删除用户过后,无法登录
DQL数据查询
查询关键字:SELECT
语法: SELECT 列名 FROM 表名 【WHERE --> GROUP BY-->HAVING--> ORDER BY】 //* 表示所有列
SELECT 要查询的列名称 FROM 表名称 WHERE 限定条件 /*行条件*/
GROUP BY grouping_columns /*对结果分组*/
HAVING condition /*分组后的行条件*/
ORDER BY sorting_columns /*对结果分组排序*/
LIMIT offset_start, row_count /*结果限定*/
条件查询就是在查询时给出WHERE子句,在WHERE子句中可以使用如下运算符及关键字:
=、!=、<>、<、<=、>、>=; BETWEEN…AND ; IN(set); IS NULL; AND;OR; NOT;
// BETWEEN…AND 注意:1.开始值<结束值 2.包含临界值的
模糊查询
语法: 列名 like '表达式' //表达式必须是字符串
_(下划线): 任意一个字符
%:任意0~n个字符,'张%'
查询姓名由5个字母构成,并且第5个字母为“i”的学生记录 SELECT * FROM stu WHERE sname LIKE '____i';
字段控制查询
(1)去除重复记录
当只查询emp表的sal字段时,那么会出现重复记录,那么想去除重复记录,需要使用DISTINCT:distinct 发音:第四听可特
SELECT DISTINCT sal FROM emp;
2)查看雇员的月薪与佣金之和
因为sal和comm两列的类型都是数值类型,所以可以做加运算。如果sal或comm中有一个字段不是数值类型,那么会出错。
SELECT *,sal+comm FROM emp;
comm列有很多记录的值为NULL,因为任何东西与NULL相加结果还是NULL,所以结算结果可能会出
现NULL。下面使用了把NULL转换成数值0的函数IFNULL:
SELECT *,sal+IFNULL(comm,0) FROM emp;
(3)给列名添加别名
在上面查询中出现列名为sal+IFNULL(comm,0),这很不美观,现在我们给这一列给出一个别名,为total:
SELECT *, sal+IFNULL(comm,0) AS total FROM emp; 其中as可以省略
排序
语法: order by 列名 asc/desc
(1) 查询所有学生记录,按年龄升序排序
SELECT * FROM stu ORDER BY age ASC;
(2)查询所有雇员,按月薪降序排序,如果月薪相同时,按编号升序排序
多列排序:当前面的列的值相同的时候,才会按照后面的列值进行排序
SELECT * FROM emp
ORDER BY sal DESC,empno ASC;
聚合函数
聚合函数是用来做纵向运算的函数:
COUNT(列名):统计指定列不为NULL的记录行数;
MAX(列名):计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;
MIN(列名):计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;
SUM(列名):计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;
AVG(列名):计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;
查询emp表中记录数: SELECT COUNT(*) AS cnt FROM emp;
查询emp表中有佣金的人数: SELECT COUNT(comm) cnt FROM emp;
注意,因为count()函数中给出的是comm列,那么只统计comm列非NULL的行数。
查询emp表中月薪大于2500的人数: SELECT COUNT(*) FROM emp WHERE sal > 2500;
统计月薪与佣金之和大于2500元的人数: SELECT COUNT(*) AS cnt FROM emp WHERE sal+IFNULL(comm,0) > 2500;
查询有佣金的人数,以及有领导的人数:SELECT COUNT(comm), COUNT(mgr)FROM emp;
SUM和AVG
当需要纵向求和时使用sum()函数。
查询所有雇员月薪和: SELECT SUM(sal) FROM emp;
查询所有雇员月薪和,以及所有雇员佣金和: SELECT SUM(sal), SUM(comm) FROM emp;
查询所有雇员月薪+佣金和:SELECT SUM(sal+IFNULL(comm,0))FROM emp;
统计所有员工平均工资:SELECT AVG(sal) FROM emp;
MAX和MIN
查询最高工资和最低工资:SELECT MAX(sal), MIN(sal) FROM emp;
分组查询
gruop需要配合聚合函数使用
查询每个部门的部门编号和每个部门的工资和:
SELECT deptno, SUM(sal) FROM emp GROUP BY deptno;
查询每个部门的部门编号以及每个部门的人数:
SELECT deptno,COUNT(*) FROM emp GROUP BY deptno;
查询每个部门的部门编号以及每个部门工资大于1500的人数:
SELECT deptno,COUNT(*) FROM emp WHERE sal>1500 GROUP BY deptno;
查询工资总和大于8000的部门编号以及工资和:
SELECT deptno, SUM(sal) FROM emp GROUP BY deptno HAVING SUM(sal) > 8000;
having与where的区别:
1.having是在分组后对数据进行过滤,where是在分组前对数据进行过滤
2.having后面可以使用分组函数(统计函数),where后面不可以使用分组函数。
WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分
组;而HAVING是对分组后数据的约束。
统计出stu表中每个班级的男女生各多少人
select grade,gender ,count(*) from stu group by grade,gender; //如果需要进行二次分组,gruoup by 后的第一个分组条件用,隔开
limit分页查询
limit 开始下标,显示条数;//开始下标从0开始
limit 显示条数;//表示默认从0开始获取数据
查询10行记录,起始行从3开始
SELECT* FROM emp LIMIT 3, 10;
如果一页记录为10条,希望查看第3页记录应该怎么查呢?
第一页记录起始行为0,一共查询10行; limit 0,10
第二页记录起始行为10,一共查询10行;limit 10,10
第三页记录起始行为20,一共查询10行; limit 20,10
pageIndex 页码值 pageSize 每页显示条数
java程序中的实现思路 :limit (pageindex-1)*pagesize,pagesize;
查询语句书写顺序:select – from- where- group by- having- order by-limit
查询语句执行顺序:from - where -group by -having - select - order by-limit
# 查询每个参加考试的学员的平均分 先分组后在avg 每组的平均分
select name, avg(score) from student group by name;
# 查询每门课程的平均分,并按照降序排列
select subject,avg(score) from student group by subject order by avg(score) desc ;
sql进阶
数据库的完整性
确保数据的完整性 = 在创建表时给表中添加约束
完整性的分类:
- 实体完整性(行完整性):
- 域完整性(列完整性):
- 引用完整性(关联表完整性):
主键约束:primary key
唯一约束:unique [key]
非空约束:not null
默认约束:default
自动增长:auto_increment
外键约束: foreign key
建议这些约束应该在创建表的时候设置
多个约束条件之间使用空格间隔
示例:
create table student(
studentno int primary key auto_increment,
loginPwd varchar(20) not null default '123456',
studentname varchar(50) not null,
sex char(2) not null,
gradeid int not null,
phone varchar(255) not null,
address varchar(255) default '学生宿舍',
borndate datetime,
email varchar(50)
);
实体完整性
实体:即表中的一行(一条记录)代表一个实体(entity)
实体完整性的作用:标识每一行数据不重复。
约束类型: 主键约束(primary key) 唯一约束(unique) 自动增长列(auto_increment)
主键约束(primary key)
注:每个表中要有一个主键。 特点:数据唯一,且不能为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);
唯一约束(unique)
特点:数据不能重复。
CREATE TABLE student( Id int primary key, Name varchar(50) unique );
自动增长列(auto_increment)
sqlserver数据库 (identity-标识列)
oracle数据库(sequence-序列)
给主键添加自动增长的数值,列只能是整数类型
CREATE TABLE student( Id int primary key auto_increment, Name varchar(50) );
INSERT INTO student(name) values(‘tom’);
域完整性
域完整性的作用:限制此单元格的数据正确,不对照此列的其它单元格比较
域代表当前单元格
域完整性约束:数据类型 非空约束(not null) 默认值约束(default)
check约束(mysql不支持)check(sex='男' or sex='女')
引用完整性
外键约束:FOREIGN KEY
示例:
CREATE TABLE student(id int primary key, name varchar(50) not null, sex
varchar(10) default '男' );
create table score(
id int primary key,
score int,
sid int ,
constraint fk_score_sid foreign key(sid) references student(id) );
constraint 自定义外键名称 foreign key(外键列名) references 主键表名(主键列名)
外键列的数据类型一定要与主键的类型一致
第二种添加外键方式
ALTER TABLEscore1 ADD CONSTRAINT fk_stu_score FOREIGN KEY(sid) REFERENCES stu(id);
多表查询
多个表之间是有关系的,那么关系靠谁来维护?
多表约束:外键列
一对多/多对一关系
客户和订单,分类和商品,部门和员工.
一对多建表原则:在多的一方创建一个字段,字段作为外键指向一的一方的主键
多对多关系
学生和课程
多对多关系建表原则:需要创建第三张表,中间表中至少两个字段,这两个字段分别作为外键指向各自一方的主键.
一对一关系
在实际的开发中应用不多.因为一对一可以创建成一张表
两种建表原则:
唯一外键对应:假设一对一是一个一对多的关系,在多的一方创建一个外键指向一的一方的主键,将外
键设置为unique.
主键对应:让一对一的双方的主键进行建立关系,一个表的主键作为外键连接到另一个表的主键.
多表查询有如下几种:
1. 合并结果集:UNION 、 UNION ALL
2. 连接查询
2.1内连接 [INNER] JOIN ON
2.2外连接 OUTER JOIN ON
-左外连接 LEFT [OUTER] JOIN
- 右外连接 RIGHT [OUTER] JOIN
- 全外连接(MySQL不支持)FULL JOIN
2.3 自然连接 NATURAL JOIN
3.子查询
合并结果集
作用:合并结果集就是把两个select语句的查询结果合并到一起!
合并结果集有两种方式:
l UNION:去除重复记录,例如:SELECT* FROM t1 UNION SELECT * FROM t2;
l UNION ALL:不去除重复记录,例如:SELECT 列名1,列名2 FROM t1 UNION ALL SELECT 列名1,列名2 FROM t2;
注意:被合并的两个结果:列数、列类型必须相同。否者报错。
连接查询
连接查询就是求出多个表的乘积,例如t1连接t2,那么查询出的结果就是t1*t2。
连接查询会产生笛卡尔积,假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),
(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。
那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过
条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。
解决方法:1使用主外键关系做为条件来去除无用信息
SELECT * FROM emp,dept WHERE emp.deptno=dept.deptno;
一:使用内连接
select 列名 from 表1 inner join 表2 on 表1.列名=表2.列名 //外键列的关系 where....
等价于:select 列名 from 表1,表2 where 表1.列名=表2.列名 and ...(其他条件)
注:<1>表1和表2的顺序可以互换
<2>找两张表的等值关系时,找表示相同含义的列作为等值关系。
<3>点操作符表示“的”,格式:表名.列名
<4>可以使用as,给表名起别名,注意定义别名之后,统一使用别名 ... from 表1 as 别名,表2 别名 ...
三表联查:
语法:
select 列名 from 表1
inner join 表2 on 表1.列名=表2.列名
inner join 表3 on 表1或表2.列名=表3.列名 where...
等价于:
select 列名 from 表1,表2,表3
where 表1.列名=表2.列名 and 表1/表2.列名=表3.列名 and...
练习
1.显示出花儿的考试成绩以及对应科目
select subjectName,score from student2 s
inner join score02 on s.stuid=score02.studnetid
inner join subject2 on subject2.subjectid=score02.subject where s.stuname='花儿';
2.显示出所有考试学生的信息
select * from student2 s
inner join score02 on s.stuid=score02.studnetid
inner join subject2 on subject2.subjectid=score02.subject ;
3.查询出mysql的考试信息
select * from student2 s
inner join score02 on s.stuid=score02.studnetid
inner join subject2 on subject2.subjectid=score02.subject where subject2.subjectName='mysql';
//这里的subject2可以省略
4.查询出考试学员的总分
select sum(score) from student2 s
inner join score02 on s.stuid=score02.studnetid
inner join subject2 on subject2.subjectid=score02.subject ;
5.查询每科的平均分
select subjectName,avg(score) from student2 s
inner join score02 on s.stuid=score02.studnetid
inner join subject2 on subject2.subjectid=score02.subject group by subjectName;
二:外连接
包括左外连接和右外连接,外连接的特点:查询出的结果存在不满足条件的可能。
-- 显示还没有员工的部门名称?
select * from emp1 e,dept1 d where e.deptno=d.deptno ;这时候dept1 部门里面的aa 是没有显示的,有这个部门,但是没有部员对应不上,不会显示没有部员的部门信息
select dname,count(ename) from emp1 e
right join dept1 d on e.deptno = d.deptno group by dname;
左外联:select 列名 from 主表 left join 次表 on 主表.列名=次表.列名
右外联:select 列名 from 次表 right join 主表 on 主表.列名=次表.列名
1.主表数据全部显示,次表数据匹配显示,能匹配到的显示数据,匹配不成功的显示null
2.主表和次表不能随意调换位置
使用场景:一般会作为子查询的语句使用
三.自然连接
自然连接(NATURAL INNER JOIN):自然连接是一种特殊的等值连接,他要求两个关系表中进行连
接的必须是相同的属性列(名字相同),无须添加连接条件,并且在结果中消除重复的属性列。
select * from dept1 natural join emp1; deptno这个字段两个表都有,查询结果就只显示一个列。
子查询
一个select语句中包含另一个完整的select语句。
子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么
就是子查询语句了。
l 子查询出现的位置:
a. where后,作为条为被查询的一条件的一部分;
b. from后,作表;
当子查询出现在where后作为条件时,还可以使用如下关键字:
a. any 满足条件最差的那个 比如大于 查询结果中 最小
b. all 满足条件最好的那个 比如大于 查询结果中 最大
例子:
工资高于JONES的员工
第一步:查询JONES的工资 SELECT sal FROM emp WHERE ename='JONES';
第二步:查询高于甘宁工资的员工 SELECT * FROM emp WHERE sal > (第一步结果);
第四章:扩展(多表插入,删除,更新操作)
多行新增
insert into 表名(列名) values (列值),(列值),(列值);
多表更新
(1)update 表1,表2 set 列名=列值 列名=列值 where 表1.列名=表2.列名 and 其他限定条件
(2)update 表1
inner join 表2 on 表1.列名=表2.列名
set 列名=列值 列名=列值
where 限定条件
update employee e,salary s set title='助工',salary=1000 where e.empid=s.empid and name='李四'
多表删除
delete 被删除数据的表 from 删除操作中使用的表 where 限定条件
//删除人事部的信息
delete d,e,s from department d,employee e,salary s where d.depid=e.depid and s.empid=e.empid and depname='人事部'
日期运算函数
now() 获得当前系统时间
year(日期值) 获得日期值中的年份 select year(hiredate) from emp;
date_add(日期,interval 计算值 计算的字段); select date_add(date (hiredate),interval -40 year),day (hiredate) from emp;
注:计算值大于0表示往后推日期,小于0表示往前推日期
示例:
date_add(now(),interval -40 year);//40年前的日期
索引的创建
索引的分类:普通索引、唯一索引、主键索引、联合索引(复合索引)、全文索引
有四种方式来添加数据表的索引
alter table tbl_name add primary key (column_list) 该语句添加一个主键,这意味这索引值必须是唯一的的,且补能为空
alter table tbl_name add unique index_name (column_list) 这条语句创建索引的值必须是唯一的(null除外,null可以出现多次)
alter table tbl_name add index index_name (column_list) 添加普通索引,索引的值可以出现多次
alter table tbl_name add fulltext index_name (column_list) 添加全文索引
第五章:数据库优化
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫
描,如:
select id from t where num is null
最好不要给数据库留NULL,尽可能的使用 NOT NULL填充数据库.
备注、描述、评论之类的可以设置为 NULL,其他的,最好不要使用NULL。
3.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则引擎将放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致
引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or Name = 'admin'
可以这样查询:
select id from t where num = 10
union all
select id from t where Name = 'admin'
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
很多时候用 exists 代替 in 是一个好的选择