常用SQL语句练习【持续更新】

mysql启动关闭

-- 启动/关闭Mysql数据库服务
net start mysql
net stop mysql
-- 登录/退出mysql服务器软件
mysql -uroot -p123 
-- 连接他人的mysql
mysql -hip地址 -u用户名 -p密码  
mysql -host=127.0.0.1 -user=root -password=123456
-- mysql的退出
-- exit或者quit都可以在命令行退出mysql服务器软件,而不是关闭mysql服务。

DDL:数据定义语言用来操作数据库的CRUD

-- 1.C(Create):创建
create database db;-- 创建db数据库
create database if not exists db1;-- 判断是否存在db1数据库,不存在则创建db1,存在则不创建
create database db2 character set gbk;-- 创建db2数据库并设置字符集gbk(默认utf8):
-- 创建db3数据库,判断是否存在,并设置字符集为gbk:    
create database if not exists db3 character set dbk;

-- 2.R(Retrieve):查询
show databases;-- 查询所有数据库的名称:
show create database 数据库名称; -- 查询某个数据库的字符集(或创建语句)

-- 3.U(Update):修改
alter database db3 character set utf8;-- 修改数据库db3的字符集(gbk)为utf8:

-- 4.D(Delete):删除
drop database db1;-- 删除数据库db1:(不判断,若没有则报错)
drop database if exists db1; -- 判断是否存在数据库db1,存在则删除,不存在则不删除
  
-- 5.使用数据库:
select database();  -- 查询正在使用的数据库名称, 若没有使用数据库则返回null
use db3;-- 使用db3数据库:

DDL:数据定义语言用来操作数据表的CRUD

-- 1.创建student表
create table student(
         id int,
         name varchar(32),
         age int,
         score double(4,1),
         birthday date,
         insert_time timestamp   //插入时间,让系统自动赋值
);

-- 2.R(Retrieve):查询表
show tables;-- 查询某个数据库中所有表的名称(前提是已经进入数据库中)。
desc student;-- 查询表结构:

-- 3.U(Update):修改表
alter table add unique(字段名称):--为表中的字段增加唯一约束
alter table student rename to student1;-- 修改表名student为student1:
show create table student1;-- 查看表的字符集(查看创建表的语句):
alter table student1 character set utf8; -- 修改表的字符集:
alter table 表名 add 列名 数据类型; -- 添加一列:
alter table student1 add gender varchar(10);
alter table 表名 change 旧列名 新列名 新数据类型; -- 修改列名和数据类型
alter table student1 change gender sex varchar(20);
alter table 表名 modify 列名 新数据类型;
alter table student1 modify sex varchar(15);
alter table 表名 drop 列名; -- 删除列
alter table student1 drop sex;
  
-- 4.D(Delete):删除表
drop table 表名;
drop table if exists 表名;  -- 判断后再删除。
 
-- 5.复制表student到studet1:
create table student1 like student;

DML:数据操作语言:增删改表中数据,操作表中数据:

-- 1.向表中插入数据
insert into student1(id,name,age)values(1,'张三',18);-- 表student1中给id,name和age列添加值
insert into student1 values(2,'李四',20,99.9,null,null);-- 给表student1所以列添加值
-- 2.删除表数据:
delete from student1 where id=1;-- 删除student1表中编号为1的记录:
delete from student1;-- 要删除表中所有记录(不推荐)
truncate table student1;-- 要删除表中所有记录(推荐)
-- 3.修改数据:
update student1 set age=25 where id=2;

DQL:数据查询语言--查询表中的记录

-- 初始化表student2:
DROP TABLE student2;
CREATE TABLE student2 (
 id INT, -- 编号
 NAME VARCHAR(20), -- 姓名
 age INT, -- 年龄
 sex VARCHAR(5), -- 性别
 address VARCHAR(100), -- 地址
 math INT, -- 数学
 english INT -- 英语
);
INSERT INTO student2(id,NAME,age,sex,address,math,english) 
VALUES (1,'马云',55,'男','杭州',66,78),
(2,'马化腾',45,'女','深圳',98,87),
(3,'马景涛',55,'男','香港',56,77),
(4,'柳岩',20,'女','湖南',76,65),
(5,'柳青',20,'男','湖南',86,NULL),
(6,'刘德华',57,'男','香港',99,99),
(7,'马德',22,'女','香港',99,99),
(8,'德玛西亚',18,'男','南京',56,65);
SELECT * FROM student2;

-- 基础查询
select name,age from student2; -- 查询student2表中name,age字段信息
select * from student2; -- 查询student2表中所有字段信息
select distinct address from student2; -- 查询去重后的地址字段
select distinct name,address from student2;-- 查询去重name和address字段信息
select name,math,english,math+english from student2;-- 查询列值四则运算结果
select name,math,english,math+ifnull(english,0) from student2;-- ifnull处理运算中null
select name,math,english,math+ifnull(english,0) as 总分 from student2;-- 给列其别名as可省
-- 多条件查询
select * from student2 where age <> 20;-- 查询年龄不等于20岁的人员信息
select * from student2 where age!=20;
select * from student2 where age between 20 and 30;-- 查询年龄[20,30]之间人员信息
select * from student2 where age>=20 and age<=30;
select * from student2 where age=20 or age=18 or age=30;-- 查询年龄为18,20,30的人
select * from student2 where age in(18,20,30);
select * from student2 where english is not null;-- 查询英语成绩不为Null的人
-- like查询
select * from student2 where name like '李%';-- 查询姓李的人
select * from student2 where name like '_雨_';-- 查询姓名第二个字为雨的人
select * from student2 where name like '___';-- 查询姓名为三个字的人
select * from student2 where name like '%德%';-- 查询名字中有德的人
-- 排序查询
select * from student2 order by math DESC; -- 按数学成绩降序排序
select * from student2 order by math ASC,english DESC;
-- 聚合函数查询(统计某列数据)
select count(name) from student2; -- 通过name字段统计表记录个数
select count(isnull(english,0))from students;-- 解决null值问题
select count(主键所在的列一般为id)from student2;-- 推荐使用
select max(math) from student2; -- 查询数学最高分
select min(math) from student2; -- 查询数学最低分
select sum(math) from student2; -- 查询某字段数据的和(排除null)
select avg(math) from student2; -- 查询某字段数据的均值(排除null)
-- 分组查询
按照性别分组,分别查询男,女同学的数学平均分以及人数
 select sex avg(math) count(id) from student2 group by sex;
按照性别分组,分别查询男,女同学的数学平均分以及人数,要求低于70分的人不参与分组。
 select sex avg(math) count(id) from student2 where math>70 order by sex;
按照性别分组,分别查询男,女同学的数学平均分以及人数,要求低于70分的人不参与分组,且人数要大于2人。
select sex avg(math) count(id) 人数 from student2 where math>70 order by sex having 人数>2;

DCL数据控制语言的使用

1、创建用户:
    在指定ip计算机的数据库服务器上添加用户密码
    若是在本机创建用户则指定ip为localhost,这样可以通过用户名和密码来访问本机上的数据库服务器
    语法:create user 用户名@指定ip identified by 密码;
    例子:create user test123@localhost IDENTIFIED by 'test123

    
    通过用户名test456和密码test456可以访问指定ip电脑上的Mysql服务器(前提是对方服务器开启了)
    create user 用户名@客户端ip identified by 密码;
    create user test456@10.4.10.18 IDENTIFIED by'test456'

    
    任意IP均可登陆
    create user 用户名@‘% ’ identified by 密码 
    create user test7@'%' IDENTIFIED by 'test7'
2、用户授权:
    给ip机上指定的数据库用户授予的指定的数据库权限
    grant 权限1,权限2,........,权限n on 数据库名.* to 用户名@IP;

    给指定的ip机上指定的用户授予所有数据库的所有权限
    grant all on . to 用户名@IP

    数据库名.*表示这个数据库中所有表
3、用户权限查询:
    show grants for 用户名@IP; --查询指定ip计算机的数据库服务器中的指定用户名权限

4、撤销用户权限:
    revoke 权限1,权限2,........,权限n on 数据库名.* from 用户名@IP;

5、删除用户:
    drop user 用户名@IP;

以下是表的约束相关sql语句

-- 创建部门表(id,dep_name,dep_location) 一方,主表
CREATE TABLE department(
   id INT PRIMARY KEY AUTO_INCREMENT, -- 主键约束+主键自增长约束
   dep_name VARCHAR(20) NULL NULL,  -- 非空约束
   dep_location VARCHAR(20)
);
-- 添加 2 个部门
INSERT INTO department VALUES(NULL, '研发部','广州'),(NULL, '销售部', '深圳');
SELECT * FROM department;

-- 创建员工表(id,name,age,dep_id) 多方,从表
CREATE TABLE employee(
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20) UNIQUE,  -- 唯一约束
  age INT,
  dep_id INT, 
  -- 设置外键dep_id对应主表department的主键id
  CONSTRAINT emp_dept_fk FOREIGN KEY (dep_id) REFERENCES department(id)
);

-- 下面给外键添加级联操作,需要先删除外键,然后重新添加外键,
-- 同时设置级联的更新和删除操作
 ALTER TABLE employee DROP FOREIGN KEY emp_dept_fk;
 ALTER TABLE employee ADD constrainst (emp_dept_fk) FOREIGN KEY (dep_ip) REFERENCES 
 department (id) ON UPDATE CASCADE ON DELETE CASCADE;

-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO employee (NAME, age, dep_id) VALUES ('张三', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('李四', 21, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('王五', 20, 1);
INSERT INTO employee (NAME, age, dep_id) VALUES ('老王', 20, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('大王', 22, 2);
INSERT INTO employee (NAME, age, dep_id) VALUES ('小王', 18, 2);
SELECT * FROM employee;

下面是多表操作,遵循建表原则

  下面是多表操作:多对多关系的多表设计
  旅游网站有收藏功能:即用户根据旅游线路分类,选择旅游线路,收藏进收藏夹。设计数据库表:
  一个旅游线路分类中有多个旅游线路。
  一个用户收藏多个线路,一个线路被多个用户收藏。
  三个实体:旅游线路分类,旅游线路和用户,设计三张表,用户表和线路表是多对多则需要中间表收藏表。

-- 创建旅游线路分类表 tab_category
/*cid 旅游线路分类主键,自动增长
  cname 旅游线路分类名称非空,唯一,字符串 100
*/
create table tab_category (
  cid int primary key auto_increment,
  cname varchar(100) not null unique
);
-- 添加旅游线路分类数据:
insert into tab_category (cname) values ('周边游'), ('出境游'), ('国内游'), ('港澳游');
select * from tab_category;


-- 创建旅游线路表 tab_route
/*
rid 旅游线路主键,自动增长
rname 旅游线路名称非空,唯一,字符串 100
price 价格
rdate 上架时间,日期类型
cid 外键,所属分类
*/
create table tab_route(
   rid int primary key auto_increment,
   rname varchar(100) not null unique,
   price double,
   rdate date,
   cid int,
  foreign key (cid) references tab_category(cid)
);
-- 添加旅游线路数据
INSERT INTO tab_route VALUES
(NULL, '【厦门+鼓浪屿+南普陀寺+曾厝垵 高铁 3 天 惠贵团】尝味友鸭面线 住 1 晚鼓浪屿', 1499,
'2018-01-27', 1),
(NULL, '【浪漫桂林 阳朔西街高铁 3 天纯玩 高级团】城徽象鼻山 兴坪漓江 西山公园', 699, '2018-02-22', 3),
(NULL, '【爆款¥1699 秒杀】泰国 曼谷 芭堤雅 金沙岛 杜拉拉水上市场 双飞六天【含送签费 泰风情 广州往返 特价团】', 1699, '2018-01-27', 2),
(NULL, '【经典•狮航 ¥2399 秒杀】巴厘岛双飞五天 抵玩【广州往返 特价团】', 2399, '2017-12-23',2),(NULL, '香港迪士尼乐园自由行 2 天【永东跨境巴士广东至迪士尼去程交通+迪士尼一日门票+香港如心海景酒店暨会议中心标准房 1 晚住宿】', 799, '2018-04-10', 4);

select * from tab_route;


-- 创建用户表 tab_user
/*uid 用户主键,自增长
username 用户名长度 100,唯一,非空
password 密码长度 30,非空
name 真实姓名长度 100
birthday 生日
sex 性别,定长字符串 1
telephone 手机号,字符串 11
email 邮箱,字符串长度 100
*/
create table tab_user (
   uid int primary key auto_increment,
   username varchar(100) unique not null,
   password varchar(30) not null,
   name varchar(100),
   birthday date,
   sex char(1) default '男',
   telephone varchar(11),
   email varchar(100)
);
-- 添加用户数据
INSERT INTO tab_user VALUES
(NULL, 'cz110', 123456, '老王', '1977-07-07', '男', '13888888888', '66666@qq.com'),
(NULL, 'cz119', 654321, '小王', '1999-09-09', '男', '13999999999', '99999@qq.com');
select * from tab_user;



-- 创建收藏表 tab_favorite
/*
rid 旅游线路 id,外键
date 收藏时间
uid 用户 id,外键
rid 和 uid 不能重复,设置复合主键,同一个用户不能收藏同一个线路两次
*/
create table tab_favorite (
   rid int,
   date datetime,
   uid int,
-- 创建复合主键
   primary key(rid,uid),
   foreign key (rid) references tab_route(rid),-- 复合主键中每一主键作为外键指向主表主键
   foreign key(uid) references tab_user(uid)
);
-- 增加收藏表数据
INSERT INTO tab_favorite VALUES
(1, '2018-01-01', 1), -- 老王选择厦门
(2, '2018-02-11', 1), -- 老王选择桂林
(3, '2018-03-21', 1), -- 老王选择泰国
(2, '2018-04-21', 2), -- 小王选择桂林
(3, '2018-05-08', 2), -- 小王选择泰国
(5, '2018-06-02', 2); -- 小王选择迪士尼
select * from tab_favorite;

下面是多表查询的:内连接查询(隐式/显示)

# 创建部门表
CREATE TABLE dept(
   id INT PRIMARY KEY AUTO_INCREMENT,
   NAME VARCHAR(20)
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');

# 创建员工表dept
CREATE TABLE emp (
   id INT PRIMARY KEY AUTO_INCREMENT,
   NAME VARCHAR(10),
   gender CHAR(1), -- 性别
   salary DOUBLE, -- 工资
   join_date DATE, -- 入职日期
   dept_id INT,
   FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('孙悟空','男',7200,'2013-02-24',1);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('猪八戒','男',3600,'2010-12-02',2);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('唐僧','男',9000,'2008-08-08',2);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('白骨精','女',5000,'2015-10-07',3);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('蜘蛛精','女',4500,'2011-03-14',1);
   INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
   ('实习生','女',3000,'2011-03-14',NULL);
   
 /*
 笛卡尔积:即两个集合的所有组合,若A集合3条数据,B集合4条数据,那么它们的组合有3*4=12种。
 select * from emp,dept;
 */
 
 /*
 内连接查询:
 1.从哪些表中查询数据
 2.查询条件是什么
 3.查询哪些字段
 */
 -- 内连接(隐式内连接查询):使用where条件来消除无用的数据
 SELECT * FROM emp,dept WHERE emp.dept_id=dept.id;-- 查询所有员工信息和对应的部门信息
 -- 查询员工表的姓名,性别以及对应的部门表的名字
 SELECT emp.name,emp.gender,dept.name FROM emp,dept WHERE emp.dept_id=dept.id;
 -- 标准格式;
 SELECT 
        t1.name,
        t1.gender,
        t2.name
 FROM 
        emp t1,
        dept t2
 WHERE
        t1.dept_id=t2.id;
-- 内连接(显示内连接查询):使用 (inner) join...on条件
SELECT * FROM emp INNER JOIN dept ON emp.dept_id=dept.id;-- 查询所有员工信息和对应的部门信息

下面是多表查询的:外连接查询(左/右)

/*
外连接查询
1.左外连接: left join..on条件
        1.语法:
          *select 字段列表 from 表1 left [outer] join 表2 on 条件   (outer可以省略不写)
          *左外连接查询的是左表所有数据以及其交集部分(两表交集)   
          /*这里新添加一个实习生还没有分配部门编号(部门编号虽然是外键,但可以设置Null值,没有 
            非空约束)若以内连接(比如隐式内连接)查询,则实习生这个记录不会被查询出来,因为没有 
            部门编号。这种情况下就需要使用左外连接(因为左外连接可以显示左表的所有数据及其交 
            集,这样左表中的实习生记录虽然没有部门,但也可查询出来):
2.右外连接:
         1.语法:
           *select 字段列表 from 表1 right [outer] join 表2 on 条件
           *右外连接查询的是右表所有数据以及其交集部分(两表交集)   
             查询所有员工信息,如果员工有部门,则查询部门名称,没部门,则不查询该员工信息。
             没有部门则不查询员工信息,使用右外连接可以实现,因为右外连接可以显示右表所有的数 
             据及其交集,由于左右表交集部分就是dept_id,由于左表实习生这条记录没有dept_id则无 
             法显示该条记录
           
3.一般只使用左外连接,因为左外连接中把两张表兑换位置就成右连接了。
*/

-- 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门,则也查询出来。
SELECT t1.*,t2.name  -- 左外连接
FROM emp t1
LEFT JOIN dept t2
ON t1.dept_id=t2.id;
-- 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门,则不查询该员工信息。
SELECT t1.*,t2.name FROM emp t1 RIGHT JOIN dept t2 ON t1.dept_id=t2.id; -- 右外连接

下面是多表查询的:子查询

/*
子查询  概念:查询中嵌套查询,称为子查询。
*/

-- 查询工资最高的员工信息(分部)
SELECT MAX(salary) FROM emp; -- 1.查询到最高工资为9000
SELECT * FROM emp WHERE emp.salary=9000; -- 2.查询到最高工资为9000的员工信息
-- 查询工资最高的员工信息(嵌套查询)
SELECT * FROM emp WHERE emp.salary=(SELECT MAX(salary) FROM emp);

/*
 子查询不同情况:
     1.子查询的结果是单行单列的:
          *子查询可以直接作为条件,使用运算符> < = <=等去判断。
     2.子查询的结果是多行单列的:
          *子查询可以直接作为条件,使用IN集合运算符判断。
     3.子查询的结果是多行多列的:
          *子查询可以作为一张虚拟表,来参与多表的查询。
*/

-- 情况1
-- 查询工资最高的员工信息(嵌套查询)
SELECT * FROM emp WHERE emp.salary=(SELECT MAX(salary) FROM emp);
-- 查询员工工资小于平均工资的人
SELECT * FROM emp WHERE emp.aslary<(SELECT AVG(salary) FROM emp);

-- 情况2
-- 查询'财务部'和'市场部'所有员工的信息
SELECT * FROM emp WHERE dept_id IN (
      SELECT id FROM dept WHERE NAME='财务部' OR NAME='市场部'
);

-- 情况3
-- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息,(嵌套查询实现)
-- 可以先查询出员工信息表,然后通过部门编号对员工信息表和部门信息表进行多表查询。
SELECT * FROM dept t1,(SELECT * FROM emp WHERE emp.join_date>2011-11-11) t2,
WHERE t1.id=t2.dept_id;
-- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息,(内连接实现不用嵌套查询更好理解)
SELECT * FROM emp t1,dept t2,WHERE t1.dept_id=t2.id AND t1.join_date>201-11-11;

下面是多表查询的练习(内连接(隐式的显示的),外连接(左外,右外),子查询(三种情况))


-- 初始化数据库
-- 部门表
CREATE TABLE dept (
  id INT PRIMARY KEY PRIMARY KEY, -- 部门id
  dname VARCHAR(50), -- 部门名称
  loc VARCHAR(50) -- 部门所在地
);

-- 添加4个部门
INSERT INTO dept(id,dname,loc) VALUES 
(10,'教研部','北京'),
(20,'学工部','上海'),
(30,'销售部','广州'),
(40,'财务部','深圳');



-- 职务表,职务名称,职务描述
CREATE TABLE job (
  id INT PRIMARY KEY,
  jname VARCHAR(20),
  description VARCHAR(50)
);

-- 添加4个职务
INSERT INTO job (id, jname, description) VALUES
(1, '董事长', '管理整个公司,接单'),
(2, '经理', '管理部门员工'),
(3, '销售员', '向客人推销产品'),
(4, '文员', '使用办公软件');


-- 员工表
CREATE TABLE emp (
  id INT PRIMARY KEY, -- 员工id
  ename VARCHAR(50), -- 员工姓名
  job_id INT, -- 职务id
  mgr INT , -- 上级领导
  joindate DATE, -- 入职日期
  salary DECIMAL(7,2), -- 工资
  bonus DECIMAL(7,2), -- 奖金
  dept_id INT, -- 所在部门编号
  CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
  CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
);

-- 添加员工
INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES 
(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);


-- 工资等级表
CREATE TABLE salarygrade (
  grade INT PRIMARY KEY,   -- 级别
  losalary INT,  -- 最低工资
  hisalary INT -- 最高工资
);

-- 添加5个工资等级
INSERT INTO salarygrade(grade,losalary,hisalary) VALUES 
(1,7000,12000),
(2,12010,14000),
(3,14010,20000),
(4,20010,30000),
(5,30010,99990);

需求:

  • 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
  • 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
  • 3.查询员工姓名,工资,工资等级
  • 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
  • 5.查询出部门编号、部门名称、部门位置、部门人数
  • 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询

1.先分析这几张表的关系:

  • emp员工表中编号id,员工名字ename,job_id是职位编号是外键对应着职位表job的主键,mgr是它的管理者编号,joindate是入职日期,salary是薪资,bonus是奖金,dept_id部门编号,也是一个外键对应着部门表的主键,
  • 因为员工表和职位表之间是一对多的关系,即一个员工对应一个职位,一个职位对应多个员工;
  • 同理员工表和部门表也是一对多的关系,即一个员工对应一个部门,一个部门对应多个员工。
  • 因为这两对表都是一对多的关系,所以对一对多关系的多表实现只要通过外键分别关联着部门表和职位表的主键,这样当部门表中某部门被砍掉后,那么员工表中对应的员工也会自动被删除掉。另外还有一个薪资等级表。

2.关系模式(逻辑结构设计)

  • emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id);
  • dept(id,dname,loc);
  • job(id,jname,descript);
  • salarygrade(grade,losalary,hisalary);
/*
多表查询的几种方式:
  1.内连接:
      隐式内连接:使用where条件来消除无用的数据。
      显示内连接:from 表1 join 表2 on 条件
  2.外连接:
      左外连接:from 表1 left join 表2 on 条件; 左外连接查询的是左表所有数据以及其交集部分(两表交集) 
      右外连接:from 表1 left join 表2 on 条件; 右外连接查询的是右表所有数据以及其交集部分(两表交集)
  3.子查询:
      子查询的结果是单行单列的,子查询可以直接作为条件,使用运算符去判断。
      子查询的结果是多行单列的,子查询可以直接作为条件,使用IN集合运算符判断。
      子查询的结果是多行多列的,子查询可以作为一张虚拟表,来参与多表的查询。
*/

-- 需求:

-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
/*
  分析: 1.需要哪些表:emp表,job表
       2.查询条件(找外键):emp.job_id=job.id
       3.查询方式:最简单的可以直接使用内连接(隐式的)
  下面SQL是最规范的写法。
*/
select 
       t1.id,    -- 查询员工编号     
       t1.ename, -- 员工姓名
       t1.salary,-- 工资
       t2.jname, -- 职务名称
       t2.description -- 职务描述
from 
       emp t1,dept t2
where 
       t1.job_id=t2.id;
       
-- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
/*
   分析:1.需要查询哪些表:emp表,job表,dept表。
       2.查询条件(找外键):emp.job_id=job.id and emp.dept_id=dept.id;
       3.查询方式:还是内连接方便。
*/
select 
       t1.id,    -- 查询员工编号     
       t1.ename, -- 员工姓名
       t1.salary,-- 工资
       t2.jname, -- 职务名称
       t2.description, -- 职务描述
       t3.dname, -- 部门名称
       t3.loc  -- 部门位置
from 
       emp t1,job t2,dept t3 
where 
       t1.job_id=t2.id and ti.dept_id=t3.id;  

-- 3.查询员工姓名,工资,工资等级,以及工资所在的范围
/*
   分析:1.需要查询哪些表:emp表,salarygrade表
       2.查询条件:注意,这两张表并没有外键关联。不能使用等式,使用大于小于或者between..and..
       emp.salary>=salarygrade.losalary and emp.salary<=salarygrade.hisalarygrade
       或者emp.salary between salarygrade.losalary  and salarygrade.hisalarygrade
*/
select 
      t1.ename,
      t1.salary,
      t2.*
from emp t1, salarygrade t2
where t1.salary between t2.losalary  and t2.hisalary;

-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
/*
   分析:1.需要查询哪些表:emp表,job表,dept表,salarygrade表
       2.查询条件;emp.job_id=job.id and emp.dept_id=dept.id
         and emp.salary between salarygrade.losalary  and salarygrade.hisalarygrade
*/
select 
     t1.ename, -- 员工姓名
     t1.salary, -- 员工薪资
     t2.jname, -- 职务名称
     t2.description, -- 职务描述
     t3.dname,  -- 部门名称
     t3.loc,   -- 部门位置
     t3.grade  -- 工资等级
     
from 
     emp t1, job t2, dept t3, salarygrade t4
where 
     t1.job_id=t2.id -- 员工表和职位表关联
     and t1.dept_id=t3.id -- 员工表和部门表关联
     AND t1.salary BETWEEN t4.losalary  AND t4.hisalary;-- 员工表和薪资等级表关联

-- 5.查询出部门编号、部门名称、部门位置、部门人数
/*
  分析:1.需要查询的表:dept表,部门人数使用emp表,
      2.使用分组查询。按照emp.dept_id完成分组,查询count(id). 
        (部门人数是通过emp表查询的,即单表查询各组人数,必然使用分组查询出各个分组人数)
      3.使用子查询将第二步的查询结果集作为虚表和dept表进行关联查询。
        使用了子查询的第三种情况。
*/
select 
       t1.id, -- 部门编号
       t1.dname,-- 部门名称
       t1.loc, -- 部门位置
       t2.total -- 部门人数
from 
       dept t1,
       (select   
               dept_id,count(id) total -- 给部门个数起别名
        from
               emp
        group by dept_id
       ) t2   
       -- 子查询的结果集(每个部门编号以及对应的部门人数)作为虚表,和dept表关联查询
where 
      t1.id=t2.dept_id;

-- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
/*
   分析:首先解释下直接上级:在emp员工表中有id以及管理者编号mgr,那么mgr的编号就是本人的直接上级,比如孙悟空的id是1001,它的mgr管理者编号是1004,那么孙悟空的直接上级就是id为1004的唐僧。
       1.需要查询的表:emp表,emp表的id和mgr是自关联的。可以给emp分别起别名t1,t2.
       2.查询条件:emp.id=emp.mgr
       3.为实现 没有领导的员工也需要查询,由于罗贯中最大,所以他没有mgr编号。
        查询左表t1(ename,mgr)所有数据和交集数据。右表t2(id,ename),右表中并没要求id,方便看。
        使用左连接查询。from 左表 left join 右表 on 条件
*/
-- 若直接内连接查询,则mgr管理者编号为Null的员工就找不到对应的id,则查询数据不全。
select 
       t1.ename,
       t1.mgr,
       t2.id,
       t2.ename
from emp t1,emp t2
where t1.mgr=t2.id;
-- 需要使用左外连接,将含有Null数据的表作为左表,进行左外连接查询左表所有数据和交集字段数据。
select
       t1.ename,
       t1.mgr,
       t2.id,
       t2.ename
from emp t1
left join emp t2
on t1.mgr=t2.id;

多表查询练习

  • 某网上商城数据库如下图所示

综合练习-【多表查询】

  • 1>查询用户的订单,没有订单的用户不显示
  • 2>查询所有用户的订单详情
  • 3>查询所有订单的用户详情

2 综合练习2-【子查询】

  • 1>查看用户为张三的订单详情
  • 2>查询出订单的价格大于300的所有用户信息。
  • 3>查询订单价格大于300的订单信息及相关用户的信息。

综合练习3-【分页查询】

  • 1>查询所有订单信息,每页显示5条数据

事务操作之转账案例

/*
事务操作之转账案例--该案例判断是否出问题以及出问题应该调用哪个语句不是自动的,是认为判断并指定处理语句。
MySql数据库中事务默认自动提交:
   *一条DML(增删改)语句会自动提交一次事务。只有提交事务后的数据才会持久化存储,即关闭窗口或者重启窗口后查询仍然是变化后的数据。如果像上面操作是手动开启和提交事务,若手动开启事务但没有手动提交事务,那么事务会默认的自动回滚。
*/

-- 1.下面sql语句实现了张三给李四转账了500元,转账没有问题。

CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    balance DOUBLE
);
-- 添加数据
INSERT INTO account(NAME,balance)VALUES ('zhangsan',1000),('lisi',1000);
SELECT * FROM account;

-- 张三给李四转账500元
-- a.张三账户-500元
UPDATE account SET balance =balance-500 WHERE NAME='zhangsan';
-- b.李四账户+500元
UPDATE account SET balance =balance+500 WHERE NAME='lisi';

-- 2.下面sql语句转账失败,转账有问题,由于'出错了..'不是sql语句,所以执行到这里报错,语句不再执行,
-- 而这时张三已经被扣除500元,但是李四并没有增加500元。转账出现问题。这个时候就需要使用回滚,撤销操作。
-- 转账有问题,回滚
CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    balance DOUBLE
);
-- 添加数据
INSERT INTO account(NAME,balance)VALUES ('zhangsan',1000),('lisi',1000);
SELECT * FROM account;

-- 张三给李四转账500元
-- 0.开启事务
START TRANSACTION;
-- 1.张三账户-500元
UPDATE account SET balance =balance-500 WHERE NAME='zhangsan';
出错了...
-- 2.李四账户+500元
UPDATE account SET balance =balance+500 WHERE NAME='lisi';
-- 发现执行有问题,回滚操作,回滚到开启事务的位置
ROLLBACK;


-- 3.下面sql转账没有问题,启动事务,提交服务

CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20),
    balance DOUBLE
);
-- 添加数据
INSERT INTO account(NAME,balance)VALUES ('zhangsan',1000),('lisi',1000);
SELECT * FROM account;

-- 张三给李四转账500元
-- 0.开启事务
START TRANSACTION;
-- 1.张三账户-500元
UPDATE account SET balance =balance-500 WHERE NAME='zhangsan';
-- 2.李四账户+500元
UPDATE account SET balance =balance+500 WHERE NAME='lisi';
-- 发现执行没有问题,提交事务
commit;

练习

-- 连上student数据库
USE student;
SHOW TABLES;-- 查看该数据库所有表
-- 1. grade 表增加一个阶段,“就业期”
INSERT INTO gradetable(gradeid,gradename) VALUES(5,'就业期');
-- 2.将第三阶段的学生的 gradeid 改为就业期的 id 
UPDATE studenttable SET grade_id=(SELECT gradeid FROM gradetable WHERE gradename='就业期') WHERE grade_id=(SELECT gradeid FROM gradetable WHERE gradename='第三阶段');
-- 3.查询所有得了 100 分的学号 
SELECT studentnum FROM scoretable WHERE score=100;
-- 4.查询所有 1989 年出生的学生(1989-1-1~1990-1-1)
 SELECT * FROM studenttable WHERE birthday BETWEEN '1989-1-1'AND '1990-1-1';
-- 5.查询学生姓名为“金蝶”的全部信息 
SELECT * FROM studenttable WHERE student_name='金蝶';
-- 6.查询 subjectid 为 8 的科目考试未及格(60 分)的学号和成绩 
SELECT studentnum,score FROM scoretable WHERE subjectid=8 AND score<60;
-- 7.查询第 3 阶段课时大于 50 的课程全部信息 
SELECT * FROM subjecttable WHERE subject_time>50 AND gradeid=3;
-- 8.查询 S1101001 学生的考试信息 
SELECT * FROM scoretable WHERE studentnum='S1101001';
-- 9.查询所有第二阶段的女生信息
SELECT * FROM studenttable WHERE sex='女'AND grade_id=(SELECT gradeid FROM gradetable WHERE gradename='第二阶段');
-- 10.“基于.NET 平台的软件系统分层开发”需要多少课时
SELECT subject_time FROM subjecttable WHERE subject_name='基于.NET平台的软件软件系统分层开发';
-- 11.查询“设计 MySchool 数据库”和“面向对象程序设计”的课时(使用 in)
SELECT subject_name,subject_time FROM subjecttable WHERE subject_name IN('设计 MySchool 数据库','面向对象程序设计');
-- 12 查询所有地址在山东的学生信息
SELECT * FROM studenttable WHERE address='山东';
-- 13 查询所有姓凌的单名同学 
SELECT * FROM studenttable WHERE student_name LIKE'凌%';
-- 14.查询 gradeid 为 1 的学生信息,按出生日期升序排序 
SELECT * FROM studenttable WHERE grade_id=1 ORDER BY birthday;
-- 15.查询 subjectid 为 3 的考试的成绩信息,用降序排序 
SELECT score FROM scoretable WHERE subjectid=3 ORDER BY score DESC;
-- 16.查询 gradeid 为 2 的课程中课时最多的课程信息 
SELECT * FROM subjecttable WHERE gradeid=2 AND subject_time=(SELECT MAX(subject_time) FROM subjecttable);
-- 17.查询北京的学生有多少个 
SELECT COUNT(student_num) FROM studenttable WHERE address='北京';
-- 18.查询有多少个科目学时小于 50 
SELECT COUNT(subjectid) FROM subjecttable WHERE subject_time<50;
-- 19.查询 gradeid 为 2 的阶段总课时是多少 
SELECT SUM(subject_time) 总课时 FROM subjecttable WHERE gradeid=2;
-- 20.查询 subjectid 为 8 的课程学生平均分 
SELECT AVG(score) 平均分 FROM scoretable WHERE subjectid=8;
-- 21.查询 gradeid 为 3 的课程中最多的学时和最少的学时 
SELECT MAX(subject_time) 最多课时,MIN(subject_time) 最少课时 FROM subjecttable WHERE gradeid=3;
-- 22.查询每个科目有多少人次考试 
SELECT subjectid,COUNT(scoreid) FROM scoretable GROUP BY subjectid;
-- 23.每个阶段课程的平均课时 
SELECT gradeid,AVG(subject_time) AS 平均课时 FROM subjecttable GROUP BY gradeid;
-- 24.查询每个阶段的男生和女生个数(group by 两列)
SELECT grade_id,sex,COUNT(student_num) 个数 FROM studenttable GROUP BY grade_id, sex;

多表查询


数据表: 

  • 雇员表(employee):雇员编号(empid,主键),姓名(name),性别(sex),年龄(age),职称(title),出生日期 (birthday),所属部门(depid) 
  • 部门(department):部门编号(depid,主键),部门名称(depname) 
  • 工资表(salary):雇员编号(empid),基本工资(basesalary),职务工资(titlesalary),扣除(deduction)
需求:
  • 1. 修改表结构,在部门表中添加部门简介字段
  • 2. 将李四的职称改为“工程师”,并将她的基本工资改成 2000,职务工资为 700
  • 3. 删除人事部门的部门记录
  • 4. 查询出每个雇员的雇员编号,实发工资,应发工资
  • 5. 查询姓张且年龄小于 40 的员工记录
  • 6. 查询雇员的雇员编号,姓名,职称,部门名称,实发工资
  • 7. 查询销售部门的雇员姓名,工资
  • 8. 统计各职称的人数
  • 9. 统计各部门的部门名称,实发工资总和,平均工资
  • 10. 查询比销售部门所有员工基本工资都高的雇员姓名
/*
数据表: 
雇员表(employee):雇员编号(empid,主键),姓名(name),性别(sex),年龄(age),职称(title),
                 出生日期 (birthday),所属部门(depid) 
部门(department):部门编号(depid,主键),部门名称(depname) 
工资表(salary):雇员编号(empid),基本工资(basesalary),职务工资(titlesalary),扣除(deduction)
*/


-- 创建部门表
CREATE TABLE department(
	depid INT PRIMARY KEY,
	depname VARCHAR(10)
);
INSERT INTO department(depid,depname) VALUES(1,'研发部'),(2,'销售部'),(3,'人事部门');

-- 创建雇员表
CREATE TABLE employee(
	empid INT PRIMARY KEY,
	NAME VARCHAR(10),
	sex CHAR(1),
	age INT,
	title VARCHAR(10),
	birthday DATE,
	depid INT,-- 从表外键,指向主表department主键depid
	CONSTRAINT emp_dep_fk FOREIGN KEY (depid) REFERENCES department(depid) 	 
);
INSERT INTO employee VALUES(1,'熊大','男',33,'部门经理','2021-02-21',1);
INSERT INTO employee VALUES(2,'熊二','男',28,'程序员','2021-02-21',1);
INSERT INTO employee VALUES(3,'熊三','男',25,'产品经理','2021-02-21',2);
INSERT INTO employee VALUES(4,'李四','女',29,'运营经理','2021-02-21',2);
INSERT INTO employee VALUES(5,'张三','女',23,'运营经理','2021-02-21',2);


-- 创建工资表
CREATE TABLE salary(
	empid INT,
	basesalary INT,
	titlesalary INT,
	deduction INT
);
INSERT INTO salary VALUES(1,15000,15000,5000);
INSERT INTO salary VALUES(2,10000,6000,4000);
INSERT INTO salary VALUES(3,9000,6000,3000);
INSERT INTO salary VALUES(4,8000,5000,4000);
INSERT INTO salary VALUES(5,8000,5000,4000);

-- 需求: 
-- 1. 修改表结构,在部门表中添加部门简介字段 
ALTER TABLE department ADD depintroduce VARCHAR(150);
-- 2. 将李四的职称改为“工程师”,并将她的基本工资改成 2000,职务工资为 700 
UPDATE employee e,salary s SET title='工程师',basesalary=2000,titlesalary=700 WHERE e.`empid`='李四' AND s.`empid`='李四';
-- 3. 删除人事部门的部门记录 
DELETE FROM department WHERE depname='人事部门';
-- 4. 查询出每个雇员的雇员编号,实发工资,应发工资 
SELECT employee.empid,basesalary+titlesalary 应发工资,basesalary+titlesalary-deduction 实发工资 FROM salary;
-- 5. 查询姓张且年龄小于 40 的员工记录 
SELECT * FROM employee WHERE NAME LIKE '张%' AND age<40;
-- 6. 查询雇员的雇员编号,姓名,职称,部门名称,实发工资 
SELECT employee.`depid`,NAME,title,depname,basesalary+titlesalary-deduction 实发工资 FROM employee,department,salary WHERE employee.`depid`=department.`depid`AND employee.`empid`=salary.`empid`;
-- 7. 查询销售部门的雇员姓名,工资 
SELECT NAME,basesalary+titlesalary-deduction 实发工资 FROM employee,department,salary WHERE employee.`depid`=department.`depid`AND depname='销售部'AND employee.`empid`=salary.`empid`;
-- 8. 统计各职称的人数 
SELECT title,COUNT(empid) FROM employee GROUP BY title; 
-- 9. 统计各部门的部门名称,实发工资总和,平均工资 
SELECT d.depname,SUM(basesalary+titlesalary-deduction)实发工资总和,AVG(basesalary+titlesalary-deduction)平均工资 
FROM department d LEFT JOIN employee e
ON d.depid=e.depid LEFT JOIN salary s ON s.empid=e.empid
GROUP BY d.depid;
-- 10. 查询比销售部门所有员工基本工资都高的雇员姓名
SELECT NAME 
FROM employee,salary 
WHERE employee.`empid`=salary.`empid` AND basesalary>(
	SELECT MAX(basesalary) 销售部最大基本工资 
	FROM salary,employee,department 
	WHERE salary.`empid`=employee.`empid`AND employee.`depid`=department.`depid`AND department.`depname`='销售部'
	);

MySQL数据库的安装以及SQL增删改查语句

https://blog.csdn.net/qq_40454863/article/details/113809607

数据库的设计、表的约束(完整性)、多表设计与查询

https://blog.csdn.net/qq_40454863/article/details/114067770

MySQL高级使用--事务详解

https://blog.csdn.net/qq_40454863/article/details/113899837

JDBC【知识点整理】

https://blog.csdn.net/qq_40454863/article/details/113963196

  • 10
    点赞
  • 69
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值