mysql数据库学习笔记 (汇总)

mysql数据库学习整理

登录数据库

mysql -u用户名 -p密码
查看数据库 注意以分号结尾
show databases;
#显示所有数据库,(#是mysql注释的符号)


_____________________________________________________________________________________

SQL概述

SQL(Structural query language) 结构化查询语言,用于操作数据库
SQL学习的三条主线

#SQL的学习分为如下的三部分:
#DML :数据操纵语言  ---> INSERT / DELETE / UPDATE / SELECT  ----增删改查
#DDL :数据定义语言  ---> CRAETE(加一个列) / ALTER (修改)/ DROP(删除) / TRUNCATE (清空)/ RENAME(重命名)
#DCL :数据控制语言  ---> COMMIT 提交数据) / ROLLBACK(回滚操作) / GRANT / REVOKE
#说到数据库,习惯上提到增删改查,数据库的增删改比较简单,查询比较难一些
#数据量大可以用limit分页显示,比如:查询五百条数据,十条十条显示

_____________________________________________________________________________________

查询

基本的SELECT语句;

elect 查询的列  from 查询的表`
show databases;
use test1
#有些字段为 null  和java的null是一个意思就是没有赋值的意思,NULL和0是两个概念
select  name myname , age as myage
from myname

#为查询后表的字段指定别名 可用 字段名 别名 的形式
#或者  字段名  as 别名 的形式

#注意所有"," 全都是半角的
#如果列的别名中想要包含空格 则用"别 名"或’别 名’引起来
#规范里要求用双引号,mysql里不严格 oracle数据库里必须是双引号

SELECT hid H_ID,gname AS "GAME NAME"
FROM girl;    

#查询所有的数据库
SHOW DATABASES;
#使用指定的数据库
USE test1;

#基本的查询操作,查哪个列,哪些列

SELECT hid,gname #要查询字段
FROM girl;             #要查询的表

查询的快捷键是F9
查询此表中的全部的列
SELECT *
FROM girl;

#列的别名
#可以使用一对""包裹别名

SELECT hid 'H ID',gname AS "游戏  昵称"
FROM girl;     

#三类常见的数据类型:

#1数值型,java的整型浮点型
#2字符型/字符串型,姓名,街道,省份 没有严格要求说字符就是一个,字符串就是多个
#3日期型
#除此以外还有很多
#日期型和字符型变量。要使用一对 单引号来引用,只能在单引号中出现
#双引号是给列起别名是使用

#显示表结构
#对应改变表
#显示字段名 数据类型 是否为空 key default extra字段属性
#图形化界面相当于选中表以后,右键,改变表

DESC girl;

#命令行显示表结构
#或者使用命令全称
DESCRIBE girl;

比较运算

操作符       含义
=           等于(不是==)
>           大于
>=          大于、等于
<           小于
<=          小于、等于
<>          不等于(也可以是!=)

重点 : 赋值使用 :=符号

#其他比较运算符

操作符                 含义
BETWEEN           在两个值之间(包含边界)
... AND ... 

IN(set)                等于值列表中的一个
LIKE                   模糊查询
IS NULL              空值

在sqlyog中将光标定位在某个查询语句上,就可以执行当前的查询
sql 中的字符理解成字符串

逻辑运算
操作符        含义
AND           逻辑并 (且)
OR            逻辑或 (或)
NOT           逻辑否 (非)

#mysql 刚安装完初始化的数据库有4个
#比较关键的是mysql 这里放的是系统相关的表
#用户名,密码都在这里,密码是加密过的


_____________________________________________________________________________________

过滤和排序数据

#1 过滤 2 排序
#查询 test1 数据库中表 goods 中所有cat_id 是8的信息,并返回

SELECT *
FROM goods
#过滤数据
WHERE cat_id=8;
#查询shop_price > 60的货物
SELECT goods_name,cat_id,shop_price
FROM goods
#WHERE (shop_price > 3000 or shop_price < 2000) ;
WHERE shop_price != 1000;

#between …and … (在两个值之间,包含边界)

SELECT  *
FROM    goods
#where   shop_price between 2000 and 3000;
WHERE   shop_price BETWEEN 3000 AND 2000;
#包含边界时用between and 比较方便,不包含时还是使用 >=之类的操作符比较简单

#in (set ) :取值为()中的任一个

SELECT *
FROM  goods
#where shop_price=2000 or shop_price=2500 or shop_price=3000;
WHERE  shop_price IN( 2000,2500,3000 );

#like :模糊查询 查询goods表 goods_name 包含a的数据

SELECT *
FROM goods
#where goods_name like '%p%e%' or goods_name LIKE '%e%p%'; 

#此处谁like 要写全 写具体
#%号代表0个或多个字符
#oracle 在单引号引的里边是区分大小写的
#WHERE goods_name LIKE ‘%p%’ and goods_name LIKE ‘%e%’;
#查询goods_name 第二个字符是a的数据
WHERE goods_name LIKE ‘_d%’; #mysql 中 _是占位符,一个下划线代表一个字符’___d%'第四个字符是d
#什么字符都可以,任意一个字符
#查询第二个字符是
,且第三个字符是a的数据

#转义字符 \

SELECT *
FROM  girl
#where gname like '%\_%女';

WHERE gname LIKE '%_%女' ESCAPE '_';
#ESCAPE '_' 是指定转义字符的意思,所以转义有两种方法

#is null :空值
#is not null :非空值

SELECT *
FROM girl
WHERE gname IS NOT NULL;

SELECT goods_name, goods_id,market_price,goods_number , (market_price * goods_number) AS '可得销售总额'
#指定一个新列,字段为总额,内容是乘积
#凡是null值参与运算,结果都是null,应该明白,null就是null 不等同于0,如果想把null 当成0 可以用函数来实现
FROM goods;

#排序 分组 order by

SELECT *
FROM goods
#Order By market_price;
#Order by 默认按升序排序
#也可以自己指定排序方式
#ASC  : 升序 (ascend) 也可以省略不写
#Desc : 降序 (descend)
ORDER BY market_price DESC;
#如果想在排序的同时做一些过滤操作,那么 where 不能乱放,不能放在order by 的后边
#where通常和from 挨着,
#from后边紧跟着where,order by 写的时候通常写在查询语句的最后
#查询 goods_number >10 的 market_price 降序之后的数据
SELECT *
FROM goods
WHERE goods_number>10
ORDER BY market_price DESC;

#二级排序

SELECT *
FROM goods
WHERE goods_number>10
ORDER BY market_price DESC,click_count;
#如果一级排序结果比较多,那么就可以指定二级,三级,n级排序
#就在原先的排序条件后加 ,条件即可

#可以使用别名排序

SELECT goods_name AS GOODSNAME #指定别名
FROM goods
WHERE goods_number>10
ORDER BY  GOODSNAME;           #按别名排序


_____________________________________________________________________________________

多表查询

#实现多个表之间的查询
#涉及到多个表连接
#多表连接,多表查询
#为什么不把所有信息都放一张表里,乱,杂,管理起来不方便,如同java中类

#create database 学生信息;
USE 学生信息;
SELECT 姓名,对应地址
FROM  基本信息,区域表;#30行 6*5=30

#以上查询是错误的,称这种错误为:笛卡尔集错误。
#没有写两个表的连接条件,或写条件了,但失效了
#如果多表连接中,没有声明多表连接条件或连接条件失效。
#直角坐标系,又叫笛卡尔坐标系

SELECT 30/6
FROM DUAL;
#dual是虚拟表

#正确的,多表连接,一定会有连接条件

USE 学生信息;
SELECT 姓名,对应地址
FROM  基本信息,区域表
#连接条件
WHERE 基本信息.`区域编号`= 区域表.`区域编号`;
#关联的语法是  表1.字段名=表2.字段名,如果两个字段名相同,则关联成功
#满足连接条件的显示出来了,

#错误示范

USE 学生信息;
SELECT 姓名,对应地址,区域编号#此时这个区域编号是基本信息表里的呢,还是区域表里的呢
#产生了二义性,所以报错ambiguous,此时的解决办法是指定具体的表
#用表.区域编号来表示
#select 后边的两个字段 姓名和对应地址都唯一的存在对应的两个表中,很好查找
#如果查询的列在多个表中都出现
#则一定要指明此列所属的表
#最好是查询时每一列都指明表,
#从SQL优化的角度说,指定所属表的字段效率比较高
#mysql高级课中有优化等其他操作
FROM  基本信息,区域表
WHERE 基本信息.`区域编号`= 区域表.`区域编号`;
#ambiguous  不确定的模糊的

#表的别名

USE 学生信息;
SELECT e.姓名    , d.对应地址
FROM  基本信息 AS e ,区域表 d
#连接条件
WHERE e.`区域编号`= d.`区域编号`;
#如果指定别名则用别名操作,不能用原有名称操作,指定别名也可用AS
#列的别名只能使用在 order by,其他地方不好使
#所以说列的别名只能用来排序,不能用来过滤

#查询具体地址操作三个表

SELECT e.姓名    , d.`区域编号` ,f.具体地址

FROM 基本信息 AS e  , 区域表 AS d , 地址表 AS f

WHERE e.`区域编号`=d.`区域编号`
AND  d.`地址编号`=f.`地址编号`;
#三个表写两个连接条件
#等值连接,两个表必须有共同字段

#总结1:如果有N个表做查询操作,那么连接条件至少有N-1个
#总结2:表的连接分类

#等值连接                   VS   非等值连接
#自连接(自己连接自己)      VS   非自连接(自己连接别人)
#内连接                     VS   外连接

#非等值连接基本信息

SELECT 基本信息.`姓名`,基本信息.`年龄`,工资等级.`等级`
FROM 基本信息,工资等级
#where  基本信息.`工资`>=工资等级.`从` and 基本信息.工资<=工资等级.到;
#协程between  and 比较清晰
WHERE   基本信息.工资 BETWEEN 工资等级.从 AND 工资等级.`到`
#查询完对结果工资等级进行降序排序
ORDER BY 工资等级.`等级` DESC;

#以上写的都是非自连接

#自连接(自己连接自己)
#查询 每个员工及其管理者的信息

SELECT emp.工号 ,emp.`姓名`   , mgr.`工号`,mgr.`姓名`
FROM  基本信息 emp , 基本信息 mgr
#操作两个表,实质是一个表
WHERE  emp.`上司工号`=mgr.`工号`;
#查询完输出顺序发生了改变
#这是个没用的例子
SELECT 基本信息.`工号`,基本信息.`上司工号`
FROM 基本信息;

#内连接:内连接: 合并具有同一列的两个以上的表的行
#结果集中不包含一个表与另一个表不匹配的行
#内连接:只查询连接条件能匹配的行的信息,
#结果集中不包含不匹配的行

USE 学生信息;
SELECT e.姓名    , d.`地址编号`
FROM  基本信息 AS e ,区域表 d
#连接条件
WHERE e.`区域编号`= d.`区域编号`;
#此表中 贝贝的区域编号为空,所以被过滤掉了

#外连接: 两个表在连接过程中除了返回满足连接条件的行
#以外还返回左(或右)表中不满足条件的行 ,
#这种连接称为左(或右) 外连接。没有匹配的行时,
#结果表中相应的列为空(NULL).

#外连接
#左外连接 :除了能查询到满足连接条件能匹配的信息行之外,还能查到左表中不满足条件的信息
#右外连接 :除了能查询到满足连接条件能匹配的信息行之外,还能查到右表中不满足条件的信息
#外连接查询到数据的数量要大于等于内连接查询到的数据的数量

#USE 学生信息;
#SELECT e.姓名    , d.`地址编号`
#FROM  基本信息 AS e ,区域表 d
#连接条件
#WHERE e.`区域编号`= d.`区域编号`(+); #使左右表长度一样
#oracle比较简单,加个+就表示左外连接,而mysql不能实现

#查询所有员工的姓名,地址编号(有人地址编号为空)

#mysql 外连接只能借助join on,其他连接,join on 和 where都可以
#sql 99的语法,规定了另一种方式,实现多表的连接
#内连接
SELECT e.姓名    , d.`地址编号`
FROM  基本信息 e JOIN  区域表 d
#连接条件
ON e.`区域编号`=d.`区域编号`;


SELECT 工号`区域表`,姓名,地址编号
FROM 基本信息 j JOIN 区域表 q  #加入一个表
ON j.`区域编号` = q.`区域编号`;  #连接条件
#where....如果还有过滤条件加where

#三个表的内连接

SELECT 工号`区域表`,姓名,q.地址编号
FROM 基本信息 j JOIN 区域表 q  #加入一个表
ON j.`区域编号` = q.`区域编号`  #连接条件
JOIN 地址表 AS l
ON q.`地址编号`=l.`地址编号`;
#join
#on    多个表就 一直join on 下去

#加入INNER 关键字,同样表示内连接
SELECT 工号`区域表`,姓名,q.地址编号
FROM 基本信息 j INNER JOIN 区域表 q  
ON j.`区域编号` = q.`区域编号`  #连接条件
JOIN 地址表 AS l
ON q.`地址编号`=l.`地址编号`;

#使用sql 99语法实现外连接

#在 JOIN 的左侧加入 LEFT OUTER 叫左外连接
SELECT 工号`区域表`,姓名,地址编号,q.`区域特色`
FROM 基本信息 j LEFT OUTER JOIN 区域表 q  #加入一个表
ON j.`区域编号` = q.`区域编号`;  #连接条件
#where....如果还有过滤条件加where
#列出左表的全部信息

#右外连接

SELECT 工号`区域表`,姓名,地`区域表`址编号,q.`区域特色`
FROM 基本信息 j RIGHT OUTER JOIN 区域表 q  #加入一个表
ON j.`区域编号` = q.`区域编号`;  #连接条件
#where....如果还有过滤条件加where
#把两个表匹配的信息列出来后,把右表中不满足条件的也列出来
#相当于列出右侧表的全部信息
#即包含左表不满足的,又包含右表不满足的
#满外连接:除了查询到满足连接条件能匹配的行的信息之外,
#还能查询到左表和右表中不满足条件的信息。
#oracle支持满外连接。使用full关键字实现,mysql不支持
#mysql 如果想实现同样的功能,只能多个表去求unio,并
#SELECT 工号`区域表`,姓名,地`区域表`址编号,q.`区域特色`
#FROM 基本信息 j full OUTER JOIN 区域表 q  #加入一个表
#ON j.`区域编号` = q.`区域编号`;  #连接条件

SELECT 工号`区域表`,姓名,地`区域表`址编号,q.`区域特色`
FROM 基本信息 j RIGHT OUTER JOIN 区域表 q  #加入一个表
ON j.`区域编号` = q.`区域编号`;  #连接条件

_____________________________________________________________________________________

函数

#单行函数
#sql 类似于java 中的方法
#y=f(x1,x2…n)
#单行函数:一个输入一个输出的函数叫单行函数
#多行函数:多个输入一个输出的函数叫多行函数
#行 : 表中的一行数据
#进去一行出来一行,就是单行函数
#进去多行,出来一行,就是多行函数 进去多个工资,出来一个最高的
#单行函数 操作数据对象
#单行函数
#数据库对象:表(table) 视图(view)索引(index)
#序列(sequence) 函数(FUNCTION) 存储过程(PROCEDURE) 触发器(trigger)
#像java 类一样
#视图:不同于表,视图修改对应数据,会更新源数据
#索引:为了快速查找,表中数据达到几十万条,快速找到想要的,可以为表创建索引
#序列:添加数据时,让序列自动添加,每次隔着几个数,比如 1 3 5 7
#函数,类似于java无返回值的方法
#存储过程,类似于java有返回值的方法
#触发器:做如下类似的操作,删除数据时每删除一条触发一条,可以用作复制,备份
#工作中 不是做DBA 所以不用深究函数这三个结构

#单行函数
mysql数据库学习笔记 (汇总)_第1张图片
#操作数据对象
#接受参数返回一个结果

#字符函数

mysql数据库学习笔记 (汇总)_第2张图片

SELECT 'hello','heLLo',LOWER('heLLo'),UPPER('hello')
FROM DUAL; #没有存在任何表中就写一个DUAL
USE 基本信息;
SELECT *
FROM  基本信息
WHERE  LOWER(姓名) = LOWER('KING');#假如数据库是时小写的
#sql 标准严格字符区分大小写  mysql 并没有这么严格,忽略了大小写
SELECT CONCAT('AAA','bbb','ccc')
FROM DUAL;

#xxx worked for xxx

SELECT CONCAT(emp.`姓名`  ,' worked for ' , mgr.`姓名`) AS '工作信息'
FROM  基本信息 emp , 基本信息 mgr

#操作两个表,实质是一个表
WHERE  emp.`上司工号`=mgr.`工号`;

#该方法特点是 从第二个参数开始,取第三个参数长度的子串

SELECT SUBSTR('HelloWorld',2,5)#mysql 索引位置是从1 开始的
#java JDBC操作数据库,一些api中的数据库索引也是从1开始
FROM DUAL;
#LENGTH()  长度
#INSTR()   字符在串中首次出现的位置,没有出现则输出0
#LPAD()
SELECT INSTR('helloworld','l')
FROM DUAL;#3
#LPAD("he",10,' ') 右对齐 十位,不足补' '
#RPAD('he',10,' ')左对齐
#TRIM('h' FROM 'helloh' ) 取什么都可以,这里去了收尾的h
FROM DUAL;
SELECT TRIM(' ' FROM 'helloh')
FROM DUAL;

#REPLACE('abcd','b','m') 替换了,全部被替换

#数学函数

SELECT ROUND(12.345,0),ROUND(12.345,2),ROUND(12.34,-1)
FROM DUAL;
#ROUND 四舍五入 第三个参数是-1时,结果是10  2被四舍五入了
#第三个参数如果是0可以去掉,是默认行为
SELECT TRUNCATE(12.345,0),TRUNCATE(12.345,2),TRUNCATE(12.34,-1)
FROM DUAL;
#truncate()是截断  以上结果分别为 12  12.34  10
#MOD(12,5) 求余可以有正负情况
SELECT MOD(12,7),MOD(-12,7),MOD(12,-7),MOD(-12,-7),MOD(12.3,3)
FROM DUAL;
#以上结果 5 -5 5 -5 0.3

#日期函数

#函数now() 返回:日期,时间
SELECT NOW() , DATE(NOW()),
TIME(NOW()),SECOND(NOW()),MINUTE(NOW()),HOUR(NOW()),
DAY(NOW()),MONTH(NOW()) , YEAR(NOW())
FROM DUAL;

#通用函数

SELECT (goods_price*IFNULL(goods_number,0))
#ifNULL(expr1,expr2) 如果第一个参数是0,那么就拿第二个参数替换第一个参数
FROM DUAL;
#oracle  使用的是nvl替换

#条件表达式

#case WHEN then then then else end

#查询所有员工信息,
#若其年龄 打印其工资的10倍
#若其年龄 打印其工资的20倍
#若其年 打印其工资的30倍
#若是其他年龄 打印其工资

#格式如下:

SELECT 工号,工资,CASE 年龄 WHEN 10 THEN 工资*10
                           WHEN 20 THEN 工资*20
                           WHEN 30 THEN 工资*30
                           ELSE 工资 END AS '新工资'
FROM  基本信息; #可以没有ELSE
#where 。。。 可以指定where过滤
#case when then 之间没有任何标点

#多行函数(分组函数)
#比如查询工资最大值
#常用分组函数:avg() sum() max() min() count()
#avg() sum() 只针对数值型变量操作,其他类型不可以
#不可以操作字符型,日期型变量

#求工资平均值,和

SELECT AVG(工资) ,SUM(工资)
FROM 基本信息;
#mysql 对某些无意义操纵不报错,这一点oracle做的比较好

#max() , min() 针对数值型,字符型,日期型操作

SELECT MAX(工资),MIN(工资),MAX(姓名) , MIN(姓名)
FROM 基本信息;

#count() 计算指定列数据中非空数据的个数

SELECT COUNT(姓名) ,COUNT(NULL),COUNT(1),COUNT(*)#1取出一条数据看看是不是NULL,
FROM 基本信息;
#avg=sum/count   他们求的都是非空数据不考虑控制
SELECT AVG(工资) , SUM(工资), SUM(工资)/COUNT(工资)
FROM 基本信息;
#sum(工资)/count(*) ,AVG(IFNULL(工资,0))
#group by 实现对各个部门进行分组计算各个组的平均工资
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id;#按组id进行分组求平均
#比如国家计算我国各个行业的平均工资是多少
#学校计算每个院系收的总学费是多少
#group by 指定要分组的列即可
SELECT COUNT(姓名),区域编号#求各个区域的人数
FROM 基本信息
GROUP BY 区域编号;
#不同部门,不同工种的平均工资
SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;
SELECT department_id,AVG(salary)
FROM employees
###这种写法即使能出来数据,但不是正确的
###没有什么意义 mysql这么写不报错,oracle 会报错
#凡是在select 中,有组函数 也有非组函数
#要求,非组函数一定要出现在我们的group by当中

#错误的

SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id;

#正确的:反之,出现在group by中的列可以不声明在select中。

SELECT department_id,AVG(salary)
FROM employees
GROUP BY department_id,job_id;

#在select 中有组函数和非组函数的列,那么非组函数的列一定要在group by 中声明
#进行这组操作

#having
#非法使用组函数
#部门最高工资比10000高的部门

SELECT department_id,MAX(salary)
FROM employees
#where max(salary)>10000
#出错了,凡是在过滤条件中,使用组函数的话,那么需要使用
#having 替换掉where
GROUP BY department_id;

#orcale这样写可以,但是mysql不行

SELECT department_id,MAX(salary)
FROM employees
HAVING MAX(salary) >10000
GROUP BY department_id;

#mysql要求把having声明在group by的 后边,oracle没有此要求

SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) >10000;

#查询 10 20 30 40 50部门中,哪些部门的最高工资比10000高
#效率低

SELECT department_id,MAX(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) >10000 AND department_id IN (10 ,20 , 30 , 40 ,50);
#这种写法不会报错,但是不建议这么写
#如果有多个过滤条件,必须将分组函数的过滤条件写在having中。
#另外,不包含组函数的过滤条件建议写在where中。因为写在where中效率更高

#sql优化,效率高

SELECT department_id,MAX(salary)
FROM employees
WHERE department_id IN (10 ,20 , 30 , 40 ,50)
#where在全表检索的时候就已经开始过滤
#having 全表检索完以后才开始过滤,效率低。
GROUP BY department_id
HAVING MAX(salary) >10000 ;

#总结:
#至此,关于关键字的使用在select中就已经结束了

#select 。。。。。,。。。。。,。。。。。别名
#from  。。。,。。。,。。。。 join 。。。。。
#on 。。。。。。。。。。。。。
#join 。。。。。。。。。。。。
#where  多表的连接条件
#and 非组函数的过滤条件
#group by 。。。。。。。。。
#having 。。。。。。。。。。
#order 。。。。。。。。。。。
#limit  。。。。。。。。。。。 分页

_____________________________________________________________________________________

子查询

#子查询,就是嵌套select ,嵌套多层,有时可以优化
#谁的工资比 张三高
#方式一:
#多次查询

USE 学生信息;
SELECT 姓名,工资
FROM 基本信息
WHERE 姓名='张三';


SELECT 姓名,工资
FROM 基本信息
WHERE 工资 > 1034;

#方式二:
#自连接
#并不是所有问题都是自连接都能解决的

SELECT j2.`姓名`,j2.`工资`
FROM 基本信息 AS j1, 基本信息 AS j2
WHERE j1.`姓名`='张三'
AND   j1.工资

#方式三
#子查询
#在java jdbc 调用服务器后台数据库时,力求
#简洁,能一次做完的事情,绝不分成两次做完。


SELECT 姓名,工资
FROM 基本信息
WHERE 工资 > (
             SELECT 工资 #不能写多余的信息
             FROM 基本信息
             WHERE 姓名='张三'
             );

#两个以上嵌套的查询都叫子查询

SELECT 姓名,工资
FROM 基本信息
WHERE       (
             SELECT 工资 #不能写多余的信息
             FROM 基本信息
             WHERE 姓名='张三'
             )<工资;
#也可以这么写,但是看着很别扭
#一般都是把轻量级的变量放在where 位置

#子查询分类
#单行子查询:返回一行查询记录

SELECT 姓名,工资
FROM 基本信息
WHERE       (

             SELECT 工资 #不能写多余的信息
             FROM 基本信息
             WHERE 姓名='张三'

             )<工资;

#由内向外
#多行子查询:返回多行查询记录

#返回 基本信息表中区域编号和斯蒂文相同,
#工资比小倩多的员工的姓名,工号,和工资
#解决方式,1 从外往里写, 2 从里往外写

SELECT 姓名,工号,工资
FROM 基本信息
WHERE 区域编号=(
                SELECT 区域编号
                FROM 基本信息
                WHERE 姓名='斯蒂文'
               ) 
 AND   
     工资>(
         SELECT 工资
         FROM 基本信息
         WHERE 姓名='小倩'
          );

#一般来讲 从里往外写 比较简单一些
#从外往里写,不可以测试

#返回公司工资最少的员工的姓名,工号,工资

SELECT 姓名,工号,工资
FROM  基本信息
WHERE  工资=
            (
            SELECT MIN(工资)
            FROM 基本信息
            );

#返回公司工资第二少的员工的姓名,工号,工资

SELECT 姓名,工号,工资
FROM  基本信息
WHERE  工资=(
     SELECT MIN(工资)
     FROM 基本信息
     WHERE 工资>(
              SELECT MIN(工资)
              FROM 基本信息
            )
            );
           

#自查询中带有having

#查询最低工资大于60号部门最低工资的部门id和其最低工资

SELECT department_id ,MIN(salary)
FROM empoyees
GROUP BY department_id
HAVING MIN(salary)>(
                    SELECT MIN(salary)
                    FROM employees
                    WHERE department_id=60
                    )
AND department_id IS NOT NULL;

#看的时候也由内往外看,说的时候从外往里说
#要学会英汉互译

#非法使用子查询
#…

SELECT employee_id, last_name
FROM   employees
WHERE  salary = #这里应该用In
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id);

**#子查询中的查询结果空值问题**
SELECT last_name, job_id
FROM   employees
WHERE  job_id =
                (SELECT job_id
                 FROM   employees
                 WHERE  last_name = 'Haas');
#公司没有这个工种以及这个人,查无此人

#多行子查询,可以使用的操作符为:in any all

SELECT employee_id, last_name
FROM   employees
WHERE  salary IN
                (SELECT   MIN(salary)
                 FROM     employees
                 GROUP BY department_id);

#any
#题目:返回其它部门中比job_id为‘IT_PROG’部门任一工资低的员工的员
#工号、姓名、job_id 以及salary

SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary < ANY # any
                    (SELECT  DISTINCT salary
                     FROM   employees
                     WHERE  job_id = 'IT_PROG')
AND    job_id <> 'IT_PROG';
###############
##DISTINCT去重#
###############

#题目:返回其它部门中比job_id为‘IT_PROG’部门任意工资低的员工的员
#工号、姓名、job_id 以及salary

SELECT employee_id, last_name, job_id, salary
FROM   employees
WHERE  salary < ALL # any
                    (SELECT  DISTINCT salary
                     FROM   employees
                     WHERE  job_id = 'IT_PROG')
AND    job_id <> 'IT_PROG';

#最困难的就是子查询
#查询工资比公司平均工资高的员工的员工号,姓名和工资。

SELECT employee_id,last_name,salary
FROM employees
WHERE salary>(
    SELECT AVG(salary)
    FROM employees
);

#*.查询各部门中工资比本部门平均
#工资高的员工的员工号, 姓名和工资
#相关查询

#方式一:

 SELECT employee_id,last_name,salary
 FROM employees e1
 WHERE salary>(
        #查询送进来的员工所在部门的平均值
        SELECT AVG(salary)
        FROM employees e2
        WHERE e1.`department_id`=e2.`department_id`
        );

#外边先送进来一条数据
#里边判断,和送进来的比较一下然后再送出去

#方式二:子查询不止可以出现在where过滤条件中

SELECT employee_id,last_name,salary    #下边相当于新制作了一张表
FROM employees e1,(SELECT department_id,AVG(salary)  dept_avg_sal FROM 
employees GROUP BY department_id) d)
WHERE e1.`department_id`=d.dept_avg_sal;

#子查询不仅可以写在where 里,能写的地方比较多
#group by 这块不能写其他地方都可以写
#排序这块也可以写
#可以在order by 中也使用子查询
#查询员工的姓名,部门id,要求按照部门名排序

SELECT last_name,department_id
FROM employees e
ORDER BY (
     SELECT department_name
     FROM departments d
     WHERE e.`department_id`=d.`department_id`
);

#查询管理者是King 的员工的姓名和工资

SELECT last_name,salary
FROM employees
WHERE manage_id IN(
      SELECT employee_id
      FROM   employees
      WHERE last_name='King'
      );

#查询平均工资最低的部门信息
#单行函数可以嵌套,多行行数,分组函数不可以嵌套
#oracle可以嵌套

SELECT MIN(AVG(salarg))
FROM employees
GROUP BY department_id

#mysql 写法

SELECT *
FROM departments
WHERE department_id=(
                    SELECT department_id
                    FROM employees
                    GROUP BY department_id
                    HAVING AVG(salary)=( 
                                        SELECT MIN(avg_sal)
                                       FROM(
                                       SELECT AVG(salary) avg_sal
                                       FROM employees
                                       GROUP BY department_id ) dept_avg_sal
                                        )
                                  );

#查询平均工资最低的部门的信息和该部门的平均工资

SELECT d.*,(SELECT AVG(salary) FROM emeployees e WHERE e.department_id=d.`department_id`) "部门平均工资"
FROM departments d
WHERE department_id=(
                    SELECT department_id
                    FROM employees
                    GROUP BY department_id
                    HAVING AVG(salary)=( 
                                        SELECT MIN(avg_sal)
                                       FROM(
                                       SELECT AVG(salary) avg_sal
                                       FROM employees
                                       GROUP BY department_id ) dept_avg_sal
                                        )
                                  );

#各个部门中 最高工资中最低的那个部门的 最低工资是多少?
#加入有三个部门 最高工资分别是 8000 9000 10000, 那么本题求的是8000那个部门的最低工资

SELECT MIN(salary)
FROM employees
WHERE department_id=(
SELECT department_id
FROM employees
GROUP BY department_id
HAVING MAX(salary)=(
                      SELECT  MIN(max_sal)
                      FROM (
                              SELECT MAX(salary) max_sal
                              FROM employees
                              GROUP BY department_id
                    ) dept_max_sal
)
)

#分号问题,如果把下边的全部选中,那么会逐个执行插入操作
#分号表示单独一条的执行语句,单独一行的代码写不写分号都无所谓

INSERT INTO ....;
INSERT INTO ....;
INSERT INTO ....;
INSERT INTO ....;

_____________________________________________________________________________________

创建和管理表

#写查询时最好一次性都做完,一次性搞定
#查询不可不免的使用子查询

#sql三条主线
#DML :inset、update ,delete,select
#DDL : create、alter、drop、truncate、rename
#dcl :commit、rollback

#主要学ddl

#显示所有的数据库
SHOW DATABASES;
#使用指定的数据库
USE 学生信息;

#显示所有的表

SHOW TABLES;

#创建表 (create table)
#方式一:"白手起家的方式",自己一点点搭建起来
#HOW TO CREATE TABLE ?
#CREATE TABLE
CREATE DATABASE AAA;
USE AAA;

#设计每个字段
#列,即字段,要指定字段的数据类型
#数据类型 等比java严格
#设置长度10位 最大9999999999
#字符型
#工资,总长度是10,其中2位是小数
#入职时间,日期型

#开发中创建表的方式

CREATE TABLE myemp1(

 emp_id INT(10) AUTO_INCREMENT PRIMARY KEY,
 emp_name VARCHAR(15),                      
 salary   DOUBLE(10,2),                     
 hire_date DATE                             
);
SELECT  * FROM myemp1 ;
DESC myemp1;
##################
#AUTO_INCREMENT #  自增长,创建一个自己增加
##################
#PRIMARY KEY         #  设置主键 保证自动添加的数是唯一的
##################

#平时创建表的时候,用到约束,
#方式二: “基于现有的表,创建新的表”,创二代,富二代

CREATE TABLE myemp2
AS            #列的别名充当新创建键的表的列名
SELECT employee_id  emp_id ,last_name,salary  #emp_id是列的别名,创建别名后新表中使用这个别名作为字段
FROM employees;

#从原有的表中复制出来三个字段供myemp使用
#原表的类型和存储范围也同步的复制过来了
#并不是所有内容都会被赋值过来
#约束并不是能被复制过来的
#此种方式创建表的同时,还可以将原有表的数据赋值过来

SELECT *
form myemp2;

#不能覆盖,所以要写个别的名

CREATE TABLE myemp3
AS            
SELECT employee_id  emp_id ,last_name,salary
FROM employees;
WHERE department_id IN (50 , 60 , 70,80)
AND salary > 5000;

#可以根据自己的想法,创造很多的新表

CREATE TABLE myemp4
AS      
SELECT department_id ,AVG(salary)
FROM employees
GROUP BY department_id;

#####基于多表创建新表

CREATE TABLE myemp5
AS      
SELECT department_name ,AVG(salary)
FROM employees e, departments d
WHERE e.department_id = d.department_id
GROUP BY department_name;

#复制 employees

CREATE TABLE employee_copy
AS
SELECT *
FROM employees;  ##约束有一些问题

#复制 employees ,但是数据为空

CREATE TABLE employee_blank
AS
SELECT *
FROM employees;  ##约束有一些问题
WHERE 1=2; #写个不成立的条件

#创建表涉及到一些常用的数据类型
#varchar()
#不写长度会报错 通常用这种可变长度的
#视频,图片都是以blog形式存储的
#有多种不同的blog

#改变表

USE aaa;
CREATE TABLE myemp1(

 emp_id INT(10) AUTO_INCREMENT PRIMARY KEY,
 emp_name VARCHAR(15),                      
 salary   DOUBLE(10,2),                     
 hire_date DATE                             
);

#修改表 (alter table)
#1添加一个列

ALTER TABLE myemp1
ADD email VARCHAR(25);
DESC myemp1;
#ora varchar2 mysql varchar

#修改现有的列

ALTER TABLE myemp1
MODIFY salary DOUBLE(15,2) DEFAULT 2000; #default 用于设置默认值
#modify用于修改表字段

#删除现有列

ALTER TABLE myemp1
#不能用delete,delete用于删数据
#这里用drop 删除结构
DROP  COLUMN email; #colum叫列

#重命名列

#可以同时改变列数据类型
#和ora 不一样
#change
USE aaa;

ALTER TABLE myemp1
CHANGE salary my_sal DOUBLE(10,2);
#oracle 的写法 :
#alter table myemp1 rename salary to mysal;
#修改四个事情 完毕

#删除表

DROP TABLE myemp1;

#重命名表

ALTER TABLE emp3
RENAME TO myemp1;
#oracle : rename myemp3 to emp3;
SELECT * FROM myemp3;
SELECT * FROM emp3;

#最后一个操作
#清空表
#清空表:将表中所有的数据清空,表结构仍然保留
#truncate table 一旦将数据删除,数据不可回滚
#delete from : 删除操作支持回滚 增删改的删

COMMIT; #提交数据
#前边做的任何修改都提交,
#之前做的修改都保存下来
##DCL
#将数据设置为不能自动提交

USE 学生信息;
SET autocommit=FALSE;#不让数据提交
DELETE FROM  地址表;
SELECT * FROM 地址表;

ROLLBACK ; #回滚数据
ROLLBACK ;#只会回滚到最近的一次commit之后,他俩是成对出现的



#############
COMMIT;
SET autocommit=FALSE;

TRUNCATE TABLE  test1.`result`; ##不可回滚数据,也可以理解为自动提交数据
#一旦执行不可找回

ROLLBACK;

SELECT * FROM test1.`result`;

回滚这里有坑
#有时无法回滚
#解决办法
https://blog.csdn.net/noaman_wgs/article/details/52121991


_____________________________________________________________________________________

数据处理的增删改

#pl/sql专门的数据库操作语言,
#增删改查中查询最复杂也最重要
#和数据库交互时,力求查询命令写的干净利落,一次能完成的事情,绝不两次做完
#相关子查询是里边和外边有相关性,外边传进去,里边再传出来,用到子查询
#创建管理表要简单一些,创建表有两种方式,白手起家,和拷贝
#修改表有四个指令,添加列,修改列,删除列等,修改列名操作比较少,一般情况下数据库表字段都是一次成型,改列名的操作很少去做
#存储范围从小改大不会对原数据造成影响,由大改小会造成数据丢失,报错
#数据类型也可以修改,本身已经有数据,由double改data 那么不匹配,在oracle报错,表中没数据可以改,在mysql中不报错
#如果里边有数据,也会改成功,会清空数据。这一列数就全没有了。
#清空表turnccate table,不可回滚
#表非常确定,想要删除,用trunccate table
#delete from 中间环节是删一删,修改一下,不确定。
#增删改都可回滚。及时commit 提交数据 省着回滚的特别远,造成数据损失

#函数 格式很重要
#sql 不难,需要多写
#没有很长的代码,撑死几十行
#投入了会心疼,会努力
#group by 后不要写子查询

#数据处理 之 增删改
#增 (添加) -----INSERT INTO

DROP TABLE aaa.`myemp1`;
USE aaa;
CREATE TABLE myemp(
 
 id INT,
 nam VARCHAR(10),#可变必须指定长度
 salary DOUBLE(10,2),
 hire_date DATE
);

SELECT * FROM  aaa.myemp;

#增
#方式一,一条一条添加数据
#默认情况下,需要按照表中的列的顺序依次赋值

INSERT INTO myemp
VALUES(1,'tom1',3400,NOW());

#默认循序按列的排列顺序来的

INSERT INTO myemp
VALUES(1,'tom1',NOW(),3400);

#这样写测试通过,不过没意义

#开发中常见情况
#有时候,不太清楚先哪个列后哪个列
#就可以在表后指定顺序,这种方法在程序开发里用的比较多

INSERT INTO myemp(id,nam,hire_date,salary)
#显示的列出表中的列,一般都这样做
VALUES(1,'tom1',NOW(),3600);

#假如员工工资还没定下来,所以可以填null

INSERT INTO myemp(id,nam,hire_date,salary)
VALUES(1,'tom1',NOW(),NULL);

#表有四个列,参数表中只写了三个,
#则下边的具体参数也要写三个
#这种情况用的也比较多,剩余列自动填null

INSERT INTO myemp(id,nam,hire_date)
VALUES(1,'tom1',NOW());

#用户信息,填表可能不完整,在保存时没写的自动填NULL
#没有声明添加数据的列,数据默认为nulll,在开发中很常见
#有时会执行不成功,涉及到约束问题
#salary添加过非空约束的话,那么执行时就会报错
#有些非空的列,必须要赋值,

#以上是一条一条添加

#方式二,导入数据,基于现有的表
#导入时要注意列的类型和范围是否一样

DESC myemp;#导表示先看结构
DESC emp;

CREATE TABLE hehehe
AS
SELECT * FROM myemp;



INSERT INTO hehehe(id,nam,salary)
SELECT id,nam,salary
FROM myemp;
#where.....

#删除数据 : delete from

DELETE FROM myemp
WHERE salary IS NULL;#删除空行

#写的时候通常有过滤条件,否则全删除了
#delete from 是天然的批量操作
#删除,有时会删除失败(报错)
#表不存在

#约束,主要对列加约束
#外键约束
#A表有一个地区编号,B表也有一个地区编号
#AB表关联以后,如果再向A表的地区编号写一个
#另外的值,这个值在b表的地区编号中不存在
#那么会报错,违反外键约束
#外键约束的值不能删

#删父表的数据,先去子表查一下看有没有相关关联

#因为有外键约束,且在employees 找到了对应的90号部门相关的员工数据,所以删除失败

DELETE FROM departments
WHERE department_id=90;

#修改数据 update … set …where…

UPDATE  myemp
SET salary=12000
WHERE id=1;

#此操作也是批量操作,如果不指定where条件,则全部更新

UPDATE  myemp
SET salary=12000,id=222,hire_date='1999-09-09'
WHERE id=2;

#有外键约束的时候也要谨慎删除

#删除的特点
#级联删除,级联置空 (看课件)
#多表同步的意思
#在设置外键约束时,在后边加上一些条件。。。。

#数据库事务 一条或多条的DML的操作综合在一起
#叫数据库事务
#数据库事务:一条或多条DML操作组合在一起,构成数据库事务
#AA 转账 给BB
#转账的一个同步性,我转你收,你收不到,就回滚

#update emp set salary=salary-100 where name='AA'
#update emp set salary=salary+100 where name='BB'

#处理事务的原则:要么一个事务中的多个DML操作都执行成功,此时提交数据
#将修改了的数据保存下来
#要么都执行不成功,则已经执行了的操作也要回滚回去。

#CC向DD转账100
#又构成一个事务,整体出现,要么都出现,要么都不出现
#DML操作,支持数据的回滚操作。
#DDL操作,不支持数据的回滚,删除一个表,修改一个表,都不可以回滚
SET autocommit=FALSE;#设置为不自动提交操作
#开发中,先让autocommit变量为false

#try{
  #update emp set salary=salary-100 where name='AA'
  #update emp set salary=salary+100 where name='BB'
#commit;
#} catch(){

#rollback;

#}

#java 中类似这么表示

#commit;

commit;
SET autocommit=FALSE;

SELECT * FROM goods;
DELETE FROM goods;
ROLLBACK;

_____________________________________________________________________________________

约束和分页

#约束(constraint) 关键字
#为了保证数据一致性和完整性,SQL规范以约束的方式对表数据尽心额外的条件限制
#常见的约束:费控约束(not null) 唯一性约束(unique) 主键约束(primaary key) 外键约束(foreign key)
#检查性约束(check) 默认值约束(default)

#如何给表添加约束:1创建的同时添加约束,2通过修改表的方式,添加,删除约束,约束不能说是修改(先删 再加)
#在一开始考虑到,造表的时候考虑清楚,否则后期可能出现约束添加不上,删除不了的情况
#添加方式的体现:1 列级约束 2 表级约束(写在表的后边而已)
#约束实际上是对表的列的限制,对表中数据额外加的限制
#通俗来说就是对表中列在进行DML操作时的限制

#1.非空约束(not null)
#只能使用列级约束

USE aaa;
CREATE TABLE myem1(
id INT   NOT NULL ,
NAME VARCHAR(15)   NOT NULL,
salary DOUBLE (10,2)
);
DESC myem1;
INSERT INTO myem1(id,NAME,salary)
VALUES(1,'tom',200);

#报错 Field ‘id’ doesn’t have a default value
#添加失败

INSERT INTO myem1(NAME,salary)
VALUES('t1',200);

INSERT INTO myem1(NAME,salary)
VALUES(200);

#最后一个字段可以为空,因为没有非空限制

INSERT INTO myem1(id,NAME,salary)
VALUES(1,'tom',NULL);

#删除非空约束

ALTER TABLE myem1
MODIFY NAME VARCHAR(15) NULL;


DESC myem1;

#添加非空约束
#有可能执行不成功,(原因:如果现有的salary中已有null值,则添加约束失败)

ALTER TABLE myem1
MODIFY salary DOUBLE(10,2) NOT NULL;

#2.唯一性约束 (unique)
#列值是唯一的

USE aaa;
CREATE TABLE myem2(
 id INT  UNIQUE, #列级约束,这默认起约束名
 NAME VARCHAR(15),
 email VARCHAR(20),
 hire_date DATE,
 
 #表级约束  约束名
 CONSTRAINT emp2_id_uk       UNIQUE(email),
 CONSTRAINT emp2_hire_date_uk UNIQUE(hire_date)
);

#NULL可以出现多次,不认为是一样的数据
#可以向声明为unique的列上多次添加null

INSERT INTO myem2(id,NAME,hire_date)
VALUES(3,'tom','2019-09-10');

#重复添加会添加失败

INSERT INTO myem2(id,NAME,hire_date,email)
VALUES(31,'t11om','2019-1-10','178@qq,com');

#删除唯一性约束
#系统会自动向声明为唯一性约束的列上添加索引

ALTER TABLE myem2
DROP INDEX emp2_hire_date_uk;

#删掉索引,对应的唯一性约束也就删掉了。

#添加唯一性约束
#…

#3.主键约束(primary key)
#主键的约束作用的列要求:非空且唯一
#一个表中,只能声明一个主键约束
#使用作用有主键约束的列作为查询条件,可以定位表中的唯一的一条记录
#唯一约束有null值的情况

CREATE TABLE my3(
  id  INT PRIMARY KEY,
  NAME VARCHAR(15)
  
 CONSTRAINT my3_id_pk PRIMARY KEY(id)
);
CREATE TABLE my3(
  id  INT AUTO_INCREMENT,#通常使用自增长,自动维护
  NAME VARCHAR(15),
 CONSTRAINT my3_id_pk PRIMARY KEY(id)
);
INSERT INTO my3(NAME)#因为设置了主键自增长,所以这里可以只写一个name
VALUES('张三');

INSERT INTO my3(NAME)#因为设置了主键自增长,所以这里可以只写一个name
VALUES('李四');
SELECT * FROM my3;


#4.外键约束:同样作用在列上

CREATE TABLE  m1(
dept_id INT,
dept_name VARCHAR(10)
);
INSERT INTO m1(dept_id,dept_name)
VALUES(10,'it');

INSERT INTO m1(dept_id,dept_name)
VALUES(20,'Account');



#需要先为mi添加主键或唯一约束
ALTER TABLE m1
ADD CONSTRAINT dept_id_pk PRIMARY KEY(dept_id);

DELETE FROM m2;
ROLLBACK;
CREATE TABLE  m2(
id INT,
NAME VARCHAR(15),
dept_id INT,
#外键约束(关联到的mydept的dept_id需要有唯一性的约束或主键约束)
CONSTRAINT m2_dept_id_fk FOREIGN KEY(dept_id) 
REFERENCES m1(dept_id)#在这个地方添加级联删除,级联置空的约束
#意思。。

);

#要求向m2 表中dept_id添加值时,要求值必须是m1表中dept_id出现过的值

#正确的

INSERT INTO m2(id,NAME,dept_id)
VALUES(2,'TOM',10);

#错误的

INSERT INTO m2(id,NAME,dept_id)
VALUES(1,'TOM',40);

#5.检查约束 check 对oracle有效,对mysql失效了

#sql语言里有这个规范,mysql里写和没写一样
CREATE TABLE m3(
 id INT AUTO_INCREMENT PRIMARY KEY,
 NAME VARCHAR(10),
 salary DOUBLE(10,2) CHECK(salary>3000)

);

#mysql执行仍然成功,oracle报错

INSERT INTO m3(NAME,salary) 
VALUES('tom',100);#加入check无意义,照样执行

#6.默认值约束(default)

CREATE TABLE m4(
id INT,
NAME VARCHAR(15),
salary DOUBLE(10,2) DEFAULT 3000

);

INSERT INTO m4(id,NAME)
VALUE(1,'tom');

SELECT * FROM m4;

#分页
#要查的数据比较多

SELECT *
FROM goods
LIMIT 0,10;#查询前十条数据

#查询goods_number 前十的信息

SELECT *
FROM goods
ORDER BY goods_number DESC

#LIMIT 0,10;#查询前十条数据
#第一个参数表示从多少条开始,第二个参数表示显示多少条

#在查询中limit写在order by的后边
LIMIT 20,3; #查询20-23的数据

#写成公式,显示第pagenumber页的pagesize条数据
#limit (pagenumber-1)*pagesize,pagesize
#约束比较多 主要掌握,主键约束,造表是主键都会加上

(本笔记整理自网络资源,侵删)

你可能感兴趣的:(SQL)