基本
1.+号的作用
在java中的+号
- 运算符,两个数都是数值型
- 连接符,只要其中一个操作数是字符串
mysql中
1.两个数都是数值,则作加法运算
2.只有有一个为字符串,则试图将字符串转为数值型。转换成功,继续加法。
3.转换失败,则将字符串转成数值0
4.只要一方为null,则结果为null
select 1+2;//3
select 1+"2";3
select 1+"a";//1
select null+1;null
2.concat的用法
SELECT
CONCAT(username, `password`)
FROM
user_info
WHERE
username = 'admin1'
//admin1123456
可以用在from后面\where\order by 等场景
3.安全等于
<=>
可以判断null(还是用来判断等于的)
SELECT
CONCAT(username, `password`)
FROM
user_info
WHERE
expired <=> null
4.常用单行函数
字符函数
- length(单位字节) CHAR_LENGTH
- concat
- upper lower
- substr substring
- instr
- trim() trim( x FROM string)
两边去空或指定字符
- lpad 用指定字符左填充到到指定长度 rpad
- replace
字符函数
- round 四舍五入
- ceil flloor
- truncate 截断
- mod取余(规则:余数符合看被除数的符合)
日期函数
- now 返回当前系统日期+时间
- curdate 只返回日期
- curtime 只返回时间
- 可以获取指定的部分、年、月、日、时、分、秒 。
STR_TO_DATE(可以随意变换时分秒的位置)/DATE_FORMAT
SELECT STR_TO_DATE('21,5,2018','%d,%m,%Y');//2018-05-21
流程控制函数
- if-else
select if(10>5,'大','小')
- case,类型java中的switch-case
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1;
when 常量2 then 要显示的值2或语句2;
...
5.分组函数
用作统计使用,又称为聚合函数或统计函数或组函数
注意事项
- sum\avg一般用于数值型
- 计算过程中会忽略null,即对avg来说不会算作分母
- 可以和distinct配合去重
5.where和having
sql中的筛选分为两类
数据源 | 位置 | 关键字 |
---|---|---|
原始表 | group by子句前面 | where |
分组后的结果集 | group by 子句后面 | having |
6.笛卡尔积现象
原因:多表间没有添加有效的连接条件
7.sql92标准连接
-
等值连接
-
非等值连接
工资表和等级标准表连接,每一条工资对应所有的标注,但通过between筛选后。只会剩下一条对应的等级标准
-
自连接
8.sql99-内连接
-
等值连接
-
非等值连接
3.自连接
9.交叉连接
就是另一种笛卡尔乘积的实现方式
10.各种连接总结
全外:mysql不支持
11. 子查询
分类:
按子查询出现的位置:
select后面:
仅仅支持标量子查询
from后面:
支持表子查询
where或having后面:★
标量子查询(单行) √
列子查询 (多行) √
行子查询
exists后面(相关子查询)
表子查询
按结果集的行列数不同:
标量子查询(结果集只有一行一列)
列子查询(结果集只有一列多行)
行子查询(结果集有一行多列)
表子查询(结果集一般为多行多列)
12.where或having后面
1.标量子查询(单行单列)
一般配合操作符
SELECT *
FROM employees
WHERE salary>(
SELECT salary
FROM employees
WHERE last_name = 'Abel'
);
2.列子查询(多行单列)
一般配合in
SELECT last_name,employee_id,job_id,salary
FROM employees
WHERE salary
3.行子查询(结果集一行多列或多行多列)了解
SELECT *
FROM employees
WHERE (employee_id,salary)=(
SELECT MIN(employee_id),MAX(salary)
FROM employees
);
用的不多,也可以通过两次查询得出
SELECT *
FROM employees
WHERE employee_id=(
SELECT MIN(employee_id)
FROM employees
)AND salary=(
SELECT MAX(salary)
FROM employees
);
13.select后面
仅仅支持标量子查询
#案例:查询每个部门的员工个数
SELECT d.*,(
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.`department_id`
) 个数
FROM departments d;
14.from后面的子查询
将子查询结果充当一张表,要求必须起别名
15 exists和in
in
确定给定的值是否与子查询或列表中的值相匹配。in在查询的时候,首先查询子查询的表
,然后将内表和外表做一个笛卡尔积
,然后按照条件进行筛选
。所以相对内表比较小的时候,in的速度较快。
因为一旦内表大,查询次数也会扩大很多倍。
exists
参考:https://www.cnblogs.com/emilyyoucan/p/7833769.html
指定一个子查询,检测行的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据一样的。匹配上就将结果放入结果集中。
exists()适合内表比外表数据大的情况
为什么?
内表1000w条,外表10条。执行1次exists查1000w条数据。但如果是in,笛卡尔机会有10000w条。相当于:一个是hash相连,一个是2层循环
对子表而言,in不走索引,exists可以走索引
not in 和not exists
如果查询语句使用了not in 那么内外表都
进行全表扫描,没有用到索引;而not extsts 的子查询依然能用
到表上的索引。所以无论那个表大,用not exists都比not in要快。
16.联合查询
1、要求多条查询语句的查询列数是一致的!
2、要求多条查询语句的查询的每一列的类型和顺序最好一致
3、union关键字默认去重,如果使用union all 可以包含重复项
17.两种插入方式
- values
insert into 表名(列名,...) values(值1,...);
- set
insert into 表名
set 列名=值,列名=值,...
18.表的复制
- 仅仅复制表的结构
CREATE TABLE copy LIKE author;
- 复制表的结构+数据
CREATE TABLE copy2
SELECT * FROM author;
- 只复制部分数据
CREATE TABLE copy3
SELECT id,au_name
FROM author
WHERE nation='中国';
- 仅仅复制某些字段
CREATE TABLE copy4
SELECT id,au_name
FROM author
WHERE 0;
19.约束类型
- NOT NULL:非空,用于保证该字段的值不能为空
比如姓名、学号等 - DEFAULT:默认,用于保证该字段有默认值
比如性别 - PRIMARY KEY:主键,用于保证该字段的值具有唯一性,并且非空
比如学号、员工编号等 - UNIQUE:唯一,用于保证该字段的值具有唯一性,可以为空
比如座位号 - CHECK:检查约束【mysql中不支持】
比如年龄、性别 - FOREIGN KEY:外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值
在从表添加外键约束,用于引用主表中某列的值
比如学生表的专业编号,员工表的部门编号,员工表的工种编号
20.添加约束
约束的添加分类:
- 列级约束:定义表时,对列进行约束
六大约束语法上都支持,但外键约束没有效果
USE students;
DROP TABLE stuinfo;
CREATE TABLE stuinfo(
id INT PRIMARY KEY,#主键
stuName VARCHAR(20) NOT NULL UNIQUE,#非空
gender CHAR(1) CHECK(gender='男' OR gender ='女'),#检查
seat INT UNIQUE,#唯一
age INT DEFAULT 18,#默认约束
majorId INT REFERENCES major(id)#外键
);
- 表级约束:表都定义完了,再添加约束
除了非空、默认
,其他的都支持
/*
语法:在各个字段的最下面
【constraint 约束名】 约束类型(字段名)
*/
DROP TABLE IF EXISTS stuinfo;
CREATE TABLE stuinfo(
id INT,
stuname VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
majorid INT,
CONSTRAINT pk PRIMARY KEY(id),#主键
CONSTRAINT uq UNIQUE(seat),#唯一键
CONSTRAINT ck CHECK(gender ='男' OR gender = '女'),#检查
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)#外键
);
21.修改表时添加约束
- 添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;
示例
#1.添加非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
#3.添加主键
#①列级约束
ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
#②表级约束
ALTER TABLE stuinfo ADD PRIMARY KEY(id);
- 添加表级约束
alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;
示例
#5.添加外键
ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id);
#1.删除非空约束
ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL;
#3.删除主键
ALTER TABLE stuinfo DROP PRIMARY KEY;
#4.删除唯一
ALTER TABLE stuinfo DROP INDEX seat;
#5.删除外键
ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;
进阶
1. 查看事务级别
select @@tx_isolation
2.回滚点
savepoint,设置保存点
#3.演示savepoint 的使用
SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滚到保存点
SELECT * FROM account;
3.试图更新特点
具备以下特点的视图不允许更新
- 包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all
- 常量视图
- Select中包含子查询
- join
- from一个不能更新的视图
- where子句的子查询引用了from子句中的表
总结
试图本质就是一次查询,,数据都是由多张表组合形成。我们要想插入,mysql必须确保能准备的定位到插入的数据对应到哪种表的哪个字段。如果都可以定位到,那就可以更新(增加和删除)
4.变量
-
系统变量:
- 全局变量
- 会话变量
-
自定义变量:
- 用户变量
- 局部变量
5.系统变量
.全局变量
作用域:针对于所有会话(连接)有效,但不能跨重启
#①查看所有全局变量
SHOW GLOBAL VARIABLES;
#②查看满足条件的部分系统变量
SHOW GLOBAL VARIABLES LIKE '%char%';
#③查看指定的系统变量的值
SELECT @@global.autocommit;
#④为某个系统变量赋值
SET @@global.autocommit=0;
SET GLOBAL autocommit=0;
.会话变量
作用域:针对于当前会话(连接)有效
#①查看所有会话变量
SHOW SESSION VARIABLES;
#②查看满足条件的部分会话变量
SHOW SESSION VARIABLES LIKE '%char%';
#③查看指定的会话变量的值
SELECT @@autocommit;
SELECT @@session.tx_isolation;
#④为某个会话变量赋值
SET @@session.tx_isolation='read-uncommitted';
SET SESSION tx_isolation='read-committed';
总结:
- 系统变量按作用域划分
- 默认session级别,需要再前缀@@session.(@@global.)
- 都有两个
@
6.自定义变量
说明:变量由用户自定义,而不是系统提供的
使用步骤:
1、声明
2、赋值
3、使用(查看、比较、运算等)
用户变量
作用域:针对于当前会话(连接)有效,作用域同于会话变量
#赋值操作符:=或:=
#①声明并初始化
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
#②赋值(更新变量的值)
#方式一:
SET @变量名=值;
SET @变量名:=值;
SELECT @变量名:=值;
#方式二:
SELECT 字段 INTO @变量名
FROM 表;
#③使用(查看变量的值)
SELECT @变量名;
局部变量
用域:仅仅在定义它的begin end
块中有效
应用在 begin end中的第一句话
#①声明
DECLARE 变量名 类型;
DECLARE 变量名 类型 【DEFAULT 值】;
#②赋值(更新变量的值)
#方式一:
SET 局部变量名=值;
SET 局部变量名:=值;
SELECT 局部变量名:=值;
#方式二:
SELECT 字段 INTO 具备变量名
FROM 表;
#③使用(查看变量的值)
SELECT 局部变量名;
总结
- 局部变量没有
@
- INTO也是赋值
#案例:声明两个变量,求和并打印
#用户变量
SET @m=1;
SET @n=1;
SET @sum=@m+@n;
SELECT @sum;
#局部变量
DECLARE m INT DEFAULT 1;
DECLARE n INT DEFAULT 1;
DECLARE SUM INT;
SET SUM=m+n;
SELECT SUM;
7.存储过程
好处:
- 提高代码的重用性
- 简化操作
含义:一组预先编译
好的SQL语句的集合,理解成批处理
语句
1、提高代码的重用性
2、简化操作
3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率
存储过程的格式
1、参数列表包含三部分
参数模式 参数名 参数类型
#举例:
in stuname varchar(20)
参数模式:
in:该参数可以作为输入,也就是该参数需要调用方传入值
out:该参数可以作为输出,也就是该参数可以作为返回值
inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
2、如果存储过程体仅仅只有一句话,begin end可以省略
存储过程体中的每条sql语句的结尾要求必须加分号
。
存储过程的结尾可以使用 delimiter
重新设置
delimiter 结束标记
案例:
delimiter $
调用语法
CALL 存储过程名(实参列表);
案例
#--------------------------------案例演示-----------------------------------
#1.空参列表
#案例:插入到admin表中五条记录
SELECT * FROM admin;
DELIMITER $
CREATE PROCEDURE myp1()
BEGIN
INSERT INTO admin(username,`password`)
VALUES('john1','0000'),('lily','0000'),('rose','0000'),('jack','0000'),('tom','0000');
END $
#调用
CALL myp1()$
#2.创建带in模式参数的存储过程
#案例1:创建存储过程实现 根据女神名,查询对应的男神信息
CREATE PROCEDURE myp2(IN beautyName VARCHAR(20))
BEGIN
SELECT bo.*
FROM boys bo
RIGHT JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name=beautyName;
END $
#调用
CALL myp2('柳岩')$
#案例2 :创建存储过程实现,用户是否登录成功
CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20))
BEGIN
DECLARE result INT DEFAULT 0;#声明并初始化
SELECT COUNT(*) INTO result#赋值
FROM admin
WHERE admin.username = username
AND admin.password = PASSWORD;
SELECT IF(result>0,'成功','失败');#使用
END $
#调用
CALL myp3('张飞','8888')$
#3.创建out 模式参数的存储过程
#案例1:根据输入的女神名,返回对应的男神名
CREATE PROCEDURE myp6(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20))
BEGIN
SELECT bo.boyname INTO boyname
FROM boys bo
RIGHT JOIN
beauty b ON b.boyfriend_id = bo.id
WHERE b.name=beautyName ;
END $
#案例2:根据输入的女神名,返回对应的男神名和魅力值
CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT)
BEGIN
SELECT boys.boyname ,boys.usercp INTO boyname,usercp
FROM boys
RIGHT JOIN
beauty b ON b.boyfriend_id = boys.id
WHERE b.name=beautyName ;
END $
#调用
CALL myp7('小昭',@name,@cp)$
SELECT @name,@cp$
#4.创建带inout模式参数的存储过程
#案例1:传入a和b两个值,最终a和b都翻倍并返回
CREATE PROCEDURE myp8(INOUT a INT ,INOUT b INT)
BEGIN
SET a=a*2;
SET b=b*2;
END $
#调用
SET @m=10$
SET @n=20$
CALL myp8(@m,@n)$
SELECT @m,@n$
#三、删除存储过程
#语法:drop procedure 存储过程名
DROP PROCEDURE p1;
DROP PROCEDURE p2,p3;#×
#四、查看存储过程的信息
DESC myp2;×
SHOW CREATE PROCEDURE myp2;
8.函数
区别:
存储过程:可以有0个返回,也可以有多个返回,适合做批量插入、批量更新
函数:有且仅有1 个返回,适合做处理数据后返回一个结果
一、创建语法
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
END
1.参数列表 包含两部分:
参数名 参数类型
2.函数体:肯定会有return语句,如果没有会报错
如果return语句没有放在函数体的最后也不报错,但不建议
return 值;
3.函数体中仅有一句话,则可以省略begin end
4.使用 delimiter语句设置结束标记
二、调用语法
SELECT 函数名(参数列表)
#1.无参有返回
#案例:返回公司的员工个数
CREATE FUNCTION myf1() RETURNS INT
BEGIN
DECLARE c INT DEFAULT 0;#定义局部变量
SELECT COUNT(*) INTO c#赋值
FROM employees;
RETURN c;
END $
SELECT myf1()$
#2.有参有返回
#案例1:根据员工名,返回它的工资
CREATE FUNCTION myf2(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
SET @sal=0;#定义用户变量
SELECT salary INTO @sal #赋值
FROM employees
WHERE last_name = empName;
RETURN @sal;
END $
SELECT myf2('k_ing') $
#案例2:根据部门名,返回该部门的平均工资
CREATE FUNCTION myf3(deptName VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE sal DOUBLE ;
SELECT AVG(salary) INTO sal
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name=deptName;
RETURN sal;
END $
SELECT myf3('IT')$
#三、查看函数
SHOW CREATE FUNCTION myf3;
#四、删除函数
DROP FUNCTION myf3;
#案例
#一、创建函数,实现传入两个float,返回二者之和
CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT
BEGIN
DECLARE SUM FLOAT DEFAULT 0;
SET SUM=num1+num2;
RETURN SUM;
END $
SELECT test_fun1(1,2)$
9.触发器
参考:https://www.cnblogs.com/geaozhang/p/6819648.html