DB:数据库
DBMS:数据库管理系统(软件)
SQL:用于 DB 和 DBMS 通信的语言(此为通用语言)这里主要学习 MySQL 数据库
1.开源免费
2.性能高
3.简单
4.可移植性好(可在windows,linux下运行)数据库是一个柜子
柜子里放了多张表格字段: 每行表格的 每类
属性: 每竖DBMS在非共享状态下需要安装 客户端 与 服务端卸载 MySQL 除 程序 卸载 之外
还需要找到安装路径 删除整个文件夹
还需找到 c盘 根目录 隐藏文件夹 ProgramData
里面还有一个 MySQL文件夹 删除它如果你重新安装依然有问题 使用360  粉碎
清理注册表登录时的账户密码
root 密码 1234启动数据库软件服务
计算机 右键 管理 服务 服务
找到mysql0815
右键 启停
属性 修改手启 自启或
以管理员 进入 命令提示符
net stop mysql0815 停止名字为mysql0815的服务
net start mysql0815 启动名字为mysql0815的服务登录方式1(开始 mysql 自带的黑窗口 )直接输入 root账户 之前设置的 密码 1234退出登录
exit   回车即可
或
Ctrl + c 退出(只限于root用户)登录方式2(windows原本的命令提示符)
mysql -h localhost -P 3306 -u root -p-host 本地 -port端口号 用户名 密码回车 会提示输入密码1234 输入即可或
mysql -h localhost -P 3306 -u root -p1234
执行结果是一样的
此时密码为显示状态
前一种只显示****也可以 这样写
mysql -hlocalhost -P3306 -uroot -p1234默认连接本地 3306 端口 默认可省略 -hlocalhost -P3306
mysql -uroot -p1234登录后
继续输入
即为 SQL 语言
show databases;    查看所有数据库 ; 可换为 /g 推荐 ;会展示4个数据库
Database 头
1.information_schema    保存 元数据
2.mysql                 保存 管理员信息
3.performance_schema    搜集的一些性能信息参数
4.test                  测试用的(为空)use test; 进入某个数据库库名
show tables; 展示某个库的所有表格信息身处当前数据库(术语) 想看其它数据库(术语)时
并不会改变身处位置
show tables from mysql; 展示其它库存在的所有表格信息
展示 表格(术语)  库名select database(); 身处何处create table stuinfo(   在当前位置建表
新建    表格  名字称为stuinfo回车 继续输入 表头 和 表头这一列数据类型
id int,
表头 数值回车
继续追加 列
name varchar(20));
表头  字符串     分号代表此次sql命令结束desc stuinfo;  查看 表格属性 查询 显示表结构
进入 表格名字select * from stuinfo; 展示表格(术语)要展示的表格名字insert into stuinfo (id,name) values(1,'john'); 编辑表格(术语) 插入要编辑的表格名字 里面的两列 表头的值(其中之一行)insert into stuinfo (id,name) values(2,'rose'); 再来一行id name
1  john
2  rose断电重启 此数据库(术语)依然存在update stuinfo set name='lilei' where id=1;
将当前所处位置(test数据库(术语)中)stuinfo 表格(术语)中id为 1 的 name 修改为 lileiid name
1  lilei
2  rosedelete from stuinfo where id=1;
将当前所处位置(test数据库(术语)中)
stuinfo 表格(术语)中id为 1 的 那一行 删除id name
2  rose查看 版本号
select version();
或
在非登录状态下 原本命令行窗口下
mysql --version
mysql -V         简写SQL 命令语法规范
1. 实际上不区分大小写2.       ; 或 /g 结尾 推荐;3.     不写结尾 即使回车 也只是换行了 并没有执行
4.注释 单行:#注释文字   或-- 注释文字多行: /* 注释 */     和js一样f9 运行
SHOW DATABASES;  要分号
USE test         不能写分号DQL 查询    相关操作
DML 增删改  相关操作
DDL 创建/删除 库/表
TCL 事物控制DCL 数据控制语言#进阶1: 基础查询
/*
语法:
select 查询列表 from 表名;类似于:system.out.println(打印东西);特点:1.查询列表可以是 多个/一个:表中的字段, 常量,表达式,函数
2.查询的结果是一个虚拟的表格
*/
USE `myemployees` #1.查询表中的单个字段
SELECT last_name
FROMemployees ;#查询 last_name 从 employees 数据库(术语)
#2.查询表中的多个字段
SELECT last_name,salary,email
FROMemployees ;#3.查询表中的所有字段
SELECT `hiredate`,`department_id`,`manager_id`,`commission_pct`,`salary`,`job_id`,`phone_number`,`email`,`last_name`,`first_name`,`employee_id`
FROM`employees`  ;#方式二:
SELECT *
FROMemployees ;#4.查询常量值 查看 打印
SELECT 100;
SELECT 'john';
#后面不加 from 表名 你要加也不报错 只不过没什么意义(只不过表有多少行 显示多少结果  不加只显示一种结果)#注意:字符型和日期型的常量值必须用引号,数值型不需要引号#5.查询表达式
SELECT 100%98;
支持 + - * / %(取模)
不支持 ++ -- *=#6.查询函数SELECT VERSION();mysql的函数调用前面必须加 select
而且mysql函数的调用是必须有返回值的# select 解释为查看更为具体#7.起别名(as 和 空格(相当于省略了as))
/*
显示自定义 替换原本表头的名字
*/
#方式一:
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名
FROMemployees ;#方式二:
SELECT 100%98 结果;
SELECT last_name 姓,first_name 名
FROMemployees ;#案例:查询salary,显示结果为 out put
SELECT salary AS 'out put'
FROMemployees ;#8.去重 DISTINCT (一次查询(SELECT )同时只可去一个重(去多个重 出来的结果 使表不规则 从道理上就说不通))#案例:查询员工表中涉及到的所有的部门编号`department_id`
SELECT DISTINCT department_id
FROMemployees ;#9.   + 号仅有 加法 运算功能 SELECT 100+90 ;
# 190SELECT '123' + 90 ;
#213 (会试图将字符转换为数值)SELECT 'john' + 90 ;
#   0(转换失败)+90  90SELECT NULL + 90 ;
# 有 null 为 null
#即使在下列表头合并 CONCAT(中有null) 也会全部为null#10. 表头拼接 合并表头
#案例:查询员工名和姓,连接成一个字段,并显示为 姓名
如果字段为数值型 会转换成 字符型
SELECT CONCAT(`last_name`,`first_name`,IFNULL(`commission_pct`, 0)) AS 姓名
FROMemployees ;#11. ifnull(可能为null的表头,为null时返回这里)
select ifnull(commission_pct,0) from employees;
判断某字段 或 表达式是否为null
如果为null 返回指定的值 否则返回原本的值#12.[补充] isnull 函数(判断某字段或表达式是否为null.如果是查询结果1,否则为0)
select isnull(commission_pct) from employees;
如果commission_pct  为null  isnull(commission_pct)结果为1(true 真)
如果commission_pct不为null  isnull(commission_pct)结果为0(false假)进阶条件查询 2#进阶2:条件查询
/*
语法 :select 查询列表(第2步)from 表名(第1步)where(子句)筛选条件;(第3步)分类:一.按条件表达式筛选简单的条件运算符: > < = >= <=  !=或<><=>安全等于即使判断目标null也不会报错二.按逻辑表达式筛选逻辑运算符:作用:用于连接条件表达式&&  ||  !或 and  or  not三.模糊查询like:一般搭配通配符使用,用于判断 字符/数值 型数值
SELECT *
FROMemployees
WHERE department_id like '1__';#展示表头为 department_id  1某某 的查询结果通配符:%任意多个字符,_任意单个字符between and    提高语言简洁度与可读性 in             提高语言简洁度与可读性 is null    / is not null  用于判断null值is null 不能判断普通类型的数值 只能判断null值 可读性高<=>       能判断普通类型的数值   能判断null值 可读性较差
*/
#一.按条件表达式筛选
#案例1:查询工资>12000的员工信息
SELECT *
FROMemployees
WHERE salary > 12000 ;#案例2:查询部门编号不等于90号的员工名和部门编号
SELECT last_name,department_id
FROMemployees
WHERE department_id <> 90 ;
#where department_id != 90 ;#二.按逻辑表达式筛选
#案例1:查询工资在10000到20000之间的员工名.工资以及奖金
SELECT last_name,salary,commission_pct
FROMemployees
WHERE salary >= 10000 AND salary <= 20000 ;#案例2:查询部门编号不在90到110之间,或者工资高于15000的员工信息
#编号大于110 或 小于90 或 工资大于 15000
# not 是 非 也就是 !
SELECT *
FROMemployees
WHERE NOT (department_id >= 90 AND department_id <= 110) #不等于 90到110这个区间OR salary > 15000 ;SELECT *
FROMemployees
WHERE department_id < 90 OR department_id > 110 OR salary > 15000 ;/*
like
特点:1.一般和通配符搭配使用通配符:% 任意多个字符,包含0个字符_ 热议单个字符between and
in
is null | is not null
*/
#1.like
#案例1:查询员工名中包含字符a的员工信息
SELECT *
FROMemployees
WHERE last_name LIKE '%a%' ;#字符串必须用单引号 %代表a前后还有东西的通配符
#二.案例2:查询员工名中第三个字符为e的,第5个字符为a的员工名和工资
SELECT last_name,salary
FROMemployees
WHERE last_name LIKE '__n_l%' ;#第三个n 5为l
#案例3:查询员工名第二个字符为_的员工名
SELECT last_name
FROMemployees
WHERE last_name LIKE '_$_%' ESCAPE '$' ;
#指定$(可任意) 为转义字符
#where last_name like '_\_%'; #自带转义\ _  #2.between and 在...之内(包括自己且必须前者小后者大)/*
1.使用我们的between and 可以提高语句的简洁度
2.包含临界值
3.两个临界值不要调换顺序 必须前者小后者大
*/
#1.查询员工编号100到120之间的员工信息
SELECT *
FROMemployees
WHERE employee_id BETWEEN 100 AND 120 ;#where employee_id >= 100
#and employee_id <= 120 ;
#3.=表头 in(表头其中一个内容,表头其中一个内容,表头其中一个内容 )
/*
含义 : 用于判断某字段的值是否属于in列表中的某一项
特点:1.使用in提高语言简洁度2.in列表的值类型必须一致或兼容3.不能使用通配符 in是等于号判断
*/#案例: 查询员工的工种名是 IT_PROG,AD_VP,AD_PRES 中的一个员工名和工种编号
SELECT last_name,job_id
FROMemployees
WHERE job_id = 'IT_PROG' OR job_id = 'AD_VP' OR job_id = 'AD_PRES' ;
#------------------------------------
SELECT last_name,job_id
FROMemployees
WHERE job_id IN ('IT_PROG', 'AD_VP', 'AD_PRES') ;#4.is null
/*
不能使用 =  <> 识别 null
必须使用专门的 is null或 is not null 判断 值(可能含null)
不可使用 salary is 12000
但可使用 <=> 安全等于
*/
#案例1:查询没有奖金的员工名和奖金率
#             为null
#IS NULL  代替 = 判断是否 为null
#IS NOT NULL 代替 != 判断是否 不为null
SELECT last_name,commission_pct
FROMemployees
WHERE commission_pct IS NOT NULL ;#安全等于  <=>  是否等于如果等于返回true
#案例1:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct
FROMemployees
WHERE commission_pct <=> NULL ;#案例2:查询工资为12000的员工信息
SELECT last_name,salary
FROMemployees
WHERE salary <=> 12000 ;#和等于没什么区别
/*
is null 与 <=> 真的一样吗
is null:仅仅可以判断null值
<=> :既可以判断null值,又可以判断普通的数值
*/
#题目 查询员工号为176的员工的姓名,部门号与年薪
/*月薪*12月+年终奖(0.几*年薪) 别名 查询结果的as  别名 ifnull  为null时为其显示0不报错commission_pct 年终奖 0.几 实际值为 年薪*0.几last_name 姓名department_id 编号salary 月薪*/
SELECT last_name,department_id,salary * 12 * (1+ IFNULL(commission_pct, 0)) AS 年薪
FROMemployees ;#题目 查询没有奖金,且工资小于18000的salary,last_name
# commission_pct IS NULL且 AND salary < 18000
SELECT salary,last_name
FROMemployees
WHERE commission_pct IS NULL AND salary < 18000 ;#题目 查询employees表中,job_id 不为'IT'或者工资为12000的员工信息
SELECT *
FROMemployees
WHERE job_id <> 'IT'
#WHERE job_id != 'IT' OR salary = 12000 ;#题目 查看部门 departments 表的结构,查询效果如下
DESC departments ;#题目 查询部门 departments 表中涉及到了哪些 location_id 位置编号
# DISTINCT 去重
SELECT DISTINCT location_id
FROMdepartments ;#题目 理解问题
/*
请问:
select * from employees 与
select * from employees where commission_pct like '%%' and last_name like '%%'
结果是否一样不一样
由于 commission_pct(奖金)有的没有奖金为null如果判断的字段有null的情况
第一种 commission_pct 会显示为  null 的结果
第二种 commission_pct 不会显示为 null 的结果如果判断的字段没有null值 两者一样
都不会显示为 null 的结果所以结果不一样
*/
SELECT # 第一种 commission_pct 有  null*
FROMemployees ;SELECT #第二种 commission_pct 没有 null*
FROMemployees
WHERE commission_pct LIKE '%%' AND last_name LIKE '%%' ;/*
但是将
select * from employees where commission_pct like '%%' and last_name like '%%'
更改为
select * from employees where commission_pct like '%%' or last_name like '%%'
后面继续写满 employees 表所有标题
这里省略
这个时候
结果 就一样了
都会显示为  null 的结果这样看来 null 代表为空 and/&& 也就是false 是不显示的
但是 || / or 为false 的 null 也是null 是会显示的
*//*
总结:
1.数据库的好处1.可以持久化数据到本地2.结构化查询2.数据库的常见概念 (较为重要)1.DB: 按照一定规定排列的表格所组成的数据库(容器/大仓库)2.DBMS: 数据库管理 软件(系统)3.SQL: 上面两者之间的 通信的一种通用语言(结构化查询语言)3.数据库存储数据的特点 1.数据存放到表中,表再存放到库中2.一个库中可以有多张表,每张表具有唯一的表名(废话)3.表中有一个或者多个列,列又称为'字段',相当于js中的'属性'4.表中的每一行数据,相当于js中的一个对象4.常见的数据库
mysql(oracle公司) ,
oracle(oracle公司) ,
db2(IBM公司) ,
sqlserver(微软公司) ,
*/一.mysql的背景,优点,安装,服务的启动/停止,登录/退出mysql安装后 属于C/S架构 既有服务端 也有客户端
一般来讲安装服务端 安装路径 非中文 没有空格企业版 社区版 5.5,  5.6,  5.7,   8.0(beta测试版)#进阶3: 排序查询
/*
引入:
SELECT *
FROMemployees ;语法:select 查询列表(表头)        (第三步)from 表(大表)                (第一步)[where 筛选条件]             (第二步)order by 排序列表 [asc|desc] (第四步)升序|降序特点:1.asc代表的是升序,desc代表降序如果不写默认是升序2.order by 子句中可以支持单个字段,多个字段,表达式,函数,别名3.order by子句一般是放在查询语句的最后面,limit子句除外
*/
#案例1: 查询员工信息,要求工资从高到低排序
SELECT *
FROMemployees
ORDER BY salary DESC ;
#降序 DESCSELECT *
FROMemployees
ORDER BY salary ;
#ORDER BY salary asc ;
#升序 asc 升序可省略不写 默认升序排序
#案例2:查询(department_id)部门编号>=90的员工信息 ,按(hiredate)入职先后进行排序[添加筛选条件]
SELECT *
FROMemployees
WHERE department_id >= 90
ORDER BY hiredate ;
#ORDER BY hiredate asc;
#升序 asc 升序可省略不写 默认升序排序
/*
案例3: 按年薪的高低显示员工的(*)信息和年薪[按表达式排序]
(salary*12*(1+commission_pct))年薪 月薪*12(1+年终奖(年薪的0.几))
(commission_pct)年终奖  有的员工无年终奖 数值为 null
(salary*12*(1+ifnull (commission_pct,0))) 年薪
ifnull(可能为null的值,代替null的值)
*/
SELECT *,salary * 12 * (1+ IFNULL(commission_pct, 0))
FROMemployees
ORDER BY salary * 12 * (1+ IFNULL(commission_pct, 0)) DESC ;
#         表达式为结果的                              降序#表达式太长 我们试试按别名排序 表头后+ as 或 空格 +你取的别名
#案例3: 按年薪的高低显示员工的(*)信息和年薪[按别名排序]
#所谓别名 就是给表头重命名 不是其它地方 请注意
#别名亦是变量 可以用来给  ORDER BY 排序
SELECT *,salary * 12 * (1+ IFNULL(commission_pct, 0)) 年薪
FROMemployees
ORDER BY 年薪 DESC ;#降序#案例:查询 根据(last_name)姓名字节长度进行排序,显示员工的姓名和工资
#姓名的长度 用到一个函数 length(表头) 查询结果为表头的长度
#所以实际上是[按函数排序]SELECT LENGTH(last_name) 字节长度,last_name,salary
FROMemployees
ORDER BY 字节长度 DESC ;#降序
/*
最后一个案例6:查询(*)员工信息,要求先按(salary)工资(asc)升序,再按(employee_id)员工编号(desc)降序
前面都只有 一项 排序
这次既有工资升序 又有编号降序 两项排序
先按 工资升序 工资相同的 再按 编号降序
假设工资相同 编号采用降序(不写降序,默认随机排列)
后面还可以接多个
*/
SELECT *
FROMemployees
ORDER BY salary ASC,#升序employee_id DESC ;#降序
/*
1.题目:查询员工的(last_name)姓名和(department_id)部门号和年薪,按年薪降序,按姓名升序
(salary*12*(1+ifnull (commission_pct,0))) 年薪
*/
SELECT last_name,department_id,salary * 12 * (1+ IFNULL(commission_pct, 0)) 年薪
FROMemployees
ORDER BY 年薪 DESC,#降序last_name ASC ;
#升序
#年薪按降序派 年薪相同按 姓名 升序排
/*
2.题目选择工资不在8000到17000的员工的(last_name)姓名和(salary)工资,按工资降序
*/
SELECT last_name,salary
FROMemployees
WHERE salary NOT BETWEEN 8000 AND 17000 #where salary<=8000 and salary>=17000
ORDER BY salary DESC ;#降序 4个字母升序 3个字母 升3降4
#3.查询(email)邮箱中包含e的员工信息,并先按邮箱的字节数降序,再按(department_id)部门号升序
#字节数 length()
SELECT *
FROMemployees
WHERE email LIKE '%e%'
ORDER BY LENGTH(email) DESC,# 降 邮箱字节数(长度)department_id ASC ;#升  部门号#进阶4:常见函数
/*
概念:类似于js的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1.隐藏了实现细节 2.提高代码的重用性
调用: select 函数(实参列表(表头)) [from 表](有就有,不从这获取数据可以不写);
特点: 1.叫什么 (函数名)2.干什么 (函数功能)分类:1.单行函数(肯定会有返回值(查询结果))如 concat(表头拼接),length(长度),ifnull(判断,替换null)字符函数  ;传入字符型 并处理数学函数   :传入数值型 并处理日期函数     :传入日期型 并处理其它函数[补充]  :稍后补充流程控制函数[补充]  :可以实现一些分支结构类似 if else,while case循环语句2.分组函数功能:做统计使用(又称为 统计/聚合/组 函数)*单行函数传一个值返回一个值 *多行函数传一组值返回一个值常见函数:字符函数:length 获得字节(当前版本utf8下汉字=3字节)长度concat字符拼接substr 截取字符串instr(母串,子串) 返回子串在母串第一次出现的起始索引,如果找不到返回0trim 去空格upper 变大写lower 变小写lpad  左填充rpad  右填充replace 替换数学函数:round 四舍五入ceil 向上取整floor 向下取整truncate 保留小数点后几位mod 取模补充 rand :获得随机数,反回0-1(不包括1)之间的小数日期函数now 获得现在时间curdate 获取现在日期 不包含时间curtime 获取现在时间 不包含日期year 获取now的年 month  获取now的月monthname 以英文形式反回月day 获取now的日hour 小时minute 分钟second 秒str_to_data 将字符串按格式转换成日期date_format 将日期格式转换成字符串datediff 反回两个日期相差的天数其它函数:version 当前数据库服务器的版本database 当前打开的数据库user 当前登录使用mysql的用户password('字符') 反回该字符的密码形式 自动加密select password('张三') 张三会变成一堆字符串select md5('张三') 张三也会变成一堆字符串控制函数if (条件表达式,表达式1,表达式2)意思是:如果条件表达式成立,反回表达式1,否则返回表达式2case情况1case 变量/表达式/字段(表头)when 常量1 then 值1 when 常量2 then 值2...else 值nendcase情况2case when 条件1 then 值1 when 条件2 then 值2...else 值nend*/
#一. 字符函数
#1.length  获取参数的字节个数
SELECT LENGTH('haha') ;
#查询结果 haha的长度为 4
SELECT LENGTH('张三丰hahaha') ;#查询结果 张三丰hahaha 的长度为 15
#一个汉字占三个字节
SHOW VARIABLES LIKE '%char%' ;#character_set_client 的字符集(格式)为 utf8
#在utf8下 一个英文字母占一个字节 一个汉字占3个字节
#在gbk 下 一个汉字占两个字节#2.concat 拼接字符串
SELECT CONCAT(last_name, '_', first_name) 姓和名
FROMemployees ;#3.upper,lower
SELECT UPPER('john');#转换为大写
SELECT LOWER('john');#转换为小写(本身小写不变 有大有小全变小)
#示例:将姓变大写,名变小写,然后拼接
SELECT CONCAT(UPPER(last_name), LOWER(first_name)) 姓名
FROMemployees ;
#我们发现 函数可以嵌套函数 (我从 ifnull()就发现啦)#4.substr/substring ,截取字字(非字节(在utf8下 汉字=3个英文字母字节))
#注意:整个sql中索引都是从1开始的
SELECT SUBSTR('我在学习mysql', 7) 看截取的第几位 ;#截取 第7位后(包括7)所有字符   sqlSELECT SUBSTR('我在学习mysql', 2,4) 看截取的第几位 ;
#截取从指定索引处指定字符长度的字符 结果 在学习m (非字节(在utf8下 汉字=3个英文字母字节))#案例:姓名中首字符大写,其它字符小写然后用_拼接 W_ang
#SUBSTR(last_name,1,1) 首字符
#CONCAT(要拼接的字符串,要拼接的字符串)
#SUBSTR(last_name,2)首字母后面的所有字符
#upper(要大写的字符)
#lower(要小写的字符)
#select 表达式/表头+空格/as+别名 取别名
SELECT CONCAT(UPPER(SUBSTR(last_name, 1, 1)),'_',LOWER(SUBSTR(last_name, 2))) 姓
FROMemployees ;#5.instr()返回子串第一次出现的起始索引,如果找不到返回0
SELECT INSTR('我在mysql学习mysql','mysql') AS 输出内容 ;#执行结果 5 '我在学习mysql'第5个字符处 是 'mysql'
#6.trim 去除左右两边空格/指定字符串
#length(返回字节数 字节(在utf8下 汉字=3个英文字母字节))
SELECT LENGTH(TRIM('   我在学习mysql   ')) AS 输出内容 ;
# 执行结果 3+3+3+3+1+1+1+1+1=3*4+1*5=17 不含空格
SELECT LENGTH(TRIM('a' FROM 'aaaa我在学习mysqlaaaa'#'aa' 时可能会出现 单数 剩下一个a的情况)) AS 输出内容 ;
# 执行结果 3+3+3+3+1+1+1+1+1=3*4+1*5=17 不含'a'#7.lpad 用指定的字符实现左填充指定长度(为数值2时显示 my 有截断的功能)
SELECT LPAD('mysql',10,'*') AS 输出内容;
#执行结果 *****mysql#8.rpad 用指定的字符实现右填充指定长度(为数值2时还是显示 my 有截断的功能)
SELECT RPAD('mysql',10,'ab') AS 输出内容;
#执行结果 mysqlababa#9.replace 替换
SELECT REPLACE('jsjsjs我在学习js', 'js', 'mysql') AS 输出内容 ;
#执行结果 mysqlmysqlmysql我在学习mysql#二.数学函数#round 四舍五入
SELECT ROUND(1.65);#执行结果 2
SELECT ROUND(1.45);#执行结果 1
/*
注: 这里的四舍五入 是 保留整数
所以小数后一位(后两位三位与这次计算无关) >=5 进1 <5舍去
所以 1.45 是 1 而不是 2 保留1位小数那也是 1.5
如果先保留一位小数 再保留整数进行两次四舍五入 就有可能是2
*/SELECT ROUND(1.567,2);#执行结果 1.57
#小数点后保留 2位 的 四舍五入#ceil(释义:屋顶) 向上取整,返回>=该参数的最小整数
SELECT CEIL(1.002);#执行结果 2
SELECT CEIL(-1.002);#执行结果 -1#floor(释义:地板) 向下取整 返回<=该参数的最大整数
SELECT FLOOR(9.99);#执行结果 9
SELECT FLOOR(-9.99);#执行结果 -10
/*
2    ↑
1   往上
0        大小
-1  往下
-2   ↓*/#truncate 保留小数点后几位SELECT TRUNCATE(1.65,1);#保留小数点后一位 1.6#mod(a,b)取余/取模(%)  a-a/b*b
/*
除号 / 两边如果都是整数 取整
假设 a为10 b为3  10/3 就是3 而不是3.3333
3*b=3*3=9
a-9=10-9=1*/
SELECT MOD(10,3);#10/3 取余为 1
SELECT 10%3;# 和上面结果是一样的SELECT MOD(-10,-3);#-1
/*a-a/b*b
-10-(-10)/(-3)*(-3)
(-10)/(-3) 取整 为3 而不是 3.33
因此
-10-3*(-3)
-10+9
-1
*/SELECT MOD(10,-3);# 1
SELECT MOD(-10,3);#-1#三.日期函数
#now 返回当前系统日期+时间
SELECT NOW();# 当前 年-月-日 时-分-秒#curdate 返回当前系统日期,不包含时间
SELECT CURDATE();# 当前 年-月-日#curtime 返回当前系统时间 不包含日期
SELECT CURTIME();# 当前 时-分-秒#可以获取指定的部分,年-月-日 时-分-秒
SELECT YEAR(NOW() ) 年;#执行结果 2021
SELECT YEAR('1998-1-1') 年;#执行结果 1998SELECT YEAR(hiredate) 年#hiredate 员工的入职时间 年-月-日 时-分-秒
FROM employees;SELECT MONTH(NOW() ) 年;#执行结果 2(代表月)
SELECT MONTHNAME(NOW() ) 年;#执行结果 February 英文版2(代表月)/*
str_to_date 将日期格式的字符 转换成指定格式的日期
str_to_date('9-13-1999','%m-%d-%Y')date_format:将日期转换成字符
date_format('2018/6/6','%Y年%m月%d日')%Y 四位年份 2018
%y 两位的年份 18
%m 月份(双)    01,02,...12
%c 月份      1,2,...12
%d 日        01,02,...12,...
%H 小时      24小时制
%h 小时      12小时制
%i 分钟      00,01,...59
%s 秒          00,01,...59*/
#str_to_date 将日期格式的字符 转换成指定格式的日期
#str_to_date('9-13-1999','%m-%d-%Y')
SELECT STR_TO_DATE('1998-3-2','%Y-%m-%d');
#执行结果 1998-03-02
#查询(hiredate)入职日期为1992-4-3的员工信息
SELECT *
FROMemployees
WHERE hiredate = '1992-4-3' ;
#如果获得的字符串 时间颠倒 就需要进行
# STR_TO_DATE 转换
SELECT *
FROMemployees
WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y') ;
#注: 可以顺序颠倒#date_format:将日期转换成字符  与上面的STR_TO_DATE相反
#date_format('2018/6/6','%Y年%m月%d日')
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS 输出日期;
#执行结果 21年02月24日
#查询(is not null)有(commission_pct)奖金的(last_name)员工名和(hiredate)入职日期(xx月/xx日 xx年)
#DATE_FORMAT(日期,要转换的字符串格式(结果是字符串))
#STR_TO_DATE(日期,重排日期(结果非字符串)的顺序)
SELECT last_name,DATE_FORMAT(hiredate, '%m月/%d日 %y年') 入职日期
FROMemployees
WHERE commission_pct IS NOT NULL ;#四. 其它函数
SELECT VERSION();#版本号
SELECT DATABASE();#查看当前的数据库当前数据库 一般指一个
SELECT USER();#查询当前使用mysql服务器所登录的账户# 五. 流程控制函数
#1.if函数:  if else 的效果
SELECT IF(10<5,'大','小');
#   ture/false true,false
#(last_name)员工名有(commission_pct)奖金 提示(IS NULL)有(返回1true) 没有(返回0false)奖金提示没有
SELECT last_name,commission_pct,IF(# if前有逗号 因为它是查询表达式commission_pct IS NULL,'true 有null没奖金','false没null有奖金') 是否有奖金
FROMemployees ;#2.case函数 的使用一:switch case 的效果
/*
java 中 这样写 case函数
switch(变量或表达式){case 常量1: 语句1;break;...default:语句n;break;}mysql 中 这样写 case函数case 要判断的字段或表达式when 常量1 then 要显示的值1或语句1;when 常量2 then 要显示的值2或语句2;...else 要显示的值n或语句n;end
}
*/
#案例 : 查询员工的(salary)工资,要求
#(department_id)部门号=30, 显示工资为1.1倍
#部门号=40, 显示工资为1.2倍
#部门号=50, 显示工资为1.3倍
#语句不能 接在select 查询 后面 所以此处暂用 显示的值
#后期通过学习 可以把整个case跟在 select 后面
#
SELECT salary 原始工资,department_id,CASEdepartment_id WHEN 30 THEN salary * 1.1 WHEN 40 THEN salary * 1.2 WHEN 50 THEN salary * 1.3 ELSE salary END AS 新工资 #as 别名
FROMemployees ;#3.case 函数的使用二:类似于 多重if
/*
java中:if 条件判断的写法if(条件1){语句1;
}else if(条件2){语句2;
}
...
else{语句n;
}mysql 中:case
when 条件1 then 要显示的值1或语句1(如果是语句要加 ;后期会说到注意点)
when 条件2 then 要显示的值2或语句2
...
else 要显示的值n 或语句n
end
*/
# 案例: 查询员工的工资的情况
#如果工资>20000,显示A级别
#如果工资>15000,显示B级别
#如果工资>10000,显示C级别
#否则           显示D级别
SELECT salary,CASEWHEN salary > 20000 THEN 'A' WHEN salary > 15000 THEN 'B' WHEN salary > 10000 THEN 'C' ELSE 'C' END 工资情况#因为此处case作为查询表达式出现所以要加 , 且尽量取别名
FROMemployees ;###################################################################题目1.显示系统时间(注:日期+时间)
SELECT NOW();#题目2. 查询员(employee_id )工号,(last_name)姓名,(salary)工资,以及工资提高百分之20%后的结果(new salary)
#
SELECT employee_id,last_name,salary,salary * 1.2 'new salary' #别名中有空格使用双引号
FROMemployees ;#题目3.将员工的(last_name)姓名按SUBSTR(last_name,1,1)首字母(ORDER BY )排序,并写出姓名的(LENGTH(last_name))长度
SELECT LENGTH(last_name) 长度,SUBSTR(last_name, 1, 1) 首字符,last_name
FROMemployees
ORDER BY 首字符 DESC ;
#按 last_name 的首字母排序 其实和 按 last_name 排序是差不多的
#差别主要体现在 按 last_name 排序 时 首字母相同 会按第二个字母进行排序
#不写默认升序排序 asc 升(3字母)  desc 降(4字母)
#题目4. 做一个查询,产生下面的结果
/*
<last_name>earns<salary> monthly but wants <salary*3>
示例结果:
别名表头 Dream Salary(释义:梦想工资)
内容拼接的 King earns 24000 monthly but wants 72000
*/
SELECT CONCAT(last_name,'earns',salary,'monthly but wants',salary * 3) AS "Dream Salary"
FROMemployees
WHERE salary = 24000 ;#条目太多 加个筛选条件
#题目5. 使用case-when,按照下面的条件
/*job        gradeAD_PRES    AST_MAN     BIT_PROG    CSA_REP     DST_CLERK   E产生下面的结果Last_name  Job_id  Gradeking       AD_PRES   A*/
SELECT last_name,job_id,CASEjob_id WHEN 'AD_PRES' THEN 'A' WHEN 'ST_MAN' THEN 'B' WHEN 'IT_PROG' THEN 'C' WHEN 'SA_REP' THEN 'D' WHEN 'ST_CLERK' THEN 'E' END AS Grade
FROMemployees
WHERE job_id = 'AD_PRES' ;# 二.分组函数
/*
功能:用做统计使用,
又称为聚合函数或统计函数或组函数
(传一组值 拿到的是一个值)分类:
sum 求和.avg 平均值,max最大值 , min最小值,count计算个数
*/
#1,简单 的使用
SELECT SUM(salary) #这会计算表头salary(工资)下所有的值的总和
FROMemployees ;SELECT AVG(salary) #这会计算表头salary(工资)下所有的值中的平均值
FROMemployees ;SELECT MIN(salary) #这会计算表头salary(工资)下所有的值的最小值
FROMemployees ;SELECT MAX(salary) #这会计算表头salary(工资)下所有的值的最大值
FROMemployees ;SELECT COUNT(salary) #这会计算表头salary(工资)下一共有几个值
FROMemployees ;SELECT SUM(salary) 求和, #只支持 number ROUND(AVG(salary), 2) 平均,#只支持 number #平均值有小数点 使用(ROUND)保留两位小数MAX(salary) 最大值,MIN(salary) 最小值,COUNT(salary) 总个数 #(非空(非null)的值的个数)
FROMemployees ;#2.分组函数 特点
#参数支持哪些类型
/*
1.sum.avg一般用于处理数值型max,min,count可以处理任何类型2.以上分组函数全部忽略(不计算)null值
sum ,COUNT,AVG,MAX,MIN3.可以和(distinct)去重 搭配实现去重的运算*/
SELECT SUM(DISTINCT salary),#去重求和SUM(salary),#普通求和COUNT(DISTINCT salary) #去重累计个数 (有几种工资(salary))
FROMemployees ;#4.count 函数的单独介绍
/**/
SELECT COUNT(salary)
FROMemployees ;#经常用来统计一共多少行
#一个表头可能有 null 可能会少统计一行
#所以统计所有表头 除非有一行全部为null
#否则不会漏行
SELECT COUNT(*) #所有表头的 所有非空(null)字段 都统计上(总行数)
FROMemployees ;SELECT COUNT('kk') #相当于额外加了个表头为1(任意字符串均可只要创造了新的列)的列# 这列的总行数就是表的总行数
FROMemployees ;
/* 效率innodb (默认存储引擎)(count(*)和count(1)差不多)但是比count(字符串)要高一些5.5版本之前默认的版本是 myisam(count(*)效率高)因为其内部有一个计数器它直接就返回了个数综上所述不管哪个存储引擎下count(*)用的比较多案例"查询每个部门的员工个数"id 名字 部门1  xx  10  1组      每一组员工出现的个数有几行就是每组员工有几个2  dd  20  2组      所以就是统计他的行数 3  mm  20  2组      所以用count(*)就行4  aa  40  3组       为什么呢5  hh  40  3组      因为经过 where等 筛选之后 的结果集 正好是我们想要的行数#5.和分组函数一同查询的字段要求是group by(等会要讲的)后的字段AVG(得出一组数据的平均值)employee_id(员工编号)
*/SELECT #查询结果出来 必须是一个规则的表格AVG(salary),#这家伙只有一行employee_id #就算这家伙有很多行 导致查询结果也只显示一行
FROMemployees ;#题目:查询公司员工(salary)工资的(max)最大值,(min)最小值,(AVG)平均值,(sum)总和
SELECT MAX(salary) 工资的最大值,MIN(salary) 工资的最小值,ROUND(AVG(salary), 2) 工资的平均值,#(保留两位小数)SUM(salary) 工资的总和
FROMemployees ;#2.查询员工表中的最大(hiredate)入职时间和最小入职时间的相差的天数
#并且起一个别名叫(DIFFRENCE)
#datediff('2017-10-1','2017-9-29');
#用来计算日期的新函数
# 执行结果  前面日期 -  后面日期 得到的天数
SELECT DATEDIFF(MAX(hiredate), MIN(hiredate)) DIFFRENCE
FROMemployees ;#3.查询部门编号为90的员工个数
SELECT COUNT(*) 部门编号为90的员工个数
FROMemployees
WHERE department_id = 90 ;#进阶5:分组查询
#引入:查询每个部门的(AVG)平均(salary)工资
SELECT AVG(salary)
FROMemployees ;#所谓分组查询 就是将2车间(总表)
#总装的平均工资(支表)
#初权的平均工资(支表)
#包纸的平均工资(支表)
#拆装的平均工资(支表)
#使用 GROUP BY 子句将表中的数据分成若干组/* 结构示例:
select column,group_function(column)
from    table
[where  condition]
[GROUP BY  group_by_expression]
[ORDER BY  column];语法示例:
select 分组函数,列(要求出现在group by的后面)     第5步
from 表                                         第1步
[where 筛选条件]                                第2步
group by 分组的列表                             第3步
[having 分组后的筛选]                           第4步
[order by 子句]                                 第6步注意:查询列表比较特殊,要求是分组函数和group by后出现的字段
*/
#引入:查询平均工资(不分部门)
SELECT AVG(salary)
FROMemployees ;#简单的分组查询
#案例1 :查询每个(job_id)工种的最高工资
SELECT MAX(salary),job_id
FROMemployees
GROUP BY job_id ;#案例2:查询每个(location_id)位置编号上的(departments)部门(COUNT(*))个数
SELECT COUNT(*),location_id
FROMdepartments #部门表 之前查询的一直是员工表employees
GROUP BY location_id ;#代表所有的部门信息
#(department_name部门名称)   装配车间
#(location_id位置编号)        2
#这个表是总表(`myemployees`)的子表
#与前面一直用的`employees` 同级#添加筛选条件
#案例1: 查询(email)邮箱中(LIKE)包含a字符的,每个(department_id)部门的平均工资
SELECT AVG(salary),department_id
FROMemployees #员工表
WHERE email LIKE '%a%'
GROUP BY department_id ;#案例2: 查询(IS NOT NULL)有(commission_pct)奖金的每个(manager_id)领导手下员工的最高(salary)工资
SELECT MAX(salary),manager_id #此处与GROUP BY 呼应 对应后为分组查询 #除了表头是 manager_id 外#表头下 每一行都是一组#manager_id  salary 都在一个表中 并没有联合查询
FROMemployees #查询的员工表
WHERE commission_pct IS NOT NULL
GROUP BY manager_id ;#添加复杂的筛选条件
#案例1:查询那个部门的员工个数>2
#1.查询每个(employees)部门的(department_id)员工(count(*))个数
SELECT COUNT(*),department_id
FROMemployees
GROUP BY department_id ;#2.根据 #1 的结果筛选, 查询哪个部门的员工个数大于2
/*
我们需要筛选出COUNT(*)>2的
但是我们在from 后 group by 前加入 where COUNT(*)>2 筛选条件时
由于 表结构不一致一边多一边少 会报错这里我们在最后使用一个新的关键词
having COUNT(*)>2
having #分组后查询
where  #分组前查询
示例如下
*/
SELECT COUNT(*),department_id
FROMemployees
GROUP BY department_id
HAVING COUNT(*) > 2 ;
#显示出以COUNT(*)>2为主 偏少的一列的表结构
#舍弃 偏多的表结构的行数
/*
我们再做几个案例进行一下巩固
#案例2:查询每个工种有奖金的员工
的最高工资>12000
的(job_id)工种编号和 MAX最高(salary)工资(像这种条件(这里是分组条件查询较多,分成两步)比较多的
我们一般应该分步来做更方便一点)
*/
#第一步.查询每个(job_id)工种(IS NOT NULL)有(commission_pct)奖金的员工的(MAX)最高(salary)工资
SELECT MAX(salary),job_id
FROMemployees
WHERE commission_pct IS NOT NULL #GROUP BY分组前筛选
GROUP BY job_id ;#第二步.根据第一步的结果继续筛选
#(MAX)最高(salary)工资>12000
#此筛选必定为分组后筛选(其实根据语义理解很容易判断出来)
SELECT MAX(salary),job_id
FROMemployees
WHERE commission_pct IS NOT NULL #GROUP BY分组前筛选
GROUP BY job_id
HAVING MAX(salary) > 12000 ;#分组后筛选
#案例3:查询领导编号>102的每个领导手下的最低工资>5000的
#查询条件较多(较绕的)分步进行更简单(此处分三步)
# 第一步.查询(manager_id)领导编号>102的每个领导手下的(MIN)最低(salary)工资
SELECT MIN(salary),manager_id
FROMemployees #员工表
GROUP BY manager_id ;#按(manager_id)领导编号分组(或许解释为
#表头下相同的 行合并成一行也不错?
#与之对应的 表其它行使用分组函数(处理一组数据变为1个数据)
#成为新的一行  1个数据 合并的行 )#第二步 添加筛选条件:(manager_id)领导编号>102
SELECT MIN(salary),manager_id
FROMemployees #员工表
WHERE manager_id > 102
#简单准确辨别 分组前 分组后 查询的方法
#因为(manager_id)领导编号在employees #员工表里
#所以是分组前查询 在此处使用 WHERE 筛选
GROUP BY manager_id ;
#如果(manager_id)领导编号不在employees #员工表里
#则是分组后查询 在此处使用 HAVING 筛选
#此方法不准确
#比如下面 最低工资是在employees #员工表里
#但使用的是 分组后查询 HAVING
#还是要根据语义来判断#第三步 添加筛选条件:(min)最低(selary)工资>5000
SELECT MIN(salary),manager_id
FROMemployees #员工表
WHERE manager_id > 102
GROUP BY manager_id
HAVING MIN(salary) > 5000 ;/*
此处接上文
注意:查询列表比较特殊,要求是分组函数和group by后出现的字段特点
总结:1.分组查询中的筛选条件分为两类数据源不一样     位置也不一样    关键字也不一样分组前筛选   原始表           GROUP BY子句前  where分组后筛选   分组后的结果集   GROUP BY子句后  having1.1 分组后筛选 判断法
当需要使用 (GROUP BY)分组函数后的结果 做条件
肯定是 分组后筛选 放在having子句中
(这... 感觉总结了一句废话)1.2 特殊情况
如果筛选的是 GROUP BY 这里
且并不需要使用 (GROUP BY)分组函数后的结果 做条件
那么 这里 先筛选 和后筛选 没有区别(结果是一样的)
能分组前筛选的,就优先考虑使用分组前筛选1.3
GROUP BY manager_id(在此以前的案例 放的都是单个的字段)
实际上也支持 按表达式 或函数分组
*/
#案例:按员工姓名的长度分组,查询每一组员工的个数,筛选员工个数大于5的有哪些
#(比较绕 建议分步 此处分为两步)
#第一步查询每种(LENGTH)长度(指(last_name)名字的长度)的员工个数
SELECT COUNT(*),LENGTH(last_name) 有几种员工的名字长度
FROMemployees
GROUP BY LENGTH(last_name)
#第二步添加筛选条件 员工个数大于5
HAVING COUNT(*) > 5 ;#如果都使用别名 当变量 修改如下
SELECT COUNT(*) 员工个数,LENGTH(last_name) 有几种员工的名字长度
FROMemployees
GROUP BY 有几种员工的名字长度
#第二步添加筛选条件 员工个数大于5
HAVING 员工个数 > 5 ;#按多个字段分组 (展示多个分组)
#案例:查询各(department_id)部门各(job_id)工种所有员工的(avg)平均(salary)工资
#按工种展示? 还是 按部门分组展示
#按工种展示 部门也展示不过有重复 加上平均工资共 3个表头
SELECT AVG(salary),department_id,job_id
FROMemployees #员工表
GROUP BY department_id,job_id ;# 在此之上追加排序功能
#按平均工资高低显示SELECT AVG(salary),department_id,job_id
FROMemployees #员工表WHERE department_id IS NOT NULL#筛选 部门不为null的
GROUP BY department_id,job_id
ORDER BY AVG(salary) DESC ;#默认升序asc  降序为desc
#ORDER BY 后可跟别名变量(好像就没有不能使用别名变量的吧)
/*
特点
总结: 2.group by子句支持单个字段/多个字段/函数/表达式3.也可以添加排序(ORDER BY放在GROUP BY后)
*/
#题目1.查询(job_id)工种的员工(salary)工资的(max)最大值,(min)最小值,(avg)平均值.(sum)总和并按job_id排序
SELECT MAX(salary) 最大值,MIN(salary) 最小值,AVG(salary) 平均值,SUM(salary) 求和,job_id 工种
FROMemployees
GROUP BY job_id
ORDER BY 工种 ;#默认升序asc 降序为desc
#题目2.查询员工最高工资和最低工资的差距(DIFFERENCE)
#DIFFERENCE即是计算日期差距函数 释义亦是 差距的意思
SELECT MAX(salary) - MIN(salary) DIFFERENCE
FROMemployees ;#题目3.查询各管理者手下员工的最低工资,其中最低工资不能低于6000
#没有管理者的员工不计算在内
SELECT #查询MIN(salary),#最低工资manager_id #管理者
FROM#数据来自employees #员工表
WHERE manager_id IS NOT NULL #没有管理者的员工不计算在内
GROUP BY manager_id #各管理者
HAVING MIN(salary) >= 6000 ;#其中最低工资不能低于6000#题目4. 查询部门所有部门的(department_id)编号,员工(COUNT(*))数量和工资平均值
#并按平均工资降序
SELECT department_id,COUNT(*),AVG(salary)
FROMemployees
GROUP BY department_id #以部门为主 各部门员工数量为COUNT(*)
ORDER BY AVG(salary) ;#题目5.查询各个(job_id)工种的员工人数
SELECT COUNT(*) 员工个数,job_id 工种
FROMemployees
GROUP BY 工种 ;#进阶6:连接查询/*
含义:又称多表查询,当查询的字段来自于多个表时
就会用到
*/SELECT   * FROM beauty ;
#女生表SELECT  * FROM boys ;
#男生表#迪卡尔集的错误情况:
SELECT NAME,boyname
FROMboys,beauty ;
/*迪卡尔集的错误情况:select count(*) from beauty;假设输出12行select count(*) from boys;假设输出4行最终结果 为12*4=48行第一列的每一行会匹配完第二列的每一行每匹配一行都算新的一行所以有 48行此现象 为 迪卡尔乘积现象发生原因:没有有效的链接条件如何避免: 添加上有效的连接条件怎么添加呢
我们链接查询有一个分类 按年代分类(不同的年代sql语言推出了不同的标准)sql 92标准(1992年推出的标准)  不推荐仅仅支持 内连接 外连接(部分)sql 99标准(1999年推出的标准)  推荐支持内连接 + 外连接(左外右外) + 交叉连接也就是说仅仅不支持 全外按功能分类:内连接:等值连接非等值连接自连接外连接:左外连接右外连接全外连接交叉链接(就只有交叉连接)*/
SELECT NAME,boyname
FROMboys,beauty
WHERE beauty.boyfriend_id = boys.id ;
#一.sql 92 标准 仅仅支持 内连接 外连接(部分)
#1.等值连接
语法:select 查询列表from 表1 别名,表2 别名where 表1.key=表2.key[and 筛选条件][group by 分组字段][having 分组后的筛选][order by 排序字段]特点:
/*1.1 多表等值连接的结果为多表的交集部分
1.2 n表链接,至少需要n-1个链接条件
1.3 多表的顺序没有要求
1.4 一般需要为表起别名
1.5 可以搭配前面介绍的所有子句使用,
比如排序,分组,筛选*/#案例1:查询女神名和对应的男神名
SELECT NAME,boyname
FROMboys,beauty
WHERE beauty.boyfriend_id = boys.id ;#案例2:查询员工名和对应的部门名
#员工名 来自于 employees 员工表的 last_name
#部门名 来自于 departments 部门表的 department_name
#连接 员工表 和 部门表 的 是 department_id
SELECT last_name,department_name
FROMemployees,departments
WHERE employees.`department_id` = departments.department_id ;
#`是着重号 并不是单引号 着重号是双击左边表自动添加的产生的#2. 可以为 from 表名(以前一直是表头)起别名
#查询 (last_name)员工名 (job_id)工种号 (job_title)工种名
#员工名 来自于 employees 员工表的 last_name
#工种号 来自于 employees 员工表的 job_id
#工种名 来自于 jobs 工种表的 job_title
#工种代号 与 工种名 分开存放的形式
#节省了字节空间(省下了重复工种名的空间字节数)
SELECT last_name,e.job_id,#两个表中都有job_id 需要区分job_title
FROMjobs j,employees e
WHERE e.job_id = j.job_id ;#当对form 后的表名 使用了别名时
#后面的WHERE子句必须使用别名(否则报错)
/*
提高语句的简洁度
区分多个重名的字段(一般指表头)
*/#3.form 后面两个表 可以调换顺序吗
#可以上面已经调换了#4.加筛选 用 因为链接俩表时使用了where 再加AND就可以了
#案例:查询有*(commission_pct)奖金的(last_name)员工名 (department_name)部门名
SELECT last_name,department_name ,commission_pct
FROMemployees e,departments d #为表起别名 后只能用别名
WHERE e.`department_id` = d.`department_id` AND e.`commission_pct` IS NOT NULL ;#案例2:查询城市名第二个字符为 o 的部门名和城市名#城市名 来自于 locations 位置表的 city
#部门名 来自于 departments 部门表的 department_name#城市与部门俩表之间使用 location_id 连接
#其中一张表 使用的location_id(只有代号) 与
#另一张表橙色钥匙使用的 location_id 相对应 中文名字
#并且橙色钥匙使用的 location_id (也含有代号)SELECT department_name,city
FROMdepartments d,locations l #为表起别名 后只能用别名
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%'; #城市名第二个字符为 o#5.加分组 GROUP BY#案例1:查询 各个城市 的部门个数(COUNT(*))#城市名 来自于 locations 位置表的 city
#部门名 来自于 departments 部门表的 department_name#链接 两张表的是 城市名对应的代号 location_id
SELECT COUNT(*) 个数,l.city
FROMdepartments d,locations l WHERE l.`location_id`=d.`location_id`
GROUP BY l.city  ;#按城市分组#案例2:查询部门表中有奖金的
#的部门名称  department_name 和
#部门表的 领导编号和 `manager_id`
#该部门中员工的最低工资 MIN(salary)#部门名/领导编号 来自部门表 `departments`
#工资 来自于 员工表 `employees`
SELECT department_name,#部门名d.manager_id,#部门表里的领导编号MIN(salary) #部门中最低工资为#sum(salary)
FROMemployees e,#员工表departments d #部门表
WHERE d.`department_id` = e.`department_id` #部门代号对应# AND commission_pct IS NOT NULL #有奖金的部门只有一个GROUP BY department_name;#部门名#6. 加排序
#筛选+where链接查询/筛选+分组函数+having筛选 后面还可以 加排序
#案例:查询工种表中不同工种的员工数量
#并且按每组的员工数量 降序#链接条件 员工数量 来自于 employees e,#员工表#工种名称 来自于 jobs j #工种表
SELECT job_title,#工种名称COUNT(*) #计算每个分组的数量,没有分组计算全部
FROMemployees e,#员工表jobs j #工种表
WHERE  e.`job_id`=j.`job_id`#只能通过`job_id`链接
#主要应该一般是按啥分组 就用啥链接
GROUP BY e.job_id
#这里按工种(job_id)分组 id是代号
#我们使用工种表 对应的 job_title 中文名称
#使用job_id也没关系 显示的依旧是 查询的job_title
#因为 job_id 与 job_title 有一一对应关系
#它俩是一样的
ORDER BY COUNT(*) DESC #排序 升3asc(不写默认) 降4desc
;#7. 链接超过两表
#WHERE 表1.k_id=表2.k_id 中再使用 and 表2.j_id=表3.j_id#案例: 查询员工表中每位员工的部门名和城市名
SELECT last_name,#员工名来自员工表department_name,#部门名来自部门表city #城市名来自于位置表
FROMemployees e,#员工表`departments` d,#部门表`locations` l #位置表
WHERE e.`department_id`=d.department_id
AND d.`location_id`=l.`location_id`;#2,非等值连接/*
在等值链接的基础上select 查询列表from 表1 别名,表2 别名{where 表1.key=表2.key} -> 此行更改为{where 非等值的连接条件}[and 筛选条件][group by 分组字段][having 分组后的筛选][order by 排序字段]*/
#案例1:查询出员工的工资和工资级别
SELECT *
FROMjob_grades ;#工资等级表
/*
lowest_sal     highest_sal     grade_level
1000        -2999        A
3000        -5999        B
6000        -9999        C
10000       -14999       D
15000       -24999       E
25000       -40000       F  */
#题目:查询出员工表中每位员工的工资和
#(job_grades)等级表的工资等级
SELECT salary,#工资grade_level #工资等级
FROMemployees e,#员工表job_grades g #工资级别表
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal` ;
#员工表中每位员工的工资 在工资级别表中
# 大于最低(lowest_sal) 小于最高(highest_sal)
#的工资级别为其最低最高区间所对应的 (grade_level)等级#追加功能 我只想看 工资级别为A的
SELECT salary,#工资grade_level #工资等级
FROMemployees e,#员工表job_grades g #工资级别表
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal` AND g.grade_level='A';
#后面亦可加 排序功能 (就没遇到不能的)#3.自链接(自己链接自己)
/*
语法:
在等值列表的基础上select 查询列表{from 表1 别名,表2 别名} -> 此行更改为{from 表 别名1,表 别名2}{where 表1.key=表2.key} -> 此行更改为{where 别名1.key1=别名2.key2} [and 筛选条件][group by 分组字段][having 分组后的筛选][order by 排序字段]
*/#案例:查询员工表中 员工名称 以及 其上级名称#由于员工表中的员工id(上级领导也算员工 需要分开使用)
#其实相当于一张表里放了 两张表 但是属性共通了某一列SELECT e.last_name,#员工表头的 员工名称e.`employee_id`,#员工表头中的 员工idm.last_name,#领导表头的 员工名称m.`employee_id` #领导表头中的 领导id
FROM`employees` e,#员工表(剥离出员工表头 与其员工id)`employees` m #员工表(剥离出领导表头 与其员工id)
WHERE e.manager_id = m.employee_id ;#题目:1.显示员工表中员工的最大工资 工资平均值
SELECT MAX(salary),AVG(salary)
FROM employees;#题目:2.查询员工表的 employee_id,job_id,last_name,
#按 department_id 降序后,当department_id相同,再按salary升序
SELECT employee_id,job_id,last_name
FROM employees
ORDER BY department_id DESC,SALARY;
#升3asc(默认)  降4desc#题目3.查询员工表的job_id中包含 a和e的,并且a在e的前面
SELECT job_id
FROM employees
WHERE job_id LIKE '%a%e%';
#注意 LIKE后面不跟= 我竟然写了等于...#题目4.已知表 student ,里面有 id(学号),name(姓名) grade(年级编号)
#已知表 grade ,里面有id(年级编号),name(年级名)
#已知表 result , 里面有 score(成绩),studentNo(学号)#要求查询姓名,年级名,成绩
/*
select s.name,g.name,score
from
student s,grade g,result r
where s.id = r.studentNo
and g.id = s.gradeid
*/#题目5.显示当前日期,以及去前后空格,截取子字符串的函数
/*
select now();
select trim(要去的字符 from '');不写默认去空格字符
select substr(str,1,2);1开始(mysql中下标从1开始) 截取两位
*/
SELECT SUBSTR( TRIM( NOW()),1,9);#题目1.显示所有员工的姓名,部门号和部门名称.
USE myemployees; #使用myemployees 大表作为数据库
SELECT last_name,d.department_id,department_name
FROMemployees e,departments d
WHERE e.department_id = d.department_id ;#题目2.查询员工表中员工id为103的员工的(job_id)工种和
#员工表中员工id为103的员工的部门id(department_id) 相通的
#部门表的  location_idSELECT employee_id,job_id,#来自员工表的 (job_id)工种location_id #来自部门表的 (location_id)位置编号
FROMemployees e,#员工表`departments` d#部门表
WHERE e.`department_id` = d.department_id
#来自员工表, 部门表 相通的 department_id部门编号
AND `employee_id`=103;#题目3. 查询所有员工中有奖金的人其所在的
#(department_name)部门名称
#,location_id,city位置编号
#以及其(last_name),名字
SELECT last_name,#来自于员工表  姓名department_name,#来自于部门表 部门名称d.location_id,#来自于部门表/位置表 均可 位置编号city #来自于位置表
FROMemployees e,#员工表`departments` d,#部门表`locations` l #位置表
WHERE `commission_pct` IS NOT NULL
#筛选出 (不为null)有奖金
AND e.`department_id`=d.`department_id`
#用于匹配 有奖金员工的部门名称
AND d.`location_id`=l.`location_id`;
#用于确认 有奖金员工的位置编号
#题目4.查询 city 在 toronto 工作的员工的
#last_name,`job_id`,`department_id`,来自员工表
#`department_name`来自部门表
SELECT last_name,`job_id`,d.`department_id`,department_name,city ,#来自于位置表d.`location_id` #部门表与 位置表通过location_id相连
FROM`departments` d,#部门表`employees` e,#员工表`locations` l #位置表
WHERE d.`location_id` = l.`location_id` #确认部门所在city位置AND d.`department_id` = e.`department_id` #确认员工所在部门AND city LIKE 'toronto' ;#筛选出 city 为  toronto 的#题目5.查询每个工种,每个部门的部门名,工种名和每个工种最低工资
#工种id`job_id` 来自于员工表`employees`/工种表
#工种名(job_title) 来自于 工种表 jobs
#部门名(`department_name`)来自于 部门表`departments`
#工资(salary)  来自于部门表`employees`
SELECT e.job_id,job_title,department_name,MIN(salary),COUNT(*)
FROM employees e,jobs j,departments d
WHERE j.job_id=e.job_id#匹配员工所在工种
AND d.`department_id` = e.`department_id` #确认员工所在部门#链接整合数据(3表相关联)
GROUP BY e.job_id;#题目6.查询 部门个数 大于2的 国家(这里没有国家名 只有编号名)
#国家 来自 位置表`locations` 的国家编号`country_id`
#部门 来自 部门表`departments`的 部门编号`department_id`/部门名称`department_name`
#共两表相连 通过 `location_id`位置编号
SELECT country_id,COUNT(*) 部门个数
FROM
locations l,#位置表
departments d#部门表
WHERE l.location_id=d.location_id
#将两表链接
GROUP BY country_id
#按国家分组
HAVING 部门个数>2
#分组后筛选 HAVING 也支持别名(好像就没有不支持别名的)
;#题目7.查询 员工的姓名,员工号,以及它的管理者的姓名和员工号
#结果示例
/*
表头的别名 employees    Emp#    manager   Mgr#
查询的结果 kochhar      101       king    100
*/#不管是 管理者/员工 的姓名`last_name`和员工号`employee_id`
#都是出自员工表 employees
#因此这是 自连接 共两张表(两张都是自己)
#注意 两张表 分别取别名 当做两张不同的表SELECT e.`last_name` employees,e.`employee_id` 'Emp#',m.`last_name` manager,m.`employee_id` 'Mgr#'
FROM
employees e,#员工表副本1
employees m#员工表副本2
WHERE e.`manager_id`=m.`manager_id`
#通过 管理者`manager_id`使两表连接
;#进阶6连接查询之 二sql 99语法
#二.sql 99 语法
/*
其中包含内连接(重要) [连接类型]: inner (等值连接,非等值连接,自连接连接)
外连接左外(重要) [连接类型]: left [outer]右外(重要) [连接类型]: right [outer]全外 [连接类型]: full [outer]
交叉连接 cross join语法:
select 查询列表
from 表1 别名
[连接类型(不写默认inner内连)] join 表2 别名
on 连接条件
#(92中用的是 where 容易混淆
#这里单独用on 提高了可读性)
[where 筛选条件]
[group by 分组]
[having 筛选条件]
[order by 排序]
[limit 子句]*/
#一.内连接 (等值连接,非等值连接,自连接连接)
/*
语法
select 查询列表
from 表1 别名
inner(默认) join 表2 别名
on 连接条件;
后面可继续跟 分组 筛选 排序等分类等值连接特点1.也可以添加排序,分组,筛选2.inner可以省略3.筛选条件放在where后面,连接条件放在on后面,提高可读性4.inner join连接和sql92语法中的等值连接效果是一样的非等值连接自连接连接
*/
#1.等值连接#题目1.查询员工名的部门名
#员工名`last_name` 来自于`employees`员工表
#部门名 `department_name` 来自于`departments`部门表
#两者以`department_id`部门编号 相连#现在的sql(99)语法
SELECT last_name,department_name
FROM departments d
INNER JOIN  employees e
ON e.department_id=d.department_id
;
#原来的sql(92)语法
SELECT last_name,department_name
FROM employees e,departments d
WHERE e.department_id=d.department_id
;#案例2.查询名字中包含e的员工名和工种名(添加筛选)
#员工名 来自于员工表`employees`的`last_name`
#工种名 来自于工种表`jobs` 的`job_title`
#共两表 以`job_id`相连SELECT last_name,job_title
FROM employees eINNER JOIN  jobs j#连接表2(inner)可以省略
ON e.job_id=j.job_id#连接条件WHERE last_name LIKE '%e%';
#这里WHERE仅有筛选的功能#案例3.查询部门个数>3的城市名和部门个数,
#(添加分组+筛选)#部门个数 来自于 departments 部门表的
#部门名称`department_name`/部门编号`department_id`的COUNT(*)#城市名 来自于位置表`location_id`的 city
#两表连接条件 为`location_id`SELECT city,COUNT(*) 部门个数
FROM departments dINNER JOIN `locations` l#连接表2(inner)可以省略
ON d.location_id=l.location_id#连接条件GROUP BY city#按城市分组 显示城市的部门个数
HAVING 部门个数>3;#案例4.查询哪个部门的部门员工>3的部门名和员工个数
#并按个数降序(添加排序)#员工个数 来自于 demployees 员工表的
#员工名称`last_name`/员工编号`employee_id`的COUNT(*)#部门名 来自于 `departments`部门表的 `department_name`
#按部门 分组 部门名称`department_name`/部门编号`department_id`#共两表 连接条件为 `department_id`
SELECT COUNT(*) 员工个数,department_name
FROM `employees` eINNER JOIN departments d#连接 表2(inner)可以省略
ON e.department_id=d.department_id#连接条件GROUP BY department_name#按部门分组 显示部门的员工个数
HAVING 员工个数>3
ORDER BY 员工个数 DESC;#升3 asc(默认) 降4 desc#案例5.查询员工名的部门名和工种名,并按部门名降序#员工名 来自于`employees`员工表的`last_name`
#部门名 来自于`departments`部门表的`department_name`
#工种名 来自于`jobs`工种表的`job_title`#累计 3表连接
#员工表 与 部门表的 连接条件为 `department_id`
#员工表 与 工种表的 连接条件为 `job_id`SELECT last_name,department_name,job_title
FROM employees e#这表作为连接另外两表的中间层
#不能写在最后面 否则 1表2表没有关系会连接失败INNER JOIN departments d#连接 表2(inner)可以省略
ON e.department_id=d.department_id#连接条件INNER JOIN jobs j#连接 表3 (inner)可以省略
ON e.job_id=j.job_id#连接条件ORDER BY department_name DESC;#升3 asc(默认) 降4 desc#二.非等值连接#题目1.查询员工的工资级别
#员工工资 来自于 employees 员工表的 salary
#工资级别 来自于 job_grades 工资等级表的 `grade_level`#共两表连接 连接类型 为 非等值
#连接条件 通过 工资区间 判断 得到相应的等级SELECT salary,grade_level
FROM employees e
JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
#通过 工资区间 判断 得到相应的等级#题目2.按工资级别分组并筛选出其组内元素大于2的,并按工资级别降序排序#工资级别 来自于 job_grades 工资等级表的 `grade_level`#员工个数 来自于`employees`员工表的
#`employee_id`员工编号/`last_name`员工名字
#累计出的 count(*) 员工个数#共两表连接 连接类型 为 s非等值
#连接条件 通过 工资区间 判断 得到相应的等级#按工资级别 grade_level 分组
SELECT grade_level,COUNT(*) 员工个数
FROM employees e
JOIN job_grades g
ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
GROUP BY grade_level
HAVING 员工个数>20
ORDER BY grade_level DESC;#升3 asc(默认) 降4 desc#三.自连接#查询员工的名字和他上级的名字
SELECT e.last_name,e.`manager_id`,m.last_name,m.manager_id
FROM `employees` e
JOIN employees m
ON e.manager_id=m.`employee_id`;#查询姓名中包含字符k的员工的名字和他上级的名字
SELECT e.last_name,e.`manager_id`,m.last_name,m.manager_id
FROM `employees` e
JOIN employees m
ON e.manager_id=m.`employee_id`
WHERE e.last_name LIKE '%k%'
;#二.外连接/*
应用场景:用于查询一个表中有,另一个表没有的记录特点:
1.外连接的查询结果为 主表 依次逐行 匹配 从表如果从表中有和它匹配的,则显示匹配的值如果从表中匹配不到的,则使用null作为匹配的值外连接查询结果=内连接结果+主表中有而从表没有的记录2.左外连接,left join左边的是主表右外连接,right join 右边的是主表3.左外 和 右外 其实就是
交换两个表的顺序,可以实现同样的效果内连接(指 等值/非等值/自连接)4.全外连接=内连接的结果+ full join 两边都是可以是主表
表1中有单表2中没有的+
表2中有但表1没有的*/#引入:查询没有男朋友的女神名字
SELECT * FROM beauty;
SELECT * FROM `boys`;
SELECT * FROM `admin`;#以下是左外连接
SELECT b.name,bo.*
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`id` IS NULL;#带小黄钥匙的绝对有值且不为 null
UPDATE boys SET usercp = NULL WHERE id=3;
#修改 boys 表 id=3(黄晓明) 的usercp值为NULL#以下是右外连接 和左外连接一样的结果 操作上调换了主从表的顺序
SELECT b.name,bo.*
FROM boys bo
RIGHT OUTER JOIN beauty b
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`id` IS NULL;#假如我还用左外连接 但是对调了主从表的顺序
SELECT b.*,bo.*
FROM boys bo
LEFT OUTER JOIN beauty b
ON b.`boyfriend_id`=bo.`id`;
#变成了查询没有女朋友的男神
#左外连接就是查询 没有雪糕的小朋友
#是个排查系统#案例1:查询那个部门没有员工
#使用左外 答题
SELECT d.*,e.employee_id
FROM departments d#部门表
LEFT OUTER JOIN employees e#左外连接 主表在 lefr 左边
ON d.`department_id`=e.`department_id`#连接条件
WHERE e.`employee_id` IS NULL;#使用右外 答题
SELECT d.*,e.employee_id
FROM employees e#部门表
RIGHT OUTER JOIN departments d#右外连接 主表在 RIGHT 右边
ON d.`department_id`=e.`department_id`#连接条件
WHERE e.`employee_id` IS NULL;#全外(当前版本不支持)
USE girls;#使用girls大表
SELECT b.*,bo.*
FROM beauty b
FULL  OUTER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`;#查询结果为两表全部对应出现
#未出现的 两表均会使用 null 匹配
#不分主从表 因此没有顺序#交叉连接(也无先后顺序关系 指from 表) 造成迪卡尔乘积SELECT b.*,bo.*
FROM beauty b
CROSS JOIN boys bo;#sql 92语法中用的 , 号隔开造成了迪卡尔乘积
#sql 99语法(也就是当前这个例子)
#使用 CROSS JOIN 代替 , 号造成迪卡尔乘积#所有(包括92/99语法)的连接到此介绍完毕
#建议使用后面学的 99 语法#功能: sql 99支持的较多
#可读性:sql 99实现连接条件和筛选条件的分离,可读性较高#题目1.查询编号>3的女神的男朋友信息,如果有则列出详细,
#如果没有,用null填充#编号来自于 `beauty`女神表的`id`
#男朋友信息来自于 `boyName`#共两表 两表使用外连接的左外 连接
#链接条件为 `beauty.boyfriend_id`
#与 boys.`id` 连接
SELECT *
FROM
beauty b
LEFT JOIN `boys` bo #outer 可省略
ON b.`boyfriend_id`=bo.`id`
WHERE b.`id`>3
AND bo.boyName IS NOT NULL;#二.查询那个城市没有部门
#城市来自于 `locations`位置表的city
#部门来自于 `departments` 部门表的`department_name`#共两表连接 为 外连接 左外连接(城市在连接左边)
#连接条件为 departments.`location_id`=`locations`.`location_id`SELECT city,d.*# d.* 表后面还可以跟*号
FROM locations l
LEFT JOIN departments d
ON  d.`location_id`=l.`location_id`
WHERE d.`location_id` IS NULL;#三,查询部门名为 sal 或 it 的员工信息
#部门名来自 `departments`部门表的`department_name`
#员工信息来自 `employees`员工表的 *#共两个连接 为外连接的左外连接(部门表在左边)
# 连接条件为 `departments`.`department_id`=`employees`.`department_id`
#附加操作为 筛选字段
SELECT department_name,e.*
FROM departments d
LEFT JOIN employees e
ON d.`department_id`=e.`department_id`
WHERE department_name='sal'
OR department_name='it';#进阶7:子查询(相比前面有些难度)
/*
含义:
出现在其他语句中的select语句,称为子查询或内查询
select 不仅仅如我们之前所见 他还可以使用在别的地方外部的语句可以是
我们尚未学过的 insert update delete select(较多)等外部的查询语句, 称为 主查询 或 外查询概念:出现在其他语句内部的select语句,称为子查询或内查询内部嵌套其他select语句的查询称为外查询或主查询
示例:select first_name from employees wheredepartment_id in(#查询条件内又用到了一个查询语句#括号里面(这里)是一个完整的select 它单独就可执行select depqrtment_id from departmentswhere location_id=1700)如何分类?1.按子查询出现的位置:(主要按这种分类来讲解)① select 后面:仅支持标量子查询(结果集只有一行一列)② from 后面支持表子查询(结果集 只要是个查询结果就行 )③ where 或 having 后面(重点讲它)支持 标量/单行 子查询(结果集只有一行一列)支持 列子查询(结果集只有多行一列)(使用较少的) 支持 行子查询(结果集有 多行多列)④ exists (未学 释义:存在与否,相关子查询) 后面 支持 所有 子查询(结果集 只要是个查询结果就行 )2.按结果集的行列数不同:①常用 标量/单行 子查询(结果集只有一行一列)②常用 列子查询(结果集只有一列多行)③行子查询(结果集有 多/一 行多列)④表/嵌套 子查询(结果集 只要是个查询结果就行 )*/#示例1.where或having后面 包含3种查询方法
#1.标量 子查询(单行子查询)
#2.列 子查询(多行子查询)#3.行 子查询(多列多行)
/*
特点:
1.子查询都会放在小括号内
2.子查询一般放在条件的右侧
3.标量 子查询,一般搭配着单行操作符使用
(单行操作符:> < = >= <= <>(不等于))列子查询,一般搭配着多行操作符使用
(多行操作符 IN,any/some,all )4.子查询 的执行优先于 主查询的执行, 主查询的条件用到了子查询的结果*/
#1.标量 子查询#1.查询 Abel 的工资
SELECT salary
FROM employees
WHERE last_name='Abel';#2查询员工的信息,满足 salary > Abel 的工资
SELECT *
FROM employees
WHERE salary>(SELECT salaryFROM employeesWHERE last_name='Abel');#案例2 筛选后面的标量子查询:返回job_id与141号员工相同,salary比143号员工多的员工
#姓名,job_id和工资#第一步 查询 141 号员工的 job_id
SELECT job_id
FROM employees
WHERE employee_id=141;#第二步 查询 143 号员工的 salary
SELECT salary
FROM employees
WHERE employee_id=143;#第三步 查询 姓名,job_id 和 (salary)工资
#要求 job_id= 第一步中141 号员工的 job_id
#要求 salary> 第二步中143 号员工的 salary
SELECT last_name,job_id, salary
FROM employees
WHERE job_id=(SELECT job_idFROM employeesWHERE employee_id=141
)
AND salary>(SELECT salaryFROM employeesWHERE employee_id=143
);#案例3:返回公司工资最少的员工的last_name,job_id和saary#第一步查询公司的最低工资
SELECT MIN(salary)
FROM employees;#第二步查询员工的last_name,job_id 和 salary,
#要求salary=第一步的查询结果
SELECT last_name,job_id,salary
FROM employees
WHERE salary=(SELECT MIN(salary)FROM employees);#案例4:查询最低工资 大于50号部门最低工资的部门的部门id和该部门最低工资(第二低)#第一步,查询50号部门的最低工资
SELECT MIN(salary)
FROM employees
WHERE department_id =50;#第二步查询每个部门的最低工资
SELECT MIN(salary),department_id
FROM employees
GROUP BY `department_id`;#第三步 在第二步结果中筛选 满足 min(salary) >第一步结果(2100$)
#的部门id和该部门最低工资
SELECT department_id,MIN(salary)
FROM employees
GROUP BY `department_id`
HAVING MIN(salary)>(SELECT MIN(salary)FROM employeesWHERE department_id =50);#非法使用子查询的情况
SELECT department_id,MIN(salary)
FROM employees
GROUP BY `department_id`
HAVING MIN(salary)>(# > < 这种单行操作符里面只能搭配标量子查询SELECT MIN(salary)#此处改为SELECT salary会报错 成了多列子查询#min()只返回一组数据的一个结果(一列一行)标量查询FROM employeesWHERE department_id =50#此处改为WHERE department_id =250(为空不是一行一列)#最终虽然不会报错且结果为空 但是也是非法使用);#示例第2点 筛选后跟 单列/多行 子查询 (where或having后面)
#且使用 ()形式包起来 不管什么样的子查询 都放在小括号里面
/*操作符               含义in/not in         等于一行列表中的任意一个
any|some         和子查询返回的某一个值比较
(两者同一个意思 有歧义可读性低 )
比如 a>all(10,20,30)等同于 a>min(10,20,30)
再比如 a<all(10,20,30)等同于 a<max(10,20,30)
而max和min属于标量子查询 而 all 却是列/多行 子查询all                 和子查询返回的所有值比较
(all(指()内所有条件满足)和any(指()内单个条件满足)经常容易搞混)
*/#筛选后跟 单列/多行 子查询#案例1:返回 location_id 是1400或1700的部门中所有员工的姓名
#location_id 来自于 位置表 locations/departments 部门表 的位置编号
#部门 来自于 `departments`部门表 的
#员工姓名 来自于 `employees`员工表的 `last_name`#感觉是2表连接 部门 `location_id` 确定部门 再确定`department_id`员工#第一步查询 location_id 是14000或1700的部门编号
SELECT DISTINCT department_id#假如说有重复的最好去一下重仅提高效率
FROM departments
WHERE location_id IN(1400,1700)
#WHERE location_id=1400
#OR location_id=1700
;
#查询结果为 单列多行 子查询#第二步查询员工姓名,要求部门编号是 第一步中的某一个
SELECT last_name
FROM employees
WHERE department_id IN(#把in完整替换为=any结果相同
# in 完整替换为not in不是这个里面的
# in 完整替换为<>all同上依旧不是这个里面的意思#此处这样做 居然省去了两表连接的步骤(其实就算两表连接也未必查的出来)SELECT DISTINCT department_id#假如说有重复的最好去一下重仅提高效率
FROM departments
WHERE location_id IN(1400,1700)
#WHERE location_id=1400
#OR location_id=1700);#案例2.返回 比 (job_id为'IT_PROG'的部门) 任一工资低的员工的
#员工号,姓名,job_id 以及salary#员工号来自于 `employees`员工表的 `employee_id`
#姓名                              `last_name`
#job_id                             工种
#salary                             工资
#部门                              `department_id`SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ANY(#任一工资低的#job_id为'IT_PROG'的部门SELECT DISTINCT salary#去重DISTINCTFROM employeesWHERE job_id='IT_PROG')
AND job_id<>'IT_PROG';#排除自己#以上可以分为两步 先做子查询
#再做题目后 把子查询放里面去#或者
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(#任一工资低的#job_id为'IT_PROG'的部门#SELECT DISTINCT salary#去重DISTINCT#改为SELECT MAX(salary)#执行结果还是一样的76行FROM employeesWHERE job_id='IT_PROG')
AND job_id<>'IT_PROG';#排除自己#案例3.               把任意 改为 所有 如下  #返回 比 (job_id为'IT_PROG'的部门) 所有 工资低的员工的
#员工号,姓名,job_id 以及salary
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<(#任一工资低的#job_id为'IT_PROG'的部门#SELECT DISTINCT salary#去重DISTINCT#改为SELECT MIN(salary)#max改成min#执行结果是44行FROM employeesWHERE job_id='IT_PROG')
AND job_id<>'IT_PROG';#排除自己
#或
SELECT employee_id,last_name,job_id,salary
FROM employees
WHERE salary<ALL(#any改成all
#执行结果还是44行#任一工资低的#job_id为'IT_PROG'的部门SELECT DISTINCT salary#去重DISTINCTFROM employeesWHERE job_id='IT_PROG')
AND job_id<>'IT_PROG';#排除自己#3.行子查询(结果集 一/多 行多列 较少使用 )#案例:查询员工编号最小并且工资最高的员工编号的员工信息#解 子查询 题目是 分步先进行子查询 #第一步查询最小的员工编号
SELECT MIN(`employee_id`)
FROM employees;#第二步查询最高工资
SELECT MAX(`salary`)
FROM employees;#第三步
SELECT *
FROM employees
WHERE employee_id=(#第一步中的查询最小的员工编号SELECT MIN(`employee_id`)FROM employees)AND salary=(#第二步中的查询最高工资SELECT MAX(`salary`)FROM employees);#我们发现查询的结果只有一行
#如果为一行子查询 我们可以精简为 以下代码
SELECT *
FROM employees
WHERE (employee_id,salary)=(SELECT MIN(employee_id),MAX(salary)FROM employees);#二,第二大种 前面都是放在where或having后的子查询
#现在讲 放在select 后的子查询#案例:查询每个部门的员工个数SELECT d.*,(SELECT COUNT(*)FROM employees eWHERE e.`department_id`=d.`department_id`
) 部门员工数量
FROM `departments` d
;#用以前两表连接也可以 这种方式也可以#案例2:查询员工号=102的部门名Exe
#不许用连接查询 其实就是用了连接查询
SELECT (SELECT `department_name`FROM `departments` dWHERE d.`department_id`=e.department_id#里面的结果只能有 1列 1行 一个结果
) 部门名FROM
employees e
WHERE e.`employee_id`=102;#三,第三大种 前面都是放在where/having/select后 的子查询
#现在讲 放在 from 后的子查询
/*
将子查询结果充当一张表,要求必须起别名
*/#案例:查询每个部门的平均工资的工资等级#第一步 查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM `employees`
GROUP BY department_id;#第二步 查询工资等级
SELECT * FROM job_grades;#工资等级表#使用 工资等级表 连接 第一步查询的各部门平均工资#共两表 相连 为内连接的非等值相连
#连接条件 为平均工资SELECT 部门平均工资与部门编号表.*,g.grade_level 工资等级
#查询ag_dep表中所有内容  等级表中的等级
FROM (#第一步 查询每个部门的平均工资SELECT AVG(salary) 部门平均工资,department_id 部门编号FROM `employees`GROUP BY department_id#各部门平均工资的 (工资 与 部门编号)表) 部门平均工资与部门编号表#必须起别名否则这个表没名字找不到
INNER JOIN job_grades g
ON 部门平均工资与部门编号表.部门平均工资 BETWEEN lowest_sal AND highest_sal;#四,exists后面(相关子查询)
#exists前面没讲过
SELECT EXISTS(#EXISTS是否存在的意思 #这里面的子查询#有结果对外部返回数字1#没结果对外部返回数字0 SELECT employee_id FROM employees);/*
语法:
exists(完整的查询语句)
结果:
1或0
*/#案例1:查询有员工的部门名SELECT `department_name`
FROM `departments` d
WHERE EXISTS(#有部门员工返回1 通过WHERE筛选#没有部门员工返回1 通不过WHERE筛选SELECT *FROM employees eWHERE d.`department_id`=e.`department_id`#两表连接);#使用 in 的方法也可以做出来 用连接查询也可以做出来
SELECT department_name
FROM `departments` d
WHERE d.department_id IN(SELECT e.department_idFROM employees e);#案例2:查询没有女朋友的男神信息#inSELECT bo.*
FROM boys bo
WHERE bo.id NOT IN(SELECT boyfriend_idFROM beauty);#都有女朋友结果为空#exists
SELECT bo.*
#查询 男神表的所有信息
FROM boys bo
#男神表
WHERE NOT EXISTS(# 筛选没有女朋友的男神SELECT boyfriend_id#查询女神的boyfriend_idFROM beauty bWHERE bo.id=b.`boyfriend_id`#连接条件);#都有女朋友结果为空#题目1.查询和 员工名为 Zlotkey 的 相同部门(80)的员工姓名和工资
#第一步查部门编号
SELECT `department_id`
FROM `employees`
WHERE `last_name`='Zlotkey';
#第二步查询在 部门编号为80 的员工的名字和工资
SELECT `last_name`,`salary`,department_id
FROM employees
WHERE `department_id`= (SELECT `department_id` FROM `employees`WHERE `last_name`='Zlotkey');#题目2.查询工资比公司平均工资高的员工的员工号,姓名和工资
#第一步查询所有员工的平均工资 6461.682243
SELECT AVG(salary)
FROM `employees`;
#第二步查询比平均工资高的员工的 编号,姓名,工资
SELECT `employee_id`,`last_name`,`salary`
FROM `employees`
WHERE salary>(SELECT AVG(salary)FROM `employees`);#题目3.查询当前部门中工资比当前部门平均工资高的员工的员工号,姓名,工资
#约三步
#第一步 查询各部门的平均工资
SELECT AVG(salary),department_id
FROM`employees`
GROUP BY `department_id`;
#第二步 连接第一步结果集(当表写在from后)和employees表
SELECT salary,e.department_id,`employee_id`,`last_name`
FROM (SELECT AVG(salary) 平均工资,department_idFROM`employees`GROUP BY `department_id`) 各部门的工资
INNER JOIN employees e
ON 各部门的工资.department_id=e.department_id
#此结果是 每个部门每个员工的工资
#在此基础上进行筛选
WHERE salary > 各部门的工资.平均工资 ;#题目4.查询和 姓名中包含字母u的员工 在相同部门的员工的 员工号,姓名
#第一步查询 姓名中包含字母u的员工 的部门编号
SELECT DISTINCT `department_id`#去重
FROM `employees`
WHERE `last_name` LIKE '%u%';#第二步 查询第一步结果 部门编号 其含有的员工
SELECT `employee_id`,`last_name`
FROM `employees`
WHERE `department_id` IN(#字结果集多行一列选择用inSELECT DISTINCT `department_id`#去重FROM `employees`WHERE `last_name` LIKE '%u%');#题目5.查询在部门的location_id为1700的部门工作的员工的员工号
#①查询 location_id 为 1700 的部门有哪些
SELECT DISTINCT department_id#最好去下重
FROM `departments`
WHERE `location_id`=1700;#②查询部门号=①中的任意一个的员工号
SELECT `employee_id`
FROM `employees`
WHERE `department_id`=ANY(#=any和in在此处都可以SELECT DISTINCT department_id#最好去下重FROM `departments`WHERE `location_id`=1700);#6.查询管理者是 K_ing 的员工姓名和工资
#子查询 有着类似于连接的效果 但又属于两种不同的方式
#①查询姓名为 K_ing 的员工编号
SELECT `employee_id`
FROM `employees`
WHERE last_name='K_ing';#结果100和156#②查询哪个员工的manager_id=①
SELECT `last_name`,salary
FROM `employees`
WHERE manager_id=ANY(#=any和in在此处都可以
#假设你不知道子查询结果是一行还是多行全用in准没事SELECT employee_idFROM `employees`WHERE last_name='K_ing');#题目7.查询工资最高的员工的姓名,
#要求first_name和last_name显示为一列,
#列名为姓名#①查询最高工资
SELECT MAX(salary)
FROM employees;#②查询工资=①的姓.名
SELECT CONCAT(first_name,last_name) '姓.名'
FROM `employees`
WHERE `salary` =(#最高工资就一个用=此处也可用inSELECT MAX(salary)FROM employees);#进阶8:分页查询(重点但是比较简单)
/*应用场景:当要显示的数据,一页显示不全,需要分页提交 sql 请求语法:  select 查询列表        ⑦from 表                ①[join type] join 表2   ②on 连接条件            ③where 筛选条件           ④group by 分组字段      ⑤having 分组后的筛选    ⑥order by 排序的字段    ⑧limit offset,size;     ⑨#分页       条目数offset要显示条目数的起始索引(这里的索引从0开始)size 要显示的条目个数特点:①limit语句(不管是从执行上从语法上)都是放在查询语句的最后②公式 要显示的页数 page,每页的条目数sizeselect 查询列表from 表limt (page-1)*size,size;#页数公式size=10page1        02        103        20
*/#案例1:查询前五条员工信息
SELECT * FROM employees
LIMIT 5;#默认offset的起始索引为0
#limit 0,5;
#limit offset,size;#案例2:查询第 11 条--第 25 条
SELECT  * FROM employees
LIMIT 10,15;#第十条条目开始 显示15条 #案例3:有奖金的员工信息,并且工资较高的前10名显示出来
SELECT * FROM employees
WHERE `commission_pct` IS NOT NULL
ORDER BY salary DESC#升3asc(默认)降4dese
LIMIT 10;#题目
/*
已知表 stuinfo
id 学号
name 姓名
email 邮箱 john@126.com
gradeId 年级编号
sex 性别 男 女
age 年龄已知表 grade
id 年级编号
gradeName 年级名称一,查询 所有学员的邮箱的用户名(注:邮箱中 @前面的字符)
通过年级编号 两表相连
再使用 substr 简写/substring全名 截取邮箱字符串
substr(要截取的字符串,开始索引(从1开始),长度)
instr(被查找的字符串,'要查找的字符串') 返回第一个找到的下标
instr(email.'@')-1 才为正确的截取长度值select substr(email,1,instr(email.'@')-1) 用户名
from stuinfo;二.分别查询男生和女生个数select count(*)个数,sex
from stuinfo
group by sex;三.查询年龄>18岁的所有学生的姓名和年级名称
select name,gradeName
from stuinfo s
inner join grade g
on s.gradeId=g.id
where age>18;四.查询哪个年级的学生最小年龄>20岁
1.每个年级的最小年龄
select min(age),gradeid
from stuinfo
group by gradeid;min(age) gradeid  5        16        27        32.在1的结果上筛选
select min(age),gradeid
from stuinfo
group by gradeid
having min(age)>20;五,试说出查询语句中涉及到的所有关键字,以及执行先后顺序select 查询列表      ⑦from 表              ①
连接类型 join 表二   ②
on 连接条件          ③
where 筛选条件       ④
group by 分组列表    ⑤
having 分组后的筛选  ⑥order by 排序列表    ⑧
limit 偏移,条目数;   ⑨
*/#1.查询工资最低的员工信息:last_name,salary#①查询最低的工资
SELECT MIN(salary)
FROM employees;#②查询last_name,salary,要求salary=①
SELECT last_name,salary
FROM employees
WHERE salary=(SELECT MIN(salary)FROM employees);#2.查询平均工资最低的部门信息
#①各部门的平均工资
SELECT AVG(salary),`department_id`
FROM `employees`
GROUP BY department_id;#② 查询①结果上最低平均工资SELECT MIN(平均工资)
FROM (SELECT AVG(salary) 平均工资,`department_id`FROM `employees`GROUP BY department_id ) 各部门的平均工资
;#③查询哪个部门的平均工资=②
SELECT AVG(salary) 平均工资,`department_id` 各部门FROM `employees`GROUP BY department_id
HAVING AVG(salary)=(SELECT MIN(平均工资)
FROM (SELECT AVG(salary) 平均工资,`department_id`FROM `employees`GROUP BY department_id ) 各部门的平均工资);#④查询部门信息
SELECT d.*
FROM `departments` d
WHERE d.`department_id`=(SELECT `department_id` 各部门FROM `employees`GROUP BY department_id
HAVING AVG(salary)=(SELECT MIN(平均工资)
FROM (SELECT AVG(salary) 平均工资,`department_id`FROM `employees`GROUP BY department_id ) 各部门的平均工资));#方式二
#①各部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id;#②求出最低平均工资的部门编号
SELECT department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)#默认升序
LIMIT 1;#0页第一行
#取得平均工资最低的那行#③查询部门信息
SELECT *
FROM `departments`
WHERE `department_id`=(SELECT department_idFROM employeesGROUP BY department_idORDER BY AVG(salary)#默认升序LIMIT 1)# 3. 查询平均工资最低的部门信息和该部门的平均工资
#①各部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id;#②求出最低平均工资的部门编号
SELECT AVG(salary) department_id
FROM employees
GROUP BY department_id
ORDER BY AVG(salary)#默认升序
LIMIT 1;#0页第一行
#取得平均工资最低的那行#③查询部门信息
SELECT d.*,平均工资
FROM `departments` d
JOIN (SELECT AVG(salary) 平均工资,department_idFROM employeesGROUP BY department_idORDER BY AVG(salary)#默认升序LIMIT 1) 最低平均工资和部门编号
ON d.`department_id`=最低平均工资和部门编号.`department_id`
;/*
#③方式二 失败
select d.*,(
这里的子查询只能放置标量子查询 单列一个
无法放 department_id
但后面又需要用到 department_id
所以此方法不可行SELECT AVG(salary) 平均工资FROM employeesGROUP BY department_idORDER BY AVG(salary)#默认升序LIMIT 1) 最低平均工资和部门编号
from `departments` d
where d.`department_id`=最低平均工资和部门编号.`department_id`
;
*/# 4. 查询平均工资最高的 job 信息
#①查询每个job的平均工资
SELECT AVG(salary),job_id
FROM `employees`
GROUP BY job_id;#②查询平均工资最高
SELECT AVG(salary),job_id
FROM `employees`
GROUP BY job_id
ORDER BY AVG(salary) DESC#降序
LIMIT 1
;#③平均工资最高 job 信息
SELECT j.*,平均工资最高的工资和工种.*
FROM `jobs` j
JOIN (SELECT AVG(salary),job_idFROM `employees`GROUP BY job_idORDER BY AVG(salary) DESC#降序LIMIT 1) 平均工资最高的工资和工种
WHERE j.`job_id`=平均工资最高的工资和工种.job_id
;# 5. 查询平均工资高于公司平均工资的部门有哪些
#①查询公司的平均工资
SELECT AVG(salary)
FROM employees;#②查询每个部门的平均工资
SELECT AVG(salary)
FROM employees
GROUP BY `department_id`;#③ 筛选②结果集,满足平均工资>①
SELECT AVG(salary),`department_id`
FROM employees
GROUP BY `department_id`
HAVING AVG(salary)>(SELECT AVG(salary)FROM employees#6461);# 6. 查询出公司中所有 manager 的详细信息.
#①查询所有 (领导)manager 的员工编号
SELECT DISTINCT manager_id#去重
FROM `employees`;#②查询详细信息,满足`employee_id`=①
SELECT e.*
FROM `employees` e
WHERE e.`employee_id` =ANY(#=ANY可完全替换为inSELECT DISTINCT manager_id#去重FROM `employees`);# 7. 按各部门工资最高的员工排列
#找出其中哪个部门最低
#①查询各部门其员工的最高工资
SELECT MAX(salary) ,department_id
FROM employees
GROUP BY `department_id`;#② 在①找出其中哪个部门最低
SELECT department_id
FROM employees
GROUP BY `department_id`
ORDER BY MAX(salary)#默认升序
LIMIT 1#0页第一行最低工资的那个
;#③ 查询②结果部门(10)的最低工资
SELECT MIN(salary) ,department_id
FROM employees
GROUP BY `department_id`
HAVING department_id=(SELECT department_idFROM employeesGROUP BY `department_id`ORDER BY MAX(salary)#默认升序LIMIT 1#0页第一行最低工资的那个);# 8. 查询平均工资最高的部门的 manager 的详细信息:
#`last_name`,`department_id`,`email`,`salary`
#①查询平均工资最高的部门
SELECT department_id
FROM employees
GROUP BY `department_id`
ORDER BY AVG(salary) DESC#降序
LIMIT 1#0页第一行最低工资的那个部门90
;
#② 查询①的结果部门中的 员工 信息
SELECT *
FROM employees e
WHERE e.`department_id`=(SELECT department_idFROM employeesGROUP BY `department_id`ORDER BY AVG(salary) DESC#降序LIMIT 1#0页第一行最低工资的那个部门90)
;#③ 查询②的结果中,为 (领导)manager的员工信息
SELECT *
FROM (SELECT *FROM employees eWHERE e.`department_id`=(SELECT department_idFROM employeesGROUP BY `department_id`ORDER BY AVG(salary) DESC#降序LIMIT 1#0页第一行最低工资的那个部门90)) 表一,(SELECT DISTINCT `manager_id`FROM employees eWHERE e.`department_id`=(SELECT department_idFROM employeesGROUP BY `department_id`ORDER BY MAX(salary) DESC#降序LIMIT 1#0页第一行最低工资的那个部门90)) 表二
WHERE 表一.`employee_id`=表二.`manager_id`;#1.查询每个专业的学生人数
#新表student的内容
SELECT * FROM `major`;#专业 主键`majorid`
SELECT * FROM `result`;#成绩 主键id   外键`studentno`
SELECT * FROM `student`;#学生 主键`studentno`学号 外键`majorid`SELECT majorid,COUNT(*)
FROM student
GROUP BY majorid;#2.查询参加考试的学生中,每个学生的平均分,最高分
SELECT AVG(score),MAX(score),studentno
FROM result
GROUP BY studentno;#3. 查询姓张的每个学生的最低分大于60的学号.姓名
#姓名 来自`student` 学员表的 `studentname`
#分数 来自`result` 成绩表的 `score`
#共两表 为 内连接的等值连接
#等值条件为 `studentno`
SELECT s.studentno,s.`studentname`,MIN(score)
FROM `student` s
JOIN result r
ON s.studentno=r.studentno
WHERE s.`studentname` LIKE "张%"
GROUP BY s.studentno
HAVING MIN(score)>60
;# 4. 查询生日在'1988-1-1'后的学生姓名,专业名称
#生日来自于 `student`学生表的`borndate`
#姓名来自于                  `studentname`
#专业名称 来自于 `major`专业表的`majorname`
#共两表 为 内连接的等值连接
#等值条件为 `majorid`
SELECT studentname,majorname,borndate
FROM student s
JOIN major m
ON s.majorid=m.majorid
WHERE DATEDIFF( borndate,'1988-1-1') > 0;
#     日期做差   这里日期- 这里的   > 0# 5. 查询每个专业的男生人数和女生人数
#专业 来自于 `student`学生表的     `majorid`
#男生人数来自于                    `sex`=男
#女生人数来自于                    `sex`=女
SELECT COUNT(*) 个数,sex 性别,majorid 专业
FROM student
GROUP BY sex,majorid;
#分组可以按两个分组,号隔开...我居然用and再写一个分组#方式二:
SELECT majorid,(SELECT COUNT(*)FROM studentWHERE sex='男'AND s.majorid=majorid) 男,(SELECT COUNT(*)FROM studentWHERE sex='女'AND s.majorid=majorid) 女
FROM student s
GROUP BY majorid;# 6. 查询专业和张翠山一样的学生的最低分
#先达成题目后面的条件 一般使用子查询
#① 查询张翠山的专业
SELECT `majorid`
FROM `student`
WHERE `studentname`='张翠山';#专业为1#② 专业为1的 学生的最低分(70)
SELECT MIN(`score`),majorid
FROM `result` r
JOIN `student` s
ON r.`studentno`=s.studentno
WHERE `majorid`=(SELECT `majorid`FROM `student`WHERE `studentname`='张翠山'#专业为1);# 7. 查询大于60分的学生的姓名,密码,专业名
SELECT `studentname`,`loginpwd`,`majorname`
FROM `student` s
JOIN `result` r
ON s.`studentno`=r.`studentno`
JOIN `major` m
ON s.`majorid`=m.`majorid`
WHERE `score`> 60;
#三表内连接的等值连接 加筛选# 8. 按邮箱位数分组,查询每组的学生个数
SELECT COUNT(*),LENGTH(email)
FROM student
GROUP BY LENGTH(email);# 9. 查询学生名,专业名,分数
SELECT `studentname`,`majorname`,`score`
FROM `student` s
JOIN `result` r
ON s.`studentno`=r.`studentno`
JOIN `major` m
ON s.`majorid`=m.`majorid`
;
#三表内连接的等值连接 加筛选# 10.查询哪个专业没有学生,分别用左连接和右连接实现
#专业 来自`major`专业表
#学生 来自 `student`学生表#两表连接 使用外连接的左外/右外均可
#连接条件 `majorid`
#左外
SELECT `majorname`,`studentname`
FROM major m
LEFT JOIN student s
ON m.majorid=s.majorid
WHERE studentname IS NULL;#右外(只是调换位置并更改连接名字)
SELECT `majorname`,`studentname`
FROM student s
RIGHT JOIN major m
ON m.majorid=s.majorid
WHERE studentname IS NULL;# 11. 查询没有成绩的学生人数
#成绩   `result`成绩表的     `score`
#学生 来自于`student`学生表的  `studentname`#共两表连接  sql 99语法外连接中的左外连接
#连接条件为 studentno
SELECT s.*,r.*
#SELECT COUNT(*)#9个
FROM student s
LEFT JOIN result r
ON s.`studentno`=r.`studentno`
WHERE score IS NULL;#进阶9:联合查询(没表)/*
union 联合 合并: 将多条查询语句的结果合并成一个结果
*/
#引入的案例:查询部门编号>90或邮箱包含a的员工信息
SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;#使用联合查询
SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;/*
语法:
查询语句1
union
查询语句2
union
...应用场景
*/
#案例:查询中国用户男性的信息
#     以及外国用户男性的信息
SELECT id,cname,csex
FROM t_ca
WHERE csex='男'
UNION
SELECT t_id,tName,tGender FROM t_ua
WHERE tGender='male';#要查询的结果来自于多个表,
#且多个表没有直接的连接关系
#但查询的信息一致时意义:1.将一条比较复杂的查询语句拆分成多条语句2.适用于查询多个表的时候,查询列基本是一致#联合查询的特点:#1.要求多条查询语句的查询列数是一致的#2.要求多余查询语句的查询的每一列的类型和顺序最好一致#3.union关键字默认去重,如果使用union all 可以包含重复项#DQL 查询总结
语法:select 查询列表            ⑦from 表1 别名      ①连接类型 join 表2   ②on 连接条件          ③where 筛选        ④group by 分组列表      ⑤having 筛选             ⑥order by 排序列表            ⑧linit 起始条目索引,条目数     ⑨#DML语言(常用)
/*
数据操纵语言:
插入:insert
修改:update
删除:delete
*/#1.插入语句 方式一
/*
语法:
insert into 表名(列名,...)values(值1,...)表名
列名
新值
字符类型 int 数字 char 字符串双引号datetime 日期单引号blob     保存图片的Nullable 可以为空null
*/
#1.插入的值的类型要与列的类型一致或兼容
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐艺昕','女','1990-4-23','18988888888',NULL,2);SELECT * FROM beauty;#2.不可以为null的列必须插入值.可以为null的列是如何插入值?
#方式2:
INSERT INTO beauty(id,NAME,sex,borndate,phone,boyfriend_id)
VALUES(14,'金星','女','1990-4-23','13888888888',9);
#方式3:
INSERT INTO beauty(id,NAME,sex,phone)
VALUES(15,'娜扎','女','13888888888');
#设计表的时候有默认值 没有默认值为null
#要么列名和值都省略, 要么值写null#3.在保持列名与值一一对应的情况下,列的顺序可以调换
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('匠心','女',16,'110');#4.列数和值的个数必须一致
INSERT INTO beauty(NAME,sex,id,phone)
VALUES('关晓彤','女',17,'110');#5.可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致
INSERT INTO beauty
VALUES(18,'张飞','男',NULL,'119',NULL,NULL);#2. 插入语句 方式二
/*
语法:
insert into 表名()
set 列名=值,列名=值,...(可以为null/有默认值的不写就行了)*/
#1.
INSERT INTO beauty
SET id=19,NAME='刘涛',phone='999';SELECT * FROM beauty
ORDER BY id DESC;#两种方式大pk
#1.方式1支持插入多行
INSERT INTO beauty
VALUES(18,'张飞','男',NULL,'119',NULL,NULL),
(19,'张飞','男',NULL,'119',NULL,NULL),
(20,'张飞','男',NULL,'119',NULL,NULL);#2.方式1支持子查询,方式2不支持
INSERT INTO beauty(id,NAME,phone)
SELECT 26,'宋健','11809866';INSERT INTO beauty(id,NAME,phone)
SELECT id+100,boyname,'11809866'
FROM boys WHERE id<3;#2.修改语句
/*
1.修改单表的记录[重点]
语法:update 表名               ①set 列=新值,列=新值,...   ③where 筛选条件;           ②2.修改多表的记录[扩充知识]
语法:update 表1 别名left/right/inner join 表2 别名on 连接条件set 表头=值,表头=值...where [筛选条件];*/
#1.修改单表的记录
#案例1:修改beauty表中姓唐的女神的电话为13899888899
UPDATE beauty SET phone='13899888899'
WHERE NAME LIKE '唐%';#案例2.修改boys表中的id号为2的名称改为张飞, 魅力值为10
UPDATE boys SET boyname='张飞',usercp='10'
WHERE id=2;SELECT * FROM boys
ORDER BY id DESC;#2.修改多表的记录
#案例1:修改张无忌的女朋友的手机号为114UPDATE boys bo#要修改的表
INNER JOIN beauty b#要连接的表
ON bo.id=b.boyfriend_id#确定表(生成虚拟表)
SET b.`phone`='114'#要修改的数据
WHERE bo.boyName='张无忌';#要修改的内容SELECT * FROM beauty;#查询被修改的内容#案例2:修改没有男朋友的女神的男朋友编号都为2号
UPDATE boys bo#找到男神表
INNER JOIN beauty b#连接女神表
ON bo.id=b.boyfriend_id#生成虚拟表
SET b.boyfriend_id=2#要修改的数据
WHERE bo.id IS NULL#要修改的项SELECT * FROM boys;#三.删除语句
/*
方式一:delete
语法:1..单表的删除[常用]delete from 表名
[where 筛选条件];2..多表的删除[补充了解知识]
sql 92语法:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;sql 99语法:
delete 表1的别名,表2的别名
from 表1 别名
inner/left/right join 表2 别名
on 连接条件
[where 筛选条件];方式二:truncate
语法:truncate table 表名;
*/#delete
#1.单表的删除
#案例1:删除手机号以9结尾的女神
DELETE#删除
FROM beauty#表
WHERE phone LIKE '%9';#要删除的内容SELECT *FROM beauty;#查询修改后的内容#2.多表的删除
#案例:删除张无忌的女朋友的信息
DELETE b,bo#要删除原生哪个表的信息
FROM beauty b#表一
INNER JOIN boys bo#内连接等值连接表二
ON b.boyfriend_id=bo.id#生成虚拟表
WHERE bo.`boyName`='张无忌';#要删除的内容#案例:删除黄晓明的信息以及他女朋友的信息
DELETE b,bo#要删除原生哪个表的信息
FROM beauty b#表一
INNER JOIN boys bo#内连接等值连接表二
ON b.boyfriend_id=bo.`id`#生成虚拟表
WHERE bo.`boyName`='黄晓明';#要删除的内容SELECT *
FROM beauty; #黄晓明对应id anglebaby 也没了
SELECT *
FROM boys;#黄晓明没了#方式二:truncate语句(不允许加WHERE以及连接条件)#案例:将魅力值>100的男神信息删除
TRUNCATE TABLE boys ;# 两种方式的 区别(常用) delete pk truncate[面试题]
/*
1.delete 可以加 where 筛选条件,TRUNCATE不能加
2.truncate 删除,效率高一丢丢
3.假如要删除的表中有自增长列,如果用delete删除后,再插入数据,自增长列的值从断点开始,而 truncate 删除后,在插入数据,自增长值从1开始
4.truncate删除没有返回值(共0行受到影响),delete删除有返回值(共几行受到影响)5.truncate删除不能回滚(事物的问题),delete删除可以回滚
*/SELECT * FROM boys;#查询boys表DELETE FROM boys;#删除boys表(断点自增)
TRUNCATE TABLE boys;#删除boys表(完全重置)INSERT INTO boys (boyName,usercp)#一次插入多行
VALUES('张飞',100),('刘备',100),('关羽',100);#1.运行以下脚本创建表my_employees
USE myemployees;
CREATE TABLE my_employees(#创建表 字段:字段值Id INT(10),First_name VARCHAR(10),Last_name VARCHAR(10),Userid VARCHAR(10),salary DOUBLE(10,2)
);CREATE TABLE users(#创建表 字段:字段值Id INT,Userid VARCHAR(10),department_id INT
);
#在`myemployees`下创建了`my_employees`和`users`两个空表#2. 显示表my_employees的结构
DESC my_employees;#查看某个表和降序同一个单词desc#3.向my_employees表中插入下列数据
/*
ID   FIRST_NAME   LAST_NAME    USERID   SALARY
1    patel         Ralph       Rpatel   895
2    Dancs         Betty       Bdancs   860
3    Biri      Ben         Bbiri    1100
4    Newman    Chad        Cnewman  750
5    Ropeburn      Audrey      Aropebur 1550
*/
#解:一
INSERT INTO my_employees#多行插入 默认对应所有表头
VALUES(1,'patel','Ralph','Rpatel',895),
(2,'Dancs','Betty','Bdancs',860),
(3,'Biri','Ben','Bbiri',1100),
(4,'Newman','Chad','Cnewman',750),
(5,'Ropeburn','Audrey','Aropebur',1550);
#解:二
INSERT INTO my_employees
#插入 联合查询结果(相当于多行插入)
SELECT 1,'patel','Ralph','Rpatel',895
UNION
SELECT 2,'Dancs','Betty','Bdancs',860
UNION
SELECT 3,'Biri','Ben','Bbiri',1100
UNION
SELECT 4,'Newman','Chad','Cnewman',750
UNION
SELECT 5,'Ropeburn','Audrey','Aropebur',1550;DELETE FROM my_employees;#删除表SELECT * FROM my_employees;#查看表#4.向users表中插入数据
/*
1   Rpatel   10
2   Bdancs   10
3   Bbiri    20
4   Cnewman  30
5   Aropebur 40
*/
INSERT INTO users#表插入(多行)数据
VALUES(1,'Rpatel',10),
(2,'Bdancs',10),
(3,'Bbiri',20),
(4,'Cnewman',30),
(5,'Aropebur',40);
#上面也能使用联合查询 插入 此处不再演示
SELECT * FROM users;#查询表#5.将3号员工的last_name修改为'drelxer'
UPDATE my_employees#修改表
SET last_name='drelxer'#修改的数据
WHERE id=3;#要修改的内容SELECT * FROM my_employees;#查询表#6.将所有工资少于900的员工的工资修改为1000
UPDATE my_employees#修改表
SET salary=1000#修改的数据
WHERE salary<900;#要修改的内容#7.将 userid 为 Bbiri 的 users 表和
#   my_employees 表的记录全部删除
DELETE m,u#要删除原生哪个表的信息
FROM users u#表一
INNER JOIN my_employees m#内连接等值连接表二
ON m.id=u.`id`#生成虚拟表
WHERE m.`userid`='Bbiri';#要删除的内容SELECT * FROM my_employees;#查询表
SELECT * FROM users;#查询表#8.删除所有数据
DELETE FROM my_employees;#删除表(不会重置断点)
DELETE FROM users;#删除表#9.检查所作的修正
SELECT * FROM my_employees;
SELECT * FROM users;#10.清空表 my_employees
TRUNCATE TABLE my_employees;#删除表(重置断点)#DDL
/*
数据定义语言库和表的管理(了解)一.库的管理
创建.修改,删除二.表的管理
创建,修改,删除创建: Create
修改: alter
删除: drop
*/#一.库的管理
#1.库的创建
/*
语法:
create database [if not exists] 库名 [character set 字符集名];
*/#案例:创建库Book
CREATE DATABASE books;
#创建库 mysql 不区分大小写
#但是 数据表的内容 字符串 应该是区分的
#创建库执行第二遍是会报错的(重名)CREATE DATABASE IF NOT EXISTS books;
#如果有那就别建了,如果没有那就创建上
#点评:这功能可有可无,报错不一样的效果#2.库的修改
/*
库一般不修改失效语句
rename database books to 新库名;
如果要修改库名
直接修改
c/programData/mysql/mysql server5.5/data/books
文件夹的名字 就是库名的名字sql语句只能修改库的字符集(数据库的编码)
alter database books character set
查看字符集 books/右键/改变数据库
默认utf8
*/
ALTER DATABASE books CHARACTER SET gbk;
#将字符集改为gbk如果是的你的之前的数据库没有设置好:对于已经存在了的数据库,可以如下操作使其改变编码方式:a. 修改MYSQL数据库编码,
如果是MYSQL数据库编码不正确:
可以在MYSQL执行如下命令: ALTER DATABASE test DEFAULT CHARACTER SET utf8;   以上命令就是将MYSQL的test数据库的编码设为utf8b. 修改MYSQL表的编码:ALTER TABLE category DEFAULT CHARACTER SET utf8; 以上命令就是将一个表category的编码改为utf8c. 修改字段的编码:
ALTER TABLE `test` CHANGE `dd` `dd` VARCHAR( 45 ) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL 以上命令就是将MYSQL数据库test表中 dd的字段编码改为utf8在命令行下插入汉字时如下代码:
set names gb2312;
有时候这一句很关键!insert into charset values('lmj');然后再重启服务就可以 了。如果出现无法启动服务的情况,
就以管理员身份运行cmd先进入到mysql安装目录下,
执行mysqld -remove
移除服务然后mysqld -install
安装服务就可以了#3.库的删除 DROP DATABASE [IF EXISTS] books;
DROP DATABASE books;
#删除名字为books的库
#重复删除会报错
DROP DATABASE IF EXISTS books;
#把重复删除会报错变成警告#二.表的管理
#1.表的创建(经常)
/*
语法:
create table 表名(列名 列的类型[(宽度) 约束],列名 列的类型[(宽度) 约束],列名 列的类型[(宽度) 约束],...列名 列的类型[(宽度) 约束])
*/
#案例:创建表Book
CREATE TABLE book(#创建空表表头id INT,#编号bname VARCHAR(20),#书名的最大长度price DOUBLE,#价格authorId INT,#作者编号publishDate DATETIME#出版日期);SELECT * FROM book;#查询表 表的内容列DESC book;#查看表 表头类型#案例:创建表author
CREATE TABLE author(
#CREATE TABLE if not exists author(id INT,au_name VARCHAR(20),#作者名的最大长度nation VARCHAR(20)#国籍名的最大长度); DESC author;#查看表 表头类型#2.修改表
/*
1.添加到最前面或者某个列的后面
alter table 表名
add column 列名 [列类型 约束]
[frist/(after 字段名)];2.修改列的类型或约束
alter table 表名
modify column 列名 新类型 [新约束]3.修改列名(可顺道改类型)
alter table 表名
change column 旧列名 新列名 [列类型 约束];4.删除列
alter table 表名
drop column 列名;5.修改表名
alter table 表名
rename [to] 新表名;
*//*alter table 表名
add/drop/modify/change column 列名 [列类型 约束];
新增/删除/修改/修改(全) 列
*/#①修改列名(表头)
ALTER TABLE book#要修改的表
CHANGE COLUMN publishdate pubDate DATETIME;
#      可省略 原列名(表头) 新名字 必须定义类型
#    仅CHANGE后
DESC book;#查看表 表头类型#②修改列的类型或约束#作者名的最大长度/默认值
ALTER TABLE book#要修改的表
MODIFY COLUMN pubDate TIMESTAMP;
#               列名   新类型
#            不区分大小写#③添加新列
ALTER TABLE author#要修改的表
ADD COLUMN annual DOUBLE;DESC author;#查看表 表头类型
#新增 列  列名(表头)#④删除列
ALTER TABLE author#要删除的表
DROP COLUMN annual;#要删除的列名
#此处不能使用 IF EXISTS 把报错变为警告#⑤修改表名
ALTER TABLE author#要修改的表
RENAME TO book_author;#为表重命名
#(之前说的是库重命名时有可能崩溃,这里是表)DESC book_author;#查看表 表头类型#3.删除表
/*
语法:
drop table [IF EXISTS] 表名;
*/
DROP TABLE book_author;DROP TABLE IF EXISTS book_author;
#删除表失败不报错,报警告
#仅仅在 创建/删除 库/表 时候有用
#IF EXISTS 在删除列是无效的
#if not exists 创表
SHOW TABLES;#查看当前库的所有表#通用的写法:(如果有数据不想被删掉不建议这么干)
#先删一遍再创建库
DROP DATABASE IF EXISTS 旧库名;
CREATE DATABASE 新库名;#先删一遍再创建表
DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 表名();#4.复制表/*
语法:1.复制表的结构create table 表名 like 旧表;2.复制表的结构+数据(可跨库 库.表 即可)create table 表名select 查询列表 from 旧表 [where 筛选]*/
INSERT INTO author#选中表插入多行数据
VALUES(1,'王小波','中国'),
(2,'道乾','中国'),
(3,'罗素','英国'),
(4,'李银河','中国');SELECT * FROM author;#查询表#1.仅仅复制表的结构不复制内容(名字为copy)
CREATE TABLE copy LIKE author;
SELECT * FROM copy;#查询表#2.完全复制(名字为copy2)
CREATE TABLE copy2#创建表copy2
SELECT * FROM author;
#数据来自查询author表的结果SELECT * FROM copy2;#查询表#部分复制(可复制任意查询结果的数据)
CREATE TABLE copy3#创建表copy3
SELECT id,au_name FROM author
#数据来自查询author表的结果
WHERE nation='中国';#仅仅复制某些字段(列名/表头)
CREATE TABLE copy4#创建表copy4
SELECT id,au_name FROM author
#数据来自查询author表的结果
WHERE 0;
#WHERE 1=2;
#由于设置了谁都不满足
#所以会返回一个只有表头的空表
#又由于表头是自己写的查询结果
#所以可以自由复制表的表头#题目
/*1.创建表dept1
name null  type
id          int(7)
name        varchar(25)
*/
USE test;
CREATE TABLE dept1(#创建表id INT(7),NAME VARCHAR(25));
SELECT * FROM dept1;#查询表#2.垮库 将表 departmentments 中的数据插入新表 dept2 中
CREATE TABLE dept2#创建表
SELECT department_id,department_name#要复制的表头
#from departments;#数据的来源
#由于 跨库了 执行以上语句会出现找不到的情况
# 需要添加非当前库的库名
FROM `myemployees`.departments;#数据的来源SELECT * FROM dept2;#查询表#3.创建表emp5
/*
name          unll?   type
id                    int(7)
first_name            varchar(25)
last_name             varchar(25)
Deptid                int(7)*/
CREATE TABLE emp5(#创建表id INT(7),first_name VARCHAR(25),last_name VARCHAR(25),Deptid INT(7)#表头  类型
);#4.将列last_name的长度增加到50
#修改 库中表的 表头和类型
ALTER TABLE emps
MODIFY COLUMN last_name VARCHAR(50);
#MODIFY修改类型
#change修改表头和类型#5.根据表 employees 创建 employees2
#复制表结构
CREATE TABLE employees2#创建表
LIKE `myemployees`.employees;#垮库获取表结构#6.删除表 emp5
DROP TABLE emp5;
#DROP TABLE if exists emp5;
#          如果 存在#7.将表 employees2 重命名为emps
#表重命名
ALTER TABLE employees2 RENAME TO emp5;
#表/库 名 使用中文在不同环境下可能乱码 维护困难#8.在表dept和emp5中添加新列test_column,
#并检查所做的操作
ALTER TABLE emp5#创建表
ADD COLUMN test_column INT(7);
#添加表头 必须写上类型(除非表设置了默认值)#9.直接删除表 emp5 中的列 department_idDESC emp5;#查看列ALTER TABLE emp5#要删除的表
DROP COLUMN department_id;3要删除的列#常见的数据类型
/*
数值型:整型:tinyint,smallint,mediumint,int/integer,bigint小数:定点数浮点数
字符型:较短的文本:char,varchar较长的文本:text,blob(较长的二进制数据(图片))日期型:*/
#一.整型
/*
分类:
tinyint,smallint,mediumint,int/integer,bigint
1        2            3     4               8(字节大小)特点:
① 如果不设置无符号还是有符号(负数),默认是有符号如果想设置无符号(正数),需要添加 unsigned 关键字②如果插入的数值超出了整型的范围,会提示警告并且插入最接近的临界值③如果不设置长度,会自带默认的长度长度代表了显示的最大宽度,搭配zerofill使用时如果不够会用0在左边填充并且默认变为无符号的整型*/#案例1.如何设置无符号和有符号
DROP TABLE IF EXISTS tab_int;
CREATE TABLE tab_int(#创建表t1 INT(7) ZEROFILL,#7代表不满7位数的使用0填充且#表头 类型         默认开启 UNSIGNED 不再支持负数符号-t2 INT UNSIGNED);DESC tab_int;#查看表头INSERT INTO tab_int VALUES(-123456);
INSERT INTO tab_int VALUES(-123789101456,-123789101456);
INSERT INTO tab_int VALUES(123789101456,123789101456);INSERT INTO tab_int VALUES(123,123);SELECT * FROM tab_int;#查询表内容#二.小数(浮点型)
/*
分类:1.浮点数
float(M,D)
double(M,D)2.定点数
dec(M,D)
decimal(M,D)特点:
①
M: 整数部位+小数部位
D: 小数部位
如果超过范围,则插入最接近的临界值②
M和D都可以省略
如果是 DECIMAL,则M默认为10,D默认为0
如果是 FLOAT/DOUBLE,则会根据插入的数值的精度来决定精度③定点型的精确度较高,如果要求插入数值的精度较高如货币运算等则考虑使用
*/
#测试M和DDROP TABLE tab_float;#删除表
CREATE TABLE tab_float(#创建表#f1 float(5,2),#共5位数且小数点保留两位  xxx.x0f1 FLOAT,f2 DOUBLE,f3 DECIMAL
);SELECT * FROM tab_float;#查询表
DESC tab_float;#查看表头INSERT INTO tab_float VALUES(123.45,123.45,123.45);
INSERT INTO tab_float VALUES(111423.456,123.456,123.456);
INSERT INTO tab_float VALUES(123.45,123.45,13.4);#原则:
/*
所选择的类型越简单越好,能保存数值的类型越小越好*/#三.字符型
/*
较短的文本
①char 固定长度的字符,写法为char(M),最大长度不能超过M其中M可以省略,默认为1
②varchar可变长度的字符写法为varchar(M)最大长度不能超过M其中M不可以省略其它:
③binary 和 ④varbinary 用于保存较短的二进制
⑤enum 用于保存枚举
⑥set 用于保存集合较长的文本:
⑦text
⑧biob(较大的二进制)特点:空间     效率   写法           M的意思            特点
char(比较耗费)    高   char(M)  最大的字符数(可省略默认为1)     固定长度的字符varchar(比较节省) 低  varchar(M)  最大的字符数(不可以省略)      可变长度的字符
*/CREATE TABLE tab_char(#创建表c1 ENUM('a','b','c')#这个表头 只能插入 a/b/c#enum 用于保存枚举);INSERT INTO tab_char VALUES('a');
INSERT INTO tab_char VALUES('b');
INSERT INTO tab_char VALUES('c');
INSERT INTO tab_char VALUES('m');#超出了ENUM列表值
INSERT INTO tab_char VALUES('A');SELECT * FROM tab_char;CREATE TABLE tab_set(#创建表s1 SET('a','b','c','d')#set 用于保存集合);
INSERT INTO tab_set VALUES('a');
INSERT INTO tab_set VALUES('A,b');
INSERT INTO tab_set VALUES('a,c,d');SELECT * FROM tab_set;#四.日期型/*分类:
date 只保存日期
time 只保存时间
year 只保存年datetime  保存日期加时间
TIMESTAMP 保存日期加时间区别
特点:       字节      范围       时区等的影响
DATETIME     8     1000-9999年   不受
TIMESTAMP    4     1970-2038年    受*/CREATE TABLE tab_date(#创建表t1 DATETIME,t2 TIMESTAMP#时间戳受时区和mysql版本影响);INSERT INTO tab_date#为表插入行数据
VALUES(NOW(),NOW());SELECT * FROM tab_date;SHOW VARIABLES LIKE 'time_zone';#显示时区SET time_zone='+9:00';#定义时区为东九区#常见约束 /*含义: 一种限制,用于限制表中的数据为了保证表中的数据的准确和可靠性分类:六大约束NOT NULL:非空,用于保证该字段的值不能为空比如姓名,学号等default:默认,用于保证该字段有默认值比如性别primary key:主键,用于保证该字段的值具有唯一性并且非空 比如学号,员工编号等unique:唯一,用于保证该字段的值具有唯一性可以为空,比如座位号check:检查约束[mysql中不支持(语法不报错但是没效果)]比如年龄,性别foreign key:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值在从表添加外键约束用于引用主表中某列的值比如学生表的专业编号,员工表的部门编号员工表的工种编号添加约束的时机:1.创建表时2.修改表时约束的添加分类:列级约束:六大约束语法上都支持,但外键约束没有效果表级约束:除了非空.默认,其它的都支持主键和唯一的大对比:保证唯一性 是否允许为空              一个表中可以有多少个 是否允许组合主键  √           ×(一列中不允许出现null)    至多一个            √,但不推荐唯一  √           √(一列中只能有一行为null)  可以有多个          √,但不推荐外键:1.要求在从表设置外键关系2.从表的外键列的类型和主表的关联列的类型要求一致名称无要求3.主表的关联列必须是一个key(一般是主键 或 唯一也行)4.插入数据时,先插入主表,再插入从表删除数据时,先删除从表,再删除主表insert into major values(1,'java');insert into major values(2,'h5');delete from stuinfo;#删除表的数据insert into stuinfo values(1,'john','男',null,19,1);insert into stuinfo values(1,'lily','男',null,19,2);DROP TABLE IF EXISTS major;#删除表头
CREATE TABLE major(#创建表id INT PRIMARY KEY,#主键majorName VARCHAR(20)#专业名称);DROP TABLE IF EXISTS stuinfo;#删除表CREATE TABLE stuinfo(#创建表id INT ,stuName VARCHAR(20) ,gender CHAR(1),seat INT ,age INT ,majorId INT,#PRIMARY KEY(id),#主键PRIMARY KEY(id,stuname),#这两个列组合成一个主键UNIQUE(seat,age),#组合唯一键#这两个组合只要有一个不同 即不会报错CHECK(gender='男' OR gender='女'),#检查约束FOREIGN KEY(majorid) REFERENCES major(id)#外键
);SHOW INDEX FROM stuinfo;#查看表的索引语法:CREATE TABLE 表名(字段名 字段类型 约束,字段名 字段类型,表级约束
)
*/#一.创建表时添加约束
#1.添加列级约束/*
语法:直接在字段名和类型后面追加 约束类型 即可
只支持:默认,非空,主键,唯一
不支持check 检查REFERENCES 外键
*/CREATE DATABASE students;#创建库
USE students;TRUNCATE TABLE major;#删除表(重置断点)CREATE TABLE stuinfo(#创建表id INT PRIMARY KEY,#主键#此处不只可以添加一个列级约束(主键除外 唯一除外) 可以添加多个 无顺序要求stuName VARCHAR(20) NOT NULL,#非空gender CHAR(1) CHECK(gender='男' OR gender='女'),#检查seat INT UNIQUE,#唯一age INT DEFAULT 18,#默认约束majorId INT REFERENCES major(id)#外键);DROP TABLE IF EXISTS major;
CREATE TABLE major(#创建表id INT PRIMARY KEY,#主键majorName VARCHAR(20)#专业名称);DESC stuinfo;#查看表头类型SHOW INDEX FROM stuinfo;
#查看索引 包括 主键 外键 唯一#2.添加表级约束/*语法:在各个字段的最下面
[constraint 约束名] 约束类型(字段名)
*/#通用的写法:(常用)CREATE TABLE IF NOT EXISTS stuinfo(id INT PRIMARY KEY,stuname VARCHAR(20) NOT NULL,sex CHAR(1),age INT DEFAULT 18,seat INT UNIQUE,majorid INT,CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键);#二.修改(关于修改表时添加的表头(列)约束)
/*1.添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束2.添加表级约束
alter table 表名 add [constraint 约束名] 约束类型(字段名) [外键的引用];*/DROP TABLE IF EXISTS stuinfo;#删除表
CREATE TABLE stuinfo(#创建表id INT ,stuName VARCHAR(20) ,gender CHAR(1),seat INT ,age INT ,majorId INT
);
#1.添加非空约束(为stuName加非空约束)
ALTER TABLE stuinfo
MODIFY COLUMN stuname
VARCHAR(20) NOT NULL;
#VARCHAR(20);#要改时 不写即可DESC stuinfo;#查看表头(列)约束#1.添加默认约束(为age加默认约束)
ALTER TABLE stuinfo
MODIFY COLUMN age
INT DEFAULT 18;#3.添加主键(只要支持列级约束的都可以这么写)
#①列级约束
ALTER TABLE stuinfo
MODIFY COLUMN id
INT PRIMARY KEY;
#或
#②表级约束 两种写法
ALTER TABLE stuinfo
ADD PRIMARY KEY(id);DESC stuinfo;#查看表头(列)约束#4.添加唯一键(seat表头)
#①列级约束
ALTER TABLE stuinfo
MODIFY COLUMN seat
INT UNIQUE;
#或
#②表级约束 两种写法
ALTER TABLE stuinfo
ADD UNIQUE(seat);#5.添加外键(只有列级 表级无效)表头majorid
ALTER TABLE stuinfo
ADD
#constraint fk_stuinfo_major
#可加名字(fk_stuinfo_major) 也可不加 不加则使用系统默认的名字
FOREIGN KEY(majorid)
REFERENCES major(id);DESC stuinfo;#查看表头(列)约束#三.修改表时删除约束#1.删除非空约束(整个表的约束不是表头)
ALTER TABLE stuinfo
MODIFY COLUMN stuname
VARCHAR(20) NULL;#可以不写null 默认就是null#2.删除默认约束(整个表的约束不是表头)
ALTER TABLE stuinfo
MODIFY COLUMN age INT;#3.删除主键(整个表的约束不是表头)
ALTER TABLE stuinfo DROP PRIMARY KEY;
#或
ALTER TABLE stuinfo MODIFY COLUMN id INT;#4.删除唯一(整个表的约束不是表头)
ALTER TABLE stuinfo DROP INDEX seat;SHOW INDEX FROM stuinfo;#查看索引#5.删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY majorId;#题目
#1.向表emp2的id列中添加 primary key 约束 (my_emp_id_pk)
ALTER TABLE emp2 MODIFY COLUMN id INT PRIMARY KEY;
#此处将主键添加到列级约束上(不支持起名字)ALTER TABLE emp2 ADD CONSTRAINT my_emp_id PRIMARY KEY(id);
#为表级约束添加主键 可起名字 但是没效果#2.向表dept2的id列中添加 primary key 约束 (my_empt_id_pk)
#同上#3.向表emp2中添加列 dept_id,并在其中定义 foreign key 约束
#  与之相关联的列是 dept2 表中的 id 列
ALTER TABLE emp2
ADD COLUMN dept_id
INT;ALTER TABLE emp2
ADD CONSTRAINT fk_emp_dept2
FOREIGN KEY(dept_id)
REFERENCES dept2(id);#      位置         支持的约束类型               是否可以起约束名
#列级约束:     列的后面      语法都支持,但外键没有效果     不可以
#表级约束:     所有列的下面  默认和非空不支持,其他都支持   可以(主键没有效果)
#                            检查约束谁都不支持#标识列
/*
又称为自增长列
含义:可以不用手动的插入值,系统提供默认的序列值(从1开始每次都增长1)特点:1.标识列必须和主键搭配吗?不一定,但要求是一个key(主键/唯一键UNIQUE)2.一个表中可以有几个标识列?至多一个!3.标识列的类型只能是数值型(int/float/douable)4.标识列可以通过 #SET auto_increment_increment=3;设置步长值还可以通过手动插入第一行数据的方法设置起始值
*/#一.创建表时设置标识列
DROP TABLE IF EXISTS tab_identity;#删除表(包括表头)CREATE TABLE tab_identity(#创建表id INT ,#id int unique auto_increment,#添加标识列 自动从1开始自增#name varchar(20) unique auto_increment,#name 无法作为自增列NAME FLOAT,seat INT#seat INT UNIQUE AUTO_INCREMENT#加两个自增长(报错)
);
TRUNCATE TABLE tab_identity;
#删除表的全部数据(除了表头)并重置标识自增断点INSERT INTO tab_identity
VALUES(NULL,'john');SELECT * FROM tab_identity;#查看表SHOW VARIABLES LIKE '%auto_increment%';
#展示 约束 类似 自增长的 约束#Variable_name                 Value
#auto_increment_increment   1  步长值 自增偏移量 设置有效
#auto_increment_offset          1         自增起始值 设置无效SET auto_increment_increment=3;
#重新设置标识的自增数步长 为3#二.修改表时设置标识列
ALTER TABLE tab_identity #选择表
MODIFY COLUMN id#表头
INT #数值型
PRIMARY KEY#主键
AUTO_INCREMENT;#标识自增#二.修改表时删除标识列
ALTER TABLE tab_identity #选择表
MODIFY COLUMN id#表头
INT #数值型
#PRIMARY KEY#主键#避免和上一个重复主键
;#去掉标识自增即可TRUNCATE TABLE tab_identity;
#删除表的全部数据(除了表头)并重置标识自增断点INSERT INTO tab_identity
VALUES(NULL,'john');SELECT * FROM tab_identity;#查看表SHOW VARIABLES LIKE '%auto_increment%';
#展示 约束 类似 自增长的 约束创建表时
COMMENT 注释 表头名字SELECT UNIX_TIMESTAMP();查询时间戳//开始 增删改查 实例
<?php
//1.连接 mysql
$a = @mysqli_connect('localhost', 'root', 'root', 'xinWen', 3306);
//             ip/dns域名  用户名  密码    数据库 端口号(默认)
// var_dump($a);
//连接成功 返回 object(mysqli)
//连接失败 语法报错 且返回 bool(false)// 使用@ 抑制 语法报错 (错误抑制符只对表达式有效)// 连接失败 专用函数 mysqli_connect_error()
// 可以返回 错误信息(英文)//2.设置字符编码
if (mysqli_connect_error()) { //如果有错echo '错误号 : ' . mysqli_connect_errno(), '<br>';echo '错误信息 : ' . mysqli_connect_error();
} else {//连接好了要设置字符编码mysqli_set_charset($a, 'utf8');echo '连接好了并设置字符编码为utf8';
}//等价写法 以上还能这么写 (效果是一致的)/*$a = @mysqli_connect('localhost', 'root', 'root', 'xinWen', 3306) or die('错误信息 : '.mysqli_connect_error());
mysqli_query($link,'SET NAMES utf8');
*/
//set names utf8指定了客户端和服务器之间传递字符的编码规则为UTF8。//3. 执行 mysql 语句//3.1 新增 插入行
$b = mysqli_query($a, "INSERT INTO news VALUES(NULL,'静夜思','窗前明月光',UNIX_TIMESTAMP());");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b != false) {echo  '<br>mysql语句 执行新增成功 新插入行自增id为' . mysqli_insert_id($a);// var_dump($b);//bool(true)} else {echo 'mysql语句 执行失败';var_dump($b);
}//3.2 修改 更新数据  把 id 为5 的 content 改为 凝似地上霜
$b2 = mysqli_query($a, "UPDATE news set content='凝似地上霜3'  where id=6; ");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b2 != false) {echo  '<br>mysql语句 执行修改成功 受影响的记录数为' . mysqli_affected_rows($a);// var_dump($b);//bool(true)} else {echo '<br>mysql语句 执行失败 错误代码' . mysqli_errno($a) . '<br>' . mysqli_error($a);//与上面 连接错误 是两个 函数 //错误结果展示: mysql语句 执行失败 错误代码1064//              Unknown column 'ids' in 'where clause'// var_dump($b2);//bool(false)
}//3.3 删除数据  把 id 为5 的 那一行数据删除
$b3 = mysqli_query($a, "DELETE FROM news where id=6; ");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b3 != false) {echo  '<br>mysql语句 执行删除成功 受影响的记录数为' . mysqli_affected_rows($a);// var_dump($b);//bool(true)} else {echo '<br>mysql语句 执行失败 错误代码' . mysqli_errno($a) . '<br>' . mysqli_error($a);//与上面 连接错误 是两个 函数 //错误结果展示: mysql语句 执行失败 错误代码1064//              Unknown column 'ids' in 'where clause'// var_dump($b2);//bool(false)
}//3.4 查询数据  查询 id 为9 的 那一行数据
$b4 = mysqli_query($a, "SELECT * FROM news ; ");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b4 != false) {echo  '<br>mysql语句 执行查询成功 查询结果为';// var_dump($b4); //查询的结果集(对象)echo '<pre>';//3.4.1 获取查询 结果集 为 索引数组print_r(mysqli_fetch_row($b4)); //获取查询 结果集 为 索引数组//只能一次获取一条print_r(mysqli_fetch_row($b4)); //获取查询 结果集 为 索引数组//第二次获取第二条//因此 的确可以 通过while 循环来做 直到 函数获取为空 跳出循环/**Array( 一条结果样例[0] => 9[1] => 静夜思[2] => 窗前明月光[3] => 1617955631) *///3.4.2 获取查询结果集  为关联数组echo '<pre>';print_r(mysqli_fetch_assoc($b4));//也是 只能一次获取一条//第二次获取第二条/**结果样例展示* Array([id] => 3[title1] => 静夜思[content] => 窗前明月光[createtime] => 1617954801)*///3.4.3 获取查询结果集  既有 关联数组 又有索引数组echo '<pre>';print_r(mysqli_fetch_array($b4));//还是 只能一次获取一条//第二次获取第二条/**结果样例展示* Array([0] => 5[id] => 5[1] => 静夜思[title1] => 静夜思[2] => 凝似地上霜3[content] => 凝似地上霜3[3] => 1617955114[createtime] => 1617955114)*///3.4.4 获取查询结果集   的 列和行echo '有几行' . mysqli_num_rows($b4) . '<br>';echo '有几列' . mysqli_num_fields($b4) . '<br>';/*** 结果样例展示* 有几行34* 有几列4(专业术语 指每一个表头)*///3.4.5 获取查询结果集  获取全部 数组(推荐 常用)echo '<pre>';print_r(mysqli_fetch_all($b4, MYSQLI_NUM)); //获取全部索引数组(默认)print_r(mysqli_fetch_all($b4, MYSQLI_ASSOC)); //获取全部关联数组print_r(mysqli_fetch_all($b4, MYSQLI_BOTH));//获取全部 索引和关联 数组 /*结果样例展示Array([0] => Array([0] => 7[1] => 静夜思[2] => 窗前明月光[3] => 1617955503)[1] => Array([0] => 8[1] => 静夜思[2] => 窗前明月光[3] => 1617955574)...[30] => Array([0] => 37[1] => 静夜思[2] => 窗前明月光[3] => 1618016159))*///  最终. 销毁 结果集(你就算不销毁计算机也会帮你销毁)mysqli_free_result($b4); //销毁 结果集mysqli_close($a); //关闭 连接数据库通道//(你就算不关闭计算机也会帮你关闭)
} else {echo '<br>mysql语句 执行失败 错误代码' . mysqli_errno($a) . '<br>' . mysqli_error($a);//与上面 连接错误 是两个 函数 //错误结果展示: mysql语句 执行失败 错误代码1064//              Unknown column 'ids' in 'where clause'// var_dump($b2);//bool(false)
}//3.2 修改 更新数据  把 id 为5 的 content 改为 凝似地上霜
$b2 = mysqli_query($a, "UPDATE news set content='凝似地上霜3'  where id=6; ");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b2 != false) {echo  '<br>mysql语句 执行修改成功 受影响的记录数为' . mysqli_affected_rows($a);// var_dump($b);//bool(true)} else {echo '<br>mysql语句 执行失败 错误代码' . mysqli_errno($a) . '<br>' . mysqli_error($a);//与上面 连接错误 是两个 函数 //错误结果展示: mysql语句 执行失败 错误代码1064//              Unknown column 'ids' in 'where clause'// var_dump($b2);//bool(false)
}//3.3 删除数据  把 id 为5 的 那一行数据删除
$b2 = mysqli_query($a, "DELETE FROM news where id=6; ");
//在php 中使用 mysql 插入一行测试数据// 失败 返回 false
// 成功 返回 true (例外: select,show,describe,explain 返回查询结果(对象))
if ($b2 != false) {echo  '<br>mysql语句 执行删除成功 受影响的记录数为' . mysqli_affected_rows($a);// var_dump($b);//bool(true)} else {echo '<br>mysql语句 执行失败 错误代码' . mysqli_errno($a) . '<br>' . mysqli_error($a);//与上面 连接错误 是两个 函数 //错误结果展示: mysql语句 执行失败 错误代码1064//              Unknown column 'ids' in 'where clause'// var_dump($b2);//bool(false)
}
?>
//结束 增删改查实例2.操作数据
增,删,改 语句没有结果集的返回需要手动查询
因此我们干脆
增,删,改  执行成功 返回true执行失败 返回false通常
我们通过
mysqli_query()
在php 中 执行 mysql 语句由于 增删改查都要连数据库
所以
我们
连接数据库的代码
最好封装到一个包含文件里面去在站点下 新建inc文件夹
在inc下创建 conn.php文件连接数据库的代码写在这里然后使用 包含
类似于 js 的import下面重复介绍前面的包含
require './2.php'; //路径错误 停止执行当前页面的 往后代码
和
include './2.php'; //路径错误 依旧执行当前页面的 往后代码require_once './2.PHP';
require_once './2.PHP';
//包含两次也只显示一次

mysql全套理解以及在php中的应用相关推荐

  1. 从《MySQL必知必会》中对MySQL的理解

    MySQL是一个开源的DBMS,是目前主流的关系型数据库DBMS之一.在<MySQL必知必会>中,作者通过简单实用的订单实例简而明要地介绍了MySQL,这里简单汇总. 查询 检索+过滤+排 ...

  2. mysql临时表的使用实例_MySQL中临时表的使用示例

    这两天事情稍微有点多,公众号也停止更新了几天,结果有读者催更了,也是,说明还是有人关注,利己及人,挺好. 今天分享的内容是MySQL中的临时表,对于临时表,之前我其实没有过多的研究,只是知道MySQL ...

  3. kettle增加字段报错_【实战】使用 Kettle 工具将 mysql 数据增量导入到 MongoDB 中

    每一个成功人士的背后,必定曾经做出过勇敢而又孤独的决定. 放弃不难,但坚持很酷~ 最近有一个将 mysql 数据导入到 MongoDB 中的需求,打算使用 Kettle 工具实现.本文章记录了数据导入 ...

  4. Mysql基础代码(不断完善中)

    Mysql基础代码,不断完善中~ /* 启动MySQL */ net start mysql/* 连接与断开服务器 */ mysql -h 地址 -P 端口 -u 用户名 -p 密码/* 跳过权限验证 ...

  5. 《PHP与MySQL程序设计(第四版)》中第73页4.2.6节分期还贷计算器数学原理分析

    -----------------------------<PHP与MySQL程序设计(第四版)>中第73页4.2.6节分期还贷计算器数学原理分析. <PHP与MySQL程序设计(第 ...

  6. MySQL——深入理解

    前言 MySQL--深入理解主要包括MySQL的存储引擎.索引以及索引对数据库操作的性能优化.SQL优化.视图.存储过程.存储函数.触发器.锁.innoDB引擎的结构原理和数据库的相关管理操作.在这篇 ...

  7. mysql日期隐式转换_mysql中的隐式转换

    什么隐式类型转换? 在MySQL中: 当操作符与不同类型的操作数一起使用时,会发生类型转换以使操作数兼容.则会发生转换隐式 也就是说,MySQL会根据需要自动将数字转换为字符串,将字符串转换数字.看到 ...

  8. 理解YOLOv2训练过程中输出参数含义

    转载自https://blog.csdn.net/dcrmg/article/details/78565440 原英文地址: https://timebutt.github.io/static/und ...

  9. mysql去除select换行符_MySQL中去除字段中的回车符和换行符

    问题: 在使用[ load data infile 'D:/node.txt' into table node fields terminated by '\t'; ]语句批量导入如下图所示的aaa. ...

最新文章

  1. 利用Python绘制萌萌哒的皮卡丘
  2. mfc倾斜文本输入_文本检测知识梳理(持续更新)
  3. [ARC062F]Painting Graphs with AtCoDeer
  4. 解决magento保存产品时耗时很长的问题
  5. docker 安装elasticsearch
  6. MySQL笔记——多表查询
  7. 八个被现代科学证实的古老信条
  8. pe怎么删除linux文件夹,PE环境下,面对无法删除的文件夹怎么办?
  9. Linux之动态网页——搭建博客
  10. 老大:用脚本实现Nginx日志每天切分的功能?我:脱了裤子放屁!
  11. P2525 Uim的情人节礼物·其之壱 prev_permutaion
  12. 360浏览器集成IE8内核
  13. (2)公众号开发-基础框架搭建
  14. 提升手机麦克风音量_安卓手机音量调整办法(听筒、话筒、扬声器)
  15. python统计字符串个数_python实现字符串中字符分类及个数统计
  16. Outlook的服务器设置中POP3协议,在outlook的服务器设置中POP3协议是指
  17. C1能力认证训练题解析 _ 第一部分 _ 计算机通识
  18. 端午百望山爬山活动-金山词霸运营团队活动
  19. 初出茅庐的SwapX为何可以对垒Uniswap?
  20. git 查看远程分支、本地分支、创建分支、把分支推到远程repository、删除本地分支

热门文章

  1. 在家如何用手机赚钱,小编来为你一一解答!
  2. 数字图像与机器视觉基础补充(2)--颜色转换+分割车牌
  3. 前端40+精选VSCode插件
  4. [转]结合php5与zend_search_lucene来创建一个全文搜索引擎
  5. Arty A7-100(XC7A100TCSG324)开箱照
  6. 白鹭引擎开发微信小游戏新手教程文档
  7. 2021漳州一中历年高考成绩查询,2021年漳州中考录取分数线,历年漳州各高中录取分数线排名...
  8. windows10删除多余顽固输入法
  9. python bug
  10. 小米玩机------MIUI里那些你可能不知道的冷知识