本文用到的数据库如下:
CREATE DATABASE exam;
/*创建部门表*/
CREATE TABLE dept(
deptno INT PRIMARY KEY,
dname VARCHAR(50),
loc VARCHAR(50)
); /*创建雇员表*/
CREATE TABLE emp(
empno INT PRIMARY KEY,
ename VARCHAR(50),
job VARCHAR(50),
mgr INT,
hiredate DATE,
sal DECIMAL(7,2),
COMM DECIMAL(7,2),
deptno INT,
CONSTRAINT fk_emp FOREIGN KEY(mgr) REFERENCES emp(empno) ,
//CONSTRAINT fk_emp_dept FOREIGN KEY(deptno) REFERENCES dept(deptno);
//本来应该添加这个外键约束,但是为了以后做案列所以不加这个约束,因为加了这个约束,那么emp表中deptno的值就必须是dept表中的主键的某一值
); /*创建工资等级表*/
CREATE TABLE salgrade(
grade INT PRIMARY KEY,
losal INT,
hisal INT
); /*创建学生表*/
CREATE TABLE stu(
sid INT PRIMARY KEY,
sname VARCHAR(50),
age INT,
gander VARCHAR(10),
province VARCHAR(50),
tuition INT
); /*插入dept表数据*/
INSERT INTO dept VALUES (10, '教研部', '北京');
INSERT INTO dept VALUES (20, '学工部', '上海');
INSERT INTO dept VALUES (30, '销售部', '广州');
INSERT INTO dept VALUES (40, '财务部', '武汉'); /*插入emp表数据*/
INSERT INTO emp VALUES (1009, '曾阿牛', '董事长', NULL, '2001-11-17', 50000, NULL, 10);
INSERT INTO emp VALUES (1004, '刘备', '经理', 1009, '2001-04-02', 29750, NULL, 20);
INSERT INTO emp VALUES (1006, '关羽', '经理', 1009, '2001-05-01', 28500, NULL, 30);
INSERT INTO emp VALUES (1007, '张飞', '经理', 1009, '2001-09-01', 24500, NULL, 10);
INSERT INTO emp VALUES (1008, '诸葛亮', '分析师', 1004, '2007-04-19', 30000, NULL, 20);
INSERT INTO emp VALUES (1013, '庞统', '分析师', 1004, '2001-12-03', 30000, NULL, 20);
INSERT INTO emp VALUES (1002, '黛绮丝', '销售员', 1006, '2001-02-20', 16000, 3000, 30);
INSERT INTO emp VALUES (1003, '殷天正', '销售员', 1006, '2001-02-22', 12500, 5000, 30);
INSERT INTO emp VALUES (1005, '谢逊', '销售员', 1006, '2001-09-28', 12500, 14000, 30);
INSERT INTO emp VALUES (1010, '韦一笑', '销售员', 1006, '2001-09-08', 15000, 0, 30);
INSERT INTO emp VALUES (1012, '程普', '文员', 1006, '2001-12-03', 9500, NULL, 30);
INSERT INTO emp VALUES (1014, '黄盖', '文员', 1007, '2002-01-23', 13000, NULL, 10);
INSERT INTO emp VALUES (1011, '周泰', '文员', 1008, '2007-05-23', 11000, NULL, 20);
INSERT INTO emp VALUES (1001, '甘宁', '文员', 1013, '2000-12-17', 8000, NULL, 20);
INSERT INTO emp VALUES (1015, '张三', '保洁员', 1009, '2001-09-01', 24500, 50000, 50); //注意 ,在部门表中根本没有50部门 /*插入salgrade表数据*/
INSERT INTO salgrade VALUES (1, 7000, 12000);
INSERT INTO salgrade VALUES (2, 12010, 14000);
INSERT INTO salgrade VALUES (3, 14010, 20000);
INSERT INTO salgrade VALUES (4, 20010, 30000);
INSERT INTO salgrade VALUES (5, 30010, 99990); /*插入stu表数据*/
INSERT INTO `stu` VALUES ('', '王永', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '张雷', '', '男', '辽宁', '');
INSERT INTO `stu` VALUES ('', '李强', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '宋永合', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '叙美丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '陈宁', '', '女', '山东', '');
INSERT INTO `stu` VALUES ('', '王丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '李永', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '张玲', '', '女', '广州', '');
INSERT INTO `stu` VALUES ('', '啊历', '', '男', '山西', '');
INSERT INTO `stu` VALUES ('', '王刚', '', '男', '湖北', '');
INSERT INTO `stu` VALUES ('', '陈永', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '李雷', '', '男', '辽宁', '');
INSERT INTO `stu` VALUES ('', '李沿', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '王小明', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '王小丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '唐宁', '', '女', '山东', '');
INSERT INTO `stu` VALUES ('', '唐丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '啊永', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '唐玲', '', '女', '广州', '');
INSERT INTO `stu` VALUES ('', '叙刚', '', '男', '山西', '');
INSERT INTO `stu` VALUES ('', '王累', '', '男', '湖北', '');
INSERT INTO `stu` VALUES ('', '赵安', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '关雷', '', '男', '辽宁', '');
INSERT INTO `stu` VALUES ('', '李字', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '叙安国', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '陈浩难', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '陈明', '', '女', '山东', '');
INSERT INTO `stu` VALUES ('', '孙丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '李治国', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '张娜', '', '女', '广州', '');
INSERT INTO `stu` VALUES ('', '安强', '', '男', '山西', '');
INSERT INTO `stu` VALUES ('', '王欢', '', '男', '湖北', '');
INSERT INTO `stu` VALUES ('', '周天乐', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '关雷', '', '男', '辽宁', '');
INSERT INTO `stu` VALUES ('', '吴强', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '吴合国', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '正小和', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '吴丽', '', '女', '山东', '');
INSERT INTO `stu` VALUES ('', '冯含', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '陈冬', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '关玲', '', '女', '广州', '');
INSERT INTO `stu` VALUES ('', '包利', '', '男', '山西', '');
INSERT INTO `stu` VALUES ('', '威刚', '', '男', '湖北', '');
INSERT INTO `stu` VALUES ('', '李永', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '张关雷', '', '男', '辽宁', '');
INSERT INTO `stu` VALUES ('', '送小强', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '关动林', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '苏小哑', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '赵宁', '', '女', '山东', '');
INSERT INTO `stu` VALUES ('', '陈丽', '', '女', '北京', '');
INSERT INTO `stu` VALUES ('', '钱小刚', '', '男', '北京', '');
INSERT INTO `stu` VALUES ('', '艾林', '', '女', '广州', '');
INSERT INTO `stu` VALUES ('', '郭林', '', '男', '山西', '');
INSERT INTO `stu` VALUES ('', '周制强', '', '男', '湖北', '');
数据库设计
单表查询与多表查询 案列
单表查询练习
/*1\. 查询出部门编号为30的所有员工*/
SELECT *
FROM emp
WHERE deptno=30;
/*2\. 查询所有销售员的姓名、编号和部门编号。*/
SELECT ename, empno, deptno
FROM emp
WHERE job='销售员';
/*3\. 找出奖金高于工资的员工。*/
SELECT *
FROM emp
WHERE comm > sal
/*4\. 找出奖金高于工资60%的员工。*/
SELECT *
FROM emp
WHERE comm > sal*0.6;
/*5\. 找出部门编号为10中所有经理,和部门编号为20中所有销售员的详细资料。*/
SELECT *
FROM emp
WHERE (deptno=10 AND job='经理') OR (deptno=20 AND job='销售员')
/*6\. 找出部门编号为10中所有经理,部门编号为20中所有销售员,还有即不是经理又不是销售员但其工资大或等于20000的所有员工详细资料。*/
SELECT *
FROM emp
WHERE (deptno=10 AND job='经理') OR (deptno=20 AND job='销售员') OR (job NOT IN ('经理', '销售员') AND sal >= 20000)
/*8\. 无奖金或奖金低于1000的员工。*/
SELECT *
FROM emp
WHERE comm IS NULL OR comm < 1000
/*9\. 查询名字由三个字组成的员工。*/
SELECT *
FROM emp
WHERE ename LIKE '___'
/*10.查询2000年入职的员工。*/
SELECT *
FROM emp
WHERE hiredate LIKE '2000-%'
/*11\. 查询所有员工详细信息,用编号升序排序*/
SELECT *
FROM emp
ORDER BY empno
/*12\. 查询所有员工详细信息,用工资降序排序,如果工资相同使用入职日期升序排序*/
SELECT *
FROM emp
ORDER BY sal DESC, hiredate ASC
/*13\. 查询每个部门的平均工资*/
SELECT deptno, AVG(sal)
FROM emp
GROUP BY deptno
/*14\. 查询每个部门的雇员数量。*/
SELECT deptno, COUNT(*)
FROM emp
GROUP BY deptno
/*15\. 查询每种工作的最高工资、最低工资、人数*/
SELECT job, MAX(sal), MIN(sal), COUNT(*)
FROM emp
GROUP BY job
多表查询练习
/*
1. 查出至少有一个员工的部门。显示部门编号、部门名称、部门位置、部门人数。
列:d.deptno, d.dname, d.loc, 部门人数
表:dept d, emp e
条件:e.deptno=d.deptno
*/
SELECT d.*, z1.cnt
FROM dept d, (SELECT deptno, COUNT(*) cnt FROM emp GROUP BY deptno) z1
WHERE d.deptno = z1.deptno
/*
3. 列出所有员工的姓名及其直接上级的姓名。
列:员工姓名、上级姓名
表:emp e, emp m
条件:员工的mgr = 上级的empno
*/
SELECT e.ename, IFNULL(m.ename, 'BOSS') 领导
FROM emp e LEFT OUTER JOIN emp m
ON e.mgr=m.empno
/*
4. 列出受雇日期早于直接上级的所有员工的编号、姓名、部门名称。
列:e.empno, e.ename, d.dname
表:emp e, emp m, dept d
条件:e.hiredate<m.hiredate
*/
SELECT e.empno, e.ename, d.dname
FROM emp e, emp m, dept d
WHERE e.mgr=m.empno AND e.hiredate<m.hiredate AND e.deptno=d.deptno
/*
5. 列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门。
列:*
表:emp e, dept d
条件:e.deptno=d.deptno
*/
SELECT *
FROM emp e RIGHT OUTER JOIN dept d
ON e.deptno=d.deptno
/*
7. 列出最低薪金大于15000的各种工作及从事此工作的员工人数。
列:job, count(*)
表:emp e
条件:min(sal) > 15000
分组:job
*/
SELECT job, COUNT(*)
FROM emp e
GROUP BY job
HAVING MIN(sal) > 15000
/*
8. 列出在销售部工作的员工的姓名,假定不知道销售部的部门编号。
列:e.ename
表:emp
条件:e.deptno=(select deptno from dept where dname='销售部')
*/
SELECT *
FROM emp e
WHERE e.deptno=(SELECT deptno FROM dept WHERE dname='销售部')
/*
9. 列出薪金高于公司平均薪金的所有员工信息,所在部门名称,上级领导,工资等级。
列:*
表:emp e
条件:sal>(查询出公司的平均工资)
*/
SELECT e.*, d.dname, m.ename, s.grade
FROM emp e, dept d, emp m, salgrade s
WHERE e.sal>(SELECT AVG(sal) FROM emp) AND e.deptno=d.deptno AND e.mgr=m.empno AND e.sal BETWEEN s.losal AND s.hisal
---------------
SELECT e.*, d.dname, m.ename, s.grade
FROM
emp e LEFT OUTER JOIN dept d ON e.deptno=d.deptno
LEFT OUTER JOIN emp m ON e.mgr=m.empno
LEFT OUTER JOIN salgrade s ON e.sal BETWEEN s.losal AND s.hisal
WHERE e.sal>(SELECT AVG(sal) FROM emp)
SELECT * FROM emp;
SELECT * FROM dept;
SELECT * FROM salgrade;
/*
10.列出与庞统从事相同工作的所有员工及部门名称。
列:e.*, d.dname
表:emp e, dept d
条件:job=(查询出庞统的工作)
*/
SELECT e.*, d.dname
FROM emp e, dept d
WHERE e.deptno=d.deptno AND job=(SELECT job FROM emp WHERE ename='庞统')
/*
11.列出薪金高于在部门30工作的所有员工的薪金 的员工姓名和薪金、部门名称。
列:e.ename, e.sal, d.dname
表:emp e, dept d
条件;sal>all (30部门薪金)
*/
SELECT e.ename, e.sal, d.dname
FROM emp e, dept d
WHERE e.deptno=d.deptno AND sal > ALL (SELECT sal FROM emp WHERE deptno=30)
/*
13.查出年份、利润、年度增长比
*/
SELECT y1.*, IFNULL(CONCAT((y1.zz-y2.zz)/y2.zz*100, '%'), '0%') 增长比
FROM tb_year y1 LEFT OUTER JOIN tb_year y2
ON y1.year=y2.year+1;
写在前面: 文章以MySQL为软件,关于MySQL这个软件的基本应用,请点击这儿学习
什么是SQL
SQL : Structured Query Language (结构化查询语言)。 作用是: 客户端使用SQL来操作服务器。
SQL标注: 是由国际标准化组织(ISO)制定的,对DBMS的统一操作方式。
SQL方言: 每个DBMS都除了会遵循标准之外,会有自己的方言。也就是自己所以特有的特殊的语句或者句法。
SQL语法:
- SQL语句可以在单行或者多行书写,以分号结束 ,没有写分号,可以换行 ;
- 可以使用空格或者缩进来增强语句的可读性 ;
- MySQL 是不区分大小写的,不过建议大写 。
- 数据库中所有的字符串类型都需要用单引号,不能使用双引号
SQL语句的分类
- DDL (Data Definition Language ) : 数据定义语言,用来对数据库或表的结构进行操作 。 也就是创建、删除、修改 库和表结构
- DML (Data Manipulation Language ) : 数据操作语言,用来对表的记录进行更新 , 也就是对表的记录进行增、删、改
- DQL (Dat Query Language ) : 数据查询语言 , 用来对表的记录进行查询
- DCL (Dat Control Language ) : 数据控制语言 , 用来定义访问权限和安全级别
数据库存储的数据类型
点击这里下载数据类型文档
DDL
DDL _ 对库的操作
- 查看所有数据库:
SHOW DATABASES ;
- 切换(选择要操作的)数据库:
USE 数据库名 ;
- 创建数据库:
CREATE DATABASE mydb1 [CHARSET=utf8]
//方框号是表示可选择的。 语句中没有方框号 - 删除数据库:
DROP DATABASE mydb1
- 修改数据库编码:
ALTER DATABASE mydb1 CHARACTER SET utf8
DDL _ 对表的操作
- 创建表
CREATE TABLE 表名(
列名 列类型,
列名 列类型,
...
列名 列类型
);
- 查看当前数据库中所有表名称:
SHOW TABLES;
- 查看表结构:
DESC 表名;
- 删除表:
DROP TABLE 表名;
- 修改_添加列:
ALTER TABLE 表名
ADD (
列名 列类型,
列名 列类型,
...
);
- 修改_修改列类型
ALTER TABLE 表名 MODIFY 列名 列类型;
- 修改_修改列名:
ALTER TABLE 表名 CHANGE 原列名 新列名 列类型;
- 修改_删除列:
ALTER TABLE 表名 DROP 列名;
- 修改_修改表名称:
ALTER TABLE 原表名 RENAME TO 新表名;
DML
where条件语法
- 条件必须是一个boolean类型的值或表达式
where 属性判断
- 条件的运算符:
运算符 | 说明举例 | 运算符 | 说明举例 |
---|---|---|---|
= | 等于 | != | 不等于 |
<> | 大于小于 | > | 大于 |
< | 小于 | >= | 大于等于 |
<= | 小于等于WHERE age >= 18 AND age <= 80 | between..and | WHERE age BETWEEN 18 AND 80 |
in(...) | WHERE name IN ('zhangSan', 'liSi')包括zhangSan和liSi | is null | WHERE age IS NULL;选中age为NULL |
not | 非 | or | 或者 |
and | 和 |
WHERE age >= 18 AND age <= 80
选中年龄在大于18和小于80WHERE age BETWEEN 18 AND 80
选中年龄在大于18和小于80
WHERE name='zhangSan' OR name='liSi'
选中名字是zhanSan或者liSi的WHERE name IN ('zhangSan', 'liSi') ;
选中名字是zhangSan和liSiWHERE age IS NULL
选择年龄值为空的WHERE age IS NOT NULL
选择年龄值不为空的
插入数据
INTERT INTO 表名(列名1,列名2, ...) VALUES(列值1, 列值2, ...);
值的顺序和个数必须与前面指定的列对应,没有给出具体指自动插入null。 如果没有给出列名,表示插入所有列
INSERT INTO stu(
number, name, age, gender
)
VALUES(
'11111111', 'zhangSan', 28, 'male'
);
修改数据
UPDATE 表名 SET 列名1=列值1, 列名2=列值2, ... [WHERE 条件]
方框号表示可以指定条件,实际语句中没有方框号。如果不加条件,就是所有记录的该列名的值全部被修改
UPDATE stu SET number=55, name='liSi' WHERE age BETWEEN 18 AND 80 //把年龄在18~80之间的所有学生number改成55,name改成liSi
删除数据
DELETE FROM 表名 [WHERE 条件];
常用删除语句TRUNCATE TABLE 表名
: TRUNCATE是DDL语句,它是先删除drop该表,再create该表。而且无法回滚!!!
DCL 超级用户root
创建用户
CREATE USER 用户名@IP地址 IDENTIFIED BY '密码';
用户只能在指定的IP地址上登录CREATE USER 用户名@'%' IDENTIFIED BY '密码';
用户可以在任意IP地址上登录
本机的IP地址可以使用localhost
用户授权
GRANT 权限1, … , 权限n ON 数据库.* TO 用户名@IP地址
给用户分派在指定的数据库上的指定的权限GRANT ALL ON 数据库.* TO 用户名@IP地址;
给用户分派指定数据库上的所有权限
权限有: create、alter、drop、insert、update、delete、select
例如;GRANT CREATE,ALTER,DROP,INSERT,UPDATE,DELETE,SELECT ON mydb1.* TO user1@localhost;
撤销授权
REVOKE 权限1, … , 权限n ON 数据库.* FROM 用户名@IP地址;
撤消指定用户在指定数据库上的指定权限
例如;REVOKE CREATE,ALTER,DROP ON mydb1.* FROM user1@localhost;
查看权限
SHOW GRANTS FOR 用户名@IP地址
查看指定用户的权限
删除用户
DROP USER 用户名@IP地址
删除用户
DQL_数据库查询语言
基础查询
查询所有的列 ; select * from 表名 ;
查询指定的列: select 列1 ,列2 ,...,列n from 表名;
如果有重复记录,则只显示一个记录 :select distinct * from 表名 ;
列运算
列运算只是对显示做了运算,并没有修改数据库中的内容
- 加减乘除:
select 列1+列2 from 表名 ;
列可以加减乘除数字 。 字符串当0处理。如果某一列中有记录为NULL,则需要用ifnull(有null值的列,0)
将null值转换为0,当然用ifnull(有null值的列,'XXX')
可以将null值转换成字符串XXX - 给列起一个别名,这个别名只是对显示有效,并没有修改数据库中的真实列名:
SELECT 列1原名 AS 列1别名, 列2原名 AS 列2别名 FROM 表名;
其中as是可以省略的 - 字符串的连续运算:
select concat('我叫',name,'我的工作是',job) from 表名 ;
其中name和job都是表的列。
条件查询_where
使用where关键字作为条件,可参考where的 条件运算符
模糊查询_like
- 查询员工表emp中姓名ename列中,姓张的,并且只有两个字的所有员工 ;
select * from emp where ename like '张_' ;
,_
的代表一个模糊的任意字符,一个下划线匹配一个字符。 - 查询员工表emp中姓名ename列中,只有三个字的所有员工 ;
select * from emp where ename like '___'
; - 查询员工表emp中姓名ename列中, 姓张的所有员工 :
select * from emp where ename like '张%' ;
其中%
号匹配多个字符 - 查询员工表emp中姓名ename列中,最后一字是林的所有员工 :
select * from emp where ename like '%林' ;
- 查询员工表emp中姓名ename列中,带小的所有员工 :
select * from emp where ename like '%小%' ;
排序_order by
升序--根据年龄由小到大对所有记录进行排序 : select * from where emp order by age asc
; age为表的列,其中asc可以省略
降序--根据工资(sal)由大到小对所有记录进行排序 : select * from where emp order by sal desc ;
, desc不可以省略
使用多列作为排序条件---根据年龄对所有进行升序,如果年龄相同的某些记录,根据工资对这些记录进行降序排序 : select * from where emp order by age asc , sal desc ;
聚合函数
聚合函数是用来做某列的纵向运算
- 查询行数: 查询emp表中所有列都不为NULL的记录的行数 :
select count(*) from emp ;
- 查最大值/最小值: 查询工资(sal)最大是多少 :
select max(sal) from emp ;
- 查询和,NULL和字符串都当成0计算 : 查询所有人工资的和 :
select sum(sal ) from emp ;
- 查询平均值,NULL和字符串都当成0计算 : 查询所有人的平均工资 :
select avg(sal) from emp ;
综合一下:select count(*) 人数,sum(sal) 总和,max(sal) 最高工资,avg(sal ) 平均工资 from emp ;
分组查询
分组查询的意思是把记录用某一列进行分组,然后查询信息,查的信息都是组信息,而不是个人信息,组信息一般都是用聚合函数计算出来的
- 使用部门(deptno)分组,查询部门编号和每个部门的记录数:
select deptno,count(*) from emp group by deptno ;
- 使用工作(job)分组,查询每种工作的最高工资:
select job ,max(sal) from emp group by job ;
组条件:分组前用where,分组后用having - 使用部门(deptno)分组,查询每组记录数,条件为记录数的工资大于15000(分组前的条件):
select deptno ,count(*) from emp where sal>15000 group by deptno ;
- 使用部门(deptno)分组,查询每组记录数,条件为每组中的记录工资大于15000(分组前的条件),并且记录数要大于等于2(分组后的条件):
select deptno ,count(*) from emp where sal>15000 group by deptno having count(*) >=2 ;
limit子句 方言
limit子句是mysql的方言,也就是mysql所特有的语言,作用是用来限定查询结果的起始行,以及总行数
- 查询起始行为第五行,一共查询3行记录:
select * from emp limit 4,3 ;
,其中4表示第5行,第一行是从0开始的,3表示一共查询3条记录
这个功能用在分页查询上非常的方便
关键字的书写顺序
用上所有的关键字的关键字书写顺序和执行顺序是: select 、from、 where、group by 、having、order by
约束
主键约束与其相关
当表的某一列被指定为主键后, 该列就不能为空(非空)、不能出现重复值(唯一性)、而且能够被引用(外键)
定义主键 PRIMARY KEY
,主键自增长AUTO_INCREMENT
, 某列非空 NOT NULL
, 唯一约束NOT NULL UNIQUE
CREATE TABLE stu(
sid INT PRIMARY KEY AUTO_INCREMENT, //定义主键,自增长
sname VARCHAR(20) NOT NULL UNIQUE, //定义名字唯一性(不重复)
age INT NOT NULL, //定义年龄非空
gender VARCHAR(10)
);
修改表时 指定主键 : ALTER TABLE stu ADD PRIMARY KEY (sid ) ;
修改表时设置主键自增长:ALTER TABLE stu CHANGE sid sid INT AUTO_INCREMENT;
修改表时删除主键自增长:ALTER TABLE stu CHANGE sid sid INT;
删除主键 : ALTER TABLE stu DROP PRIMARY KEY ;
建立多对一 外键约束
员工表(
员工编号 ,主键
员工姓名 ,
。。。。
员工部门编号 (值是10,20,30,null)
CONSTRAINT fk_员工表_部门表 FOREIGN KEY (员工部门编号) REFERENCES 部门表(部门编号) ; //添加外键约束
);
部门表(
部门编号 ,主键
部门名称
);
如上代码, 员工和所属部门是多对一的关系 。 员工表中部门这一列就是员工表的外键 。
外键必须是表(另一个表或者本表都可以)的主键值,即 外键引用主键 。 外键内容可以重复、可以为空。 一张表可以有多个外键 。
外键的取值必须在部门表的主键值的范围之内,不能出现部门表主键没有的值,否则会报错误 。
修改表时添加外键约束 :ALTER TABLE 员工表 ADD CONSTRAINT fk_员工表_部门表 FOREIGN KEY(员工部门编号) REFERENCES 部门表(部门编号);
修改表时删除外键约束 : ALTER TABLE 员工表 DROP FOREIGN KEY fk_员工表_部门表 ;
建立一对一 外键约束
需要要其中一张表的主键即是主键又是外键
丈夫表(
丈夫编号 ,主键
丈夫姓名 ,
);
妻子表(
妻子编号 ,主键+外键
妻子名字
CONSTRAINT fk_妻子表_丈夫表 FOREIGN KEY (妻子编号) REFERENCES 丈夫表(丈夫编号) ; //添加外键约束
);
如上代码 , 丈夫和妻子是一对一的关系 。 妻子表中的妻子编号即是主键又是外键 。
建立多对多 外键约束
需要使用三张表 , 在中间表中使用两个外键,分别引用其他两个表的主键 。
学生表(
学生编号 , 主键
学生姓名
);
教师表(
教师编号 , 主键
教师姓名
);
中间表(
中间表学生编号 ,
中间表教师编号
CONSTRAINT fk_学生表_教师表_添加学生外键 FOREIGN KEY(中间表学生编号) REFERENCES 学生表(学生编号), //添加外键约束
CONSTRAINT fk_学生表_教师表_添加教师外键 FOREIGN KEY(中间表教师编号) REFERENCES 教师表(教师编号) //添加外键约束
);
如上述代码 , 学生和教师是多对多的关系 。 中间表中的每条记录都是来说明学生和教师之间的关系 。
多表查询
连接查询
内连接
/*
方言 , MySQL所特有
查询 员工姓名 工资 和所在部门名称
*/
SELECT e.ename,e.sal,d.dname
FROM emp AS e,dept AS d
WHERE e.deptno=d.deptno;
/*
标准 ,以后建议都用标准
查询 员工姓名 工资 和所在部门名称
*/
SELECT e.ename,e.sal,d.dname
FROM emp AS e INNER JOIN dept AS d
ON e.deptno=d.deptno;
上述执行就可以发现 , 查询出的人名中并没有张三这个人,因为张三的部门是50,而在部门表中并没有50这个部门。 如果想要显示张三,并且对应部门的名称显示NULL 的话,需要外连接
外连接
/*
左链接 ,先查询出左表(以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL
*/
SELECT e.ename,e.sal,d.dname
FROM emp AS e LEFT OUTER JOIN dept d
ON e.deptno=d.deptno ;
/*
右链接 ,先查询出右表(以右表为主),然后查询左表,左表中满足条件的显示出来,不满足条件的显示NULL
*/
SELECT e.ename,e.sal,d.dname
FROM emp AS e RIGHT OUTER JOIN dept d
ON e.deptno=d.deptno ;
/*
全外连接
SELECT e.ename,e.sal,d.dname
FROM emp AS e FULL OUTER JOIN dept d
ON e.deptno=d.deptno ;
但是MySQL数据库不支持,可以用UNION ALL 的方式来解决
*/
SELECT e.ename,e.sal,d.dname
FROM emp AS e LEFT OUTER JOIN dept d
ON e.deptno=d.deptno
UNION ALL
SELECT e.ename,e.sal,d.dname
FROM emp AS e RIGHT OUTER JOIN dept d
ON e.deptno=d.deptno ;
如上代码所示, 外连接有左右之分,左链接 ,先查询出左表(以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL,比如,员工中的张三,先把张三查询出来,然后右表(部门表)中并没有50号部门,所以显示NULL 。 右链接 ,先查询出右表(以右表为主),然后查询左表,左表中满足条件的显示出来,不满足条件的显示NULL ,比如部门表中有个40号财务部门,先查询出来,但是左表(员工)中并没有40号部门的员工,所以左侧都显示为NULL.
子查询
子查询就是嵌套查询,select中包含多个select 。 子查询出现的位置 ,在where后,作为条件的一部门 ;在from后,作为被查询的一条表 。当子查询出现在where后作为条件时,可以用any、all 关键字 。
子查询的结果集的形式有 : 单行单列、单行多列、多行单列、多行多列
/*
子查询案例一 : 查询工资高于关羽工资的员工
子查询作为条件 。 形式为单行单列
子条件是关羽的工资
*/
SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename="关羽") ;
/*
子查询案例二 : 工资高于30部门所有人的员工信息
子查询作为条件 。 形式为多行单列
子条件是30部门所有人的工资
*/
SELECT * FROM emp WHERE sal > ALL (SELECT sal FROM emp WHERE deptno=30) ;
/*
子查询案例三 : 查询工作和工资与殷天正完全相同的员工
子查询作为条件 。 形式为单行多列
子条件是殷天正的工作和工资
*/
SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename="殷天正");
/*
子查询案例四 : 查询员工编号为1006的员工名称、部门名称、员工工资、部门地址
子查询 作为表。 形式为多行多列
子条件是部门表中的部门名称、部门地址 , 部门编号作为去除笛卡尔积的条件也必须被查询
*/
SELECT e.ename,e.sal,d.dname,d.loc
FROM emp AS e , (SELECT dname ,loc ,deptno FROM dept) AS d
WHERE e.deptno=d.deptno AND e.empno=1006 ;