方式一: 计算机–右击管理–服务
方式二: 通过管理员服务运行
net start 服务名
启动服务
net stop 服务名
停止服务
方式一: 通过MySQL自带的客户端(仅限管理员)
方式二: 通过DOS
登录: mysql [-h 主机名 -p 端口号] -u 用户名 -p密码
退出: EXIT
或者ctrl+c
查看所有的数据库
SHOW DATABASES;
打开指定的库
USE 库名
查看当前库的所有表
SHOW TABLES
查看其他库的所有表
SHOW TABLES form 库名
创建表
CREATE TABLE 表名(
列名 列类型,
列名 列类型,
... ...
);
查看表结构
DESC 表名;
查看服务器版本
方式一: 登录到MySQL服务端
SELECT version()
方式二: 在DOS下
mysql --version
或者mysql --V
语法
SELECT 查询列表 FROM 表名;
(F12快捷键格式化)
特点
查询表中的单个字段
SELECT last_name FROM empoyee;
查询表中的多个字段
SELECT last_name,firt_name,email FROM empoyee;
查询表中的所有字段
SELECT * FROM 表名
(*即表示匹配所有)
查询常量值
SELECT 100;
SELECT 'john';
查询表达式
SELECT 100*9;
SELECT 100%98;
查询函数
SELECT fun();
为字段起别名(提高可读性,便于理解)
(如果需要查询的字段有重名的情况,使用重名可以区分开来)
SELECT 100%98 AS 结果;
SELECT lASt_name AS 姓;
SELECT last_name 姓,first_name 名 FROM 表名;
==注:==若别名中有空格,则请将整个别名用 ` 括起来,表示是一个字符串
8. 去重(搜索到的重复结果)
添加关键字DISTINCT
SELECT DISTINCT employee_id FROM employees;
+号的作用(在MySQL中的+号仅有运算符的功能)
SELECT 100+90;
运算符
SELECT '123'+90;
其中一方为字符型,则会试图将字符型转换成数值型。若转换成功,则继续做加法运算。若失败,则将字符型换成0
SELECT null+10;
一方为null,则结果为null
注: +号不能用于连接字符串(可以用 CONCAT()函数实现此功能)
语法:
SELECT
查询列表
FROM
表名
WHERE
筛选条件;
分类:
条件运算符:> < = != <>(不等于) >= <=
逻辑表达式:&& || ! and or not
like 、 between and 、 in 、 is null
按条件表达式筛选
SELECT
last_name,
department_id
FROM
employees
WHERE
department_id <> 90; # !=也支持
按逻辑表达式筛选
SELECT
last_name,
salary,
FROM
employees
WHERE
salary>=10000
AND
salary<=20000;
### 初学时可将and、or、not写在一行,以方便理解
模糊查询
like(一般和通配符搭配使用)
通配符:
% 任意多个字符
_ 任意单个字符
\ 转义符
(推荐用 ESCAPE 关键字任意指定转义符)
#案例:查询员工名中包含字符'a'的员工信息
SELECT
*
FROM
employees
WHERE
last_name LIKE '%a%'; # %号代表任意字符
between and(两边两个连接词也被包含在范围中)
# 案例:查询员工标号在 100~120 的员工信息
SELECT
*
FROM
emplpyees
WHERE
employee_id BETWEEN 100 AND 120;
### between and 的连接词是 左小右大!
in(包判断某字段的值是否属于in列表)
#案例:查询员工的工种编号是 IT_PROG、AD_VP的员工名、工种编号
SELECT
last_name,
job_id,
FROM
employees
WHERE
job_id IN( 'IT_PROG','AD_VP');
### in列表的值类型必须一致或者兼容!
### in列表里的值不满足通配符运算!
is null(仅用来判断NULL值)
#案例:查询没有奖金(奖金率为null)的员工名和奖金率
SELECT
last_name,
commission-pct
FROM
employees
WHERE
commission_pct IS NULL;
## 若查询有奖金的,则可写成 IS NOT NULL
==Ps:==安全等于<=>(可读性较低)
commission_pct <=> NULL;
salary <=> 12000;
语法:
SELECT
查询列表
FROM
表
[WHERE 筛选条件]
ORDER BY
排序列表 [ASC|DESC];
# ASC 表示升序(默认ASC)
例:SELECT * FROM employees ORDER BY salary DESC;
#案例:查询部门编号>=90的团工信息,按入职时间的先后排序
SELECT *
FROM employees
WHERE department_id >= 90
ORDER BY hiredate ASC;
length:获取字符的字节长度(UTF8中一个中文占3个字节长度)
SELECT LENGTH('John');
concat:拼接字符
SELECT CONCAT(last_name,' ',first_name) AS 姓名;
upper、lower:转大小写字符
SELECT UPPER('john');
SELECT LOWER('JOHN');
substr(substring):截取字符
==注意:==在MySQL中的索引是从 1 开始
SELECT SUBSTR('好好学习天天向上',5);
# 天天向上
SELECT SUBSTR('好好学习天天向上',3,4);
# 学习天天( 3是索引,4是字符长度 )
instr:查询字符第一次出现的索引,未找到则返回 0
SELECT INSTR('好好学习天天向上','学习');
trim:删除字符左右的指定字符(默认删除空格)
SELECT TRIM(' 哈哈 ');
# 返回'哈哈'
SELECT TRIM('a' FROM 'aaa哈a哈aaa');
# 返回'哈a哈'
SELECT TRIM('aa' FROM 'aaa哈a哈aaa');
# 返回 'a哈a哈a'
lpad、rpad:从左(右)填充字符至指定长度
SELECT LPAD('好好学习',8,'*');
# 返回'****好好学习'
SELECT LPAD('好好学习',2,'*');
# 返回'好好'
replace:替换
SELECT REPLACE('好好学习天天向上','学习','钻研');
SELECT ROUND('1.65');
SELECT CEIL(1.2);
SELECT CEIL(1.0);
,返回1SELECT TRUNCATE(1.257,2);
,返回 1.25SELECT MOD(10,3);
mod(a,b) = a - a/b*b
,返回值得正负只取决于aSELECT NOW();
返回字符串’2020-04-28 13:26:25’SELECT YEAR(NOW());
SELECT MONTH('2020-04-28');
SELECT DATEDIFF('2020-04-28','2020-04-01');
返回28STR_TO_DATE('4-28-2020','%m-%d-%Y');
,返回 ‘1999-09-13’DATE_FORMAT('2020/4/28','%Y年%m月%d日');
,返回 ‘2020年04月28日’格式符 | 功能 |
---|---|
%Y | 四位的年份 |
%y | 两位的年份 |
%m | 月份(01,02…) |
%c | 月份(1,2…) |
%d | 日(01,02…) |
%H | 小时(24小时制) |
%h | 小时(12小时制) |
%i | 分钟(00,01…) |
%s | 秒(00,01…) |
if 函数:效果同 三目运算符
SELECT IF(10>5,'大','小');
,返回 ‘大’
case 函数(一):类似于 switch case
CASE 要判断的字段或表达式
WHEN 常量1 THEN 要显示的(值1,)或(语句1;)
WHEN 常量2 THEN 要显示的(值2,)或(语句2;)
...
ELSE 要显示的(值n,)或(语句n;)
END
case 函数(二):类似于 if … else if … else
CASE
WHEN 条件1 THEN 要显示的(值1,)或(语句1;)
WHEN 条件2 THEN 要显示的(值2,)或(语句2;)
...
ELSE 要显示的(值n,)或(语句n;)
END
SELECT SUM(DISTINCT salary) FROM employees;
SELECT COUNT(DISTINCT salary) FROM employees;
==注意:==分组函数会忽略 null 值
sum 求和、avg 平均值 、max 最大值、min 最小值
SELECT SUM(salary) FROM employees;
,返回salary的总和(返回一个值)
count 计算个数
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees; # --> 在 MYISM存储引擎下效率更高
# 一般可用来统计行数(个数)
SELECT COUNT(常量值) FROM employees; # --> 在INNODB储存引擎下,效率差不多。但效率比COUNT(字段)高
# 同样用来统计行数(通常常量值用1)
和分组函数一同查询的字段有限制
SELECT AVG(salary),employee_id FROM employees;
得到的结果没有意义!!!
和分组函数一同查询的字段,要求是 group by 后面的字段
通过 group by 语句将表中的数据分成若干组
SELECT 分组函数,查询列表 #列表要求出现在group by的后面
FROM 表
[WHERE 筛选条件]
[GROUP BY 分组的列表]
[ORDER BY 排序列表];
==注意:==查询列表必须特殊,要求是分组函数和 group by 后出现的字段
简单的筛选
# 案例一:查询每个工种的最高工资
SELECT MAX(salary),job_id
FROM employees
GROUP BY job_id;
# 案例二:查询邮箱中包含a字符的,每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
WHERE email LIKE '%a%'
GROUP BY department_id
ORDER By salary ASC;
添加复杂的筛选条件(对分组后的条件进行筛选)
# 查询每个工种有奖金的员工的最高工资>12000的工种编号的最高工资
# ①查询每个工种有奖金的员工的最高工资
SELECT MAX(sakary),job_id
FROM employees
WHERE commission_pct IS NOT NULL
GROUP BY job_id
# ②根据①的结果进行筛选,工资>12000
HAVING MAX(salary) > 12000;
按表达式或函数分组
# 按照员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT COUNT(*),LENGTH(last_name) AS len_name
FROM employees
GROUP BY LENGTH(last_name) # 一般放字段,不放函数。可以使用别名
HAVING COUNT(*) > 5;
按多个字段分组
# 查询每个部门的每个工种的员工的平均工资
SELECT AVG(salary), department_id,job_id
FROM employees
GROUP BY department_id,job_id;
又称:多表查询。当查询的值设计多个表时,即可使用多表连接
△笛卡尔乘积现象: 表1有m行,表2有n行,结果有m*n行
SELECT 'name',boyname FROM boys,beauty;
发生原因:没有有效的连接条件
解决办法:添加连接条件
SELECT 'name',boyname FROM boys,beauty
WHERE beauty.boysfriend_id = boys.id;
sql92标准
特点:仅仅支持内联接
sql99标准【推荐】
特点:支持 所有的内连接 + 外连接(左外、右外)+ 交叉连接
#####内连接
等值连接
为表起别名
# 查询员工名、工种号、工种名
SELECT last_name,e.job_id,job_title # 这里的job_id有歧义,需要用表名限定
FROM employees AS e,jobs j # 使用别名
WHERE e.job_id = j.job_id
加入分组
# 查询每个城市的部门个数
SELECT COUNT(*) 个数,city
FROM departments d,locations l
WHERE d.location_id = l.location_id
GROUP BY city;
三表连接
# 查询员工名、部门名和所在的城市
SELECT last_name,department_name,city
FROM employees e,departments d,locations l
WHERE e.department_id = d.department_id
AND d.location_id = l.location_id
ORDER BY last_name ASC;
非等值连接
# 案例:查询员工的工资和工资级别
SELECT salary,grade_level
FROM employees e,job_grade g
WHERE salary BETWEEN g.lowest_sal AND g.highest_sal
ORDER BY salary D ESC;
自连接
# 案例:查询员工名以及上级的名字
SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
FROM employees e,employees m
WHERE e.manager_id = m.employee_id;
SELECT 查询列表
FROM 表1 别名
[连接类型] JOIN 表2 别名
ON 连接条件
[WHERE 筛选条件]
... ...
包含:等值连接、非等值连接、自连接
‘INNER’ 可以省略
# 案例:查询部门个数>3的城市名和部门个数(分组+筛选)
SELECT city,COUNT(*) 部门个数
FROM departments d
INNER JOIN locations l
ON d.location_id = l.location_id
GROUP BY city
HAVING 部门个数 > 3;
# 查询员工名、部门名、工种名,并按部门名降序(三表连接)
SELECT last_name,department_name,job_title
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
INNER JOIN jobs j ON e.job_id = j.job_id
ORDER BY department_name DESC;
#####外连接
一般用于查询 [ 一个表中有,另一个表中没有的 ] 值
######特点
# 案例:查询男朋友不在男神表 的女神名
SELECT b.name[,bo.*]
FROM beauty b
LEFT OUTER JOIN boys bo
ON b.boyfriend_id = bo.id
WHERE bo.id IS NULL; # 一般选择判断 id,因为id作为主键不能为null
# 案例:查询没有员工的部门
SELECT d.*,e.employee_id
FROM departemnt d
LEFT JOIN employees e
ON d.department_id = e.department_id
WHERE e.employee_id IS NULL;
#全外连接(MySQL不支持)
#####交叉连接( cross )
即实现:笛卡尔乘积(表1有m行,表2有n行,结果有m*n行)
含义:出现在其他语句中的 select 语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询
分类:
####where或having后面
特点:
> < >= <= = <>
in/not in 、 any|some 、 all
#####标量子查询
(单行子查询)
# 案例:返回 job_id 与 141号 员工相同,salary 比 143号 员工多的员工的姓名,job_id 和工资
SELECT last_name,job_id,salary
FROM employees
WHERE job_id = (
SELECT job_id
FROM employees
WHERE employee_id = 141
) AND salary > (
SELECT salary
FROM employees
WHERE employee_id = 143
);
# 案例:查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT department_id,MIN(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) > (
SELECT MIN(salary)
FROM employees
WHERE department_id = 50
);
==注意:==子查询的结果必须是一行一列!
#####列子查询
(多行子查询)
搭配多行操作符使用in/not in 、 any/some 、 all
MIN MAX
代替且可读性更高,所以使用较少)MIN MAX
代替且可读性更高,所以使用较少)# 案例:返回 location_id 是 1400 或 1700 的部门中的所有员工
SELECT last_name
FROM employees
WHERE department_id IN (
# location_id 是 1400 或 1700 的部门id
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN (1400,1700)
);
#####行子查询
(一列多行,或多行多列,使用较少)
# 案例:查询员工编号最小 并且 工资最高 的员工信息(可能null)
# ----------------------原方法----------------------
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
);
只支持标量子查询(一行一列)
# 案例:查询每个部门的员工个数
SELECT d.*, (
#查每个部门人数
SELECT COUNT(*)
FROM employees e
WHERE e.department_id = d.department_id
) 个数
FROM department d;
支持表子查询(多行多列都行)
# 案例:查询每个部门的平均工资的工资等级
SELECT ag.*, g.grade_level
FROM (
# 每个部门的平均工资表
SELECT AVG(salary) ag,department_id
FROM employees
GROUP BY department_id
) ag_dep # 必须起别名,否则后面不能使用
INNER JOIN job_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
相关子查询(表子查询),布尔类型,即结果只有 1 或者 0
可以用 in 代替实现
SELECT EXISTS(
SELECT employee_id
FROM employees # 到此返回 1
WHERE salary = 9999 # 到此返回 0
);
应用场景:当需要显示的数据一页显示不全,需要分页提交sql请求
语法:
SELECT 查询列表
... ...
LIMIT offset,size;
# offset:要显示的条目的起始索引(起始索引从 0 开始)
# size:要显示的条目个数
SELECT * FROM employees LIMIT 0,5;
关键字:union
功能:将多条查询语句的结果(多张表的结果)合并成一个结果
应用场景:要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致
特点:
UNION ALL
可不去重)# 案例:查询 部门编号>90 或 邮箱包含a 的员工信息
SELECT * FROM employees WHERE email LIKE '&a&'
UNION
SELECT * FROM employees WHERE department_id > 90;
即数据操作语言。
关键词:insert
语法:
INSERT INTO 表名(列名1,列名2,...)
VALUES(值1,值2, ...)
[,(值1,值2, ...)
, ... ... ... ];
注意
# 案例
INSERT INTO beauty(id,name,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'李莉','女','2000-3-23','18888888888',null,5)
,(13,'李莉','女','2000-3-23','18888888888',null,5);
INSERT INTO beauty
VALUES(13,'李莉','女','2000-3-23','18888888888',null,5);
语法:
INSERT INTO 表名
SET 列名=值,列名=值,... ;
方式一支持插入多,方式二不支持
方式一支持子查询,方式二不支持
INSERT INTO beauty(id,name)
SELECT 12,'Lily';
# 此处省略,直接使用常量代替
UPDATE 表名
SET 列=新值, 列=新值, ...
WHERE 筛选条件; #若不加筛选条件,则修改表中每一行的信息
# 案例:修改boys表中的id为2,名称为张飞,魅力值10
UPDATE boys
SET boyname='张飞',usercp=10
WHERE id=2;
UPDATE 表1 别名1,表2 别名2
SET 列=值,...
WHERE 筛选条件
AND 筛选条件;
UPDATE 表1 别名
INNER|LEFT|RIGHT JOIN 表2 别名 ON 连接条件
SET 列=值
WHERE 筛选条件;
# 案例:修改张无忌的女朋友的电话为114
UPDATE boys bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
SET b.phone = '114'
WHERE bo.boyname = '张无忌';
DELETE FROM 表名
WHERE 筛选条件;
DELETE 表1的别名 或 表2的别名 # 加谁删谁
FROM 表1 别名,表2 别名
WHERE 连接条件
AND 筛选条件
同【修改】
# 案例:伤处手机号以9结尾的女神信息
DELETE FROM beauty
WHERE phone LIKE '%9';
# 案例:删除张无忌的女朋友信息
DELETE b
FROM beauty b
INNER JOIN boys bo ON b.boyfriend_id = bo.id
WHERE bo.boyname = '张无忌';
TRUNCATE TABLE 表名;
注意
即数据定义语言,主要是库和表的管理
CREATE DATABASE 库名;
CREATE DATABASE IF NOT EXISTS 库名;
一般不建议修改库,容易引起数据崩溃丢失
更改库的字符集:
ALTER DATABASE 库名 CHARACTER SET gbk;
DROP DATABASE 库名;
DROP DATABASE IF EXISTS 库名;
CREATE TABLE 表名(
列名 列的类型[(长度)] [列的约束],
... ... ,
列名 列的类型[(长度)] [列的约束]
)
PS通用:一般创建表(库)前,尝试将原表(库)删除再创建。
修改表名
ALTER TABLE 旧表名 RENAME TO 新表名;
修改列名(可以同时修改类型)
ALTER TABLE 表名 CHANGE [COLUMN] 旧列名 新列名 类型; #类型必须加上
修改列的类型或约束
ALTER TABLE 表名 MODIFY COLUMN 列名 类型;
添加新列
ALTER TABLE 表名 ADD COLUMN 新列 类型;
删除列
ALTER TABLE 表名 DROP COLUMN 列名;
DROP TABLE 表名;
DROP TABLE IF EXISTS 表名;
仅仅复制表的结构
CREATE TABLE 新表名 LIKE 源表;
复制表的结果加数据
CREATE TABLE 新表名
SELECT * FROM 源表;
仅仅复制部分结果
CREATE TABLE 新表名
SELECT 列,列,列
FROM 源表
WHERE 0; #添加一个 false 的条件
tinyint(1字节)、smallint(2字节)、mediumint(3字节)、int(4字节)、bigint(8字节)
设置无符号和有符号
CREATE TABLE table1(
test int # 默认是有符号值
);
CREATE TABLE table2(
test int UNSIGNED #无符号值
# 若对此插入 负值,则在表中值为0
)
当插入的值超过了值得范围时,插入的值会变成范围的临界值,同时会报out of range
的警告
如果不设置长度,则会有默认的长度
注意 整型的长度值不代表范围,代表表中的值显示的最大宽度
(配上关键词ZEROFILL
会使宽度不足用0代替,同时自动变为无符号型)
test int(7) ZEROFILL #表示长度为7的无符号int,不足7位会用0自动填充
float(M,D) (4字节)、double(M,D) (8字节)
DEC(M,D) 或 DECIMAL(M,D) 字节数为M+2
特点:
原则 所选择的类型越简单越好,能保存数值的类型越小越好
较短的文本:char(M)、varchar(M) M代表最长字符数
(binary、varbinary)
char:固定长度,比较耗费空间,效率较高
varchar:可变长度,节省空间,效率较低
注意 char 若省略长度,则默认为 1
varchar 不能省略长度
较长的文本:text、blob(较大的二进制)
(blob的介绍和使用在 JDBC.md 中)
枚举型:ENUM
enum1 ENUM('a''b','c')
注意 若插入的值不在 enum 中,则在表中会为 null,且警告
集合型:Set
set1 SET('a','b','c','d');
INSERT INTO 表名 VALUES
('a'),
('a','b','c'),
('a','b');
# 表中有三行,分别是 'a 'a,b,c' 'a,b'
类型 | 字节 | 最小值 | 最大值 |
---|---|---|---|
date | 4 | 1000-01-01 | 9999-12-31 |
datetime | 8 | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 |
timestamp ★ | 4 | 19700101080001 | 2038年的某一时刻 |
time | 3 | -839:59:59 | 838:59:59 |
year | 1 | 1901 | 2155 |
含义:用于限制表中的数据,为了最终保证表中数据的一致性
分类:
PS:添加约束的时机:①创建表时;②修改表时;
CREATE TABLE stu(
id INT PRIMARY KEY, # 主键
stuName VARCHAR(20) NOT NULL, # 非空
gender CHAR(1) CHECK(gender='男' OR gender='女'), # 检查,MySQL不支持
seat INT UNIQUE, # 唯一
age INT DEFAULT 18, # 默认
major_id INT FOREIGN KEY REFERENCES major(id) #外键,引用 major 表的 id
);
注意 六大约束语法上支持,但外键约束无效果!!!
[CONSTRAINT 约束名] 约束类型(字段名)
CREATE TABLE stuinfo(
id INT,
stuName VARCHAR(20),
gender CHAR(1),
seat INT,
age INT,
major_id INT,
PRIMARY KEY(id), # 主键
#PRIMARY KEY(id,stuName), # 表示两个列组合成一个主键,可单独重复,不可成对重复(不推荐!!!)
CONSTRAINT uq UNIQUE(seat), # 唯一键
FOREIGN KEY(major_id) REFERENCES major(id) # 外键
);
注意 除非空、默认以外,其他都支持
CREATE TABLE stuinfo(
id INT PRIMARY KEY,
stuName VARCHAR(20) NOT NULL,
gender CHAR(1),
age INT DEFAULT 18,
seat INT UNIQUE,
major_id INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(mayjor_id) REFERENCES major(id)
);
主键 和 唯一
唯一? | 非空? | 表中可以有多少个 | 允许组合? | |
---|---|---|---|---|
主键 | √ | × | 1 | √,但不推荐 |
唯一 | √ | √ | 可以多个 | √,但不推荐 |
外键特点
列级约束
ALTER TABLE 表名 MODIFY COLUMN 列名 类型 新约束条件;
ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
表级约束
ALTER TABLE 表名 ADD MODIFY [CONSTRAINT 约束名] 约束类型(字段名)[外键的引用];
ALTER TABLE stuinfo ADD MODIFY [CONSTRAINT ...] PRIMARY KEY(id);
删除非空约束
ALTER TABLE 表名 MODIFY COLUMN 列名 列类型; #省略约束条件 即 删除
# 删除主键
ALTER TABLE 表名 DROP PRIMARY KEY;
# 删除唯一键(即索引)
ALTER TABLE 表名 DROP INDEX 唯一键;
又称为自增长列
自增列的步长可以设置,起始值可以通过手动第一条插入的值进行设置
SET auto_increment_increment = 步长;
含义:可以不用手动插入的插入值,系统提供默认的序列值(默认从1开始)
注意:
创建表时
CREATE TABLE table1(
id INT PRIMARY KEY AUTO_INCREMENT ,
stuName VARCHAR(20)
);
# 插入时,id值可以乱填,一般可null
修改表时
# 添加
ALTER TABLE 表名 MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT ;
# 删除
ALTER TABLE 表名 MODIFY COLUMN id INT PRIMARY KEY ;
Transaction Control Language. 事务控制语言
一个或一组 sql 语句组成一个执行单元,在这个单元中,每个MySQL语句是相互依赖的。要么全部执行,要么全部不执行。(例:转账)
若某一句执行失败,就会回滚。
隐式事务:事务没有明显的开起和结束的标记
比如insert、update、delete语句
显式事务:事务具有明显的开启和结束的标记
**前提:**必须先设置自动提交功能为禁用
步骤一:开始事务
SET autocommit = 0; # 仅在当前询问有效
START TRANSACTION; # 可选
步骤二:编写事务中的 sql 语句(select、insert、update、delete)
...;
步骤三:结束事务(两种方式)
COMMIT; # 提交事务
ROLLBACK;# 回滚事务(即撤销)
哪些操作会使得事务自动提交?
set autocommit=false
对DDL操作无效原因:对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,没有采取必要的隔离机制。
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
read uncommitted | √ | √ | √ |
read committed(Oracle默认) | × | √ | √ |
repeatable read(MySQL默认) | × | × | √ |
serializable | × | × | × |
查看当前隔离级别:
SELECT @@tx_isolation;
设置隔离级别
set session transaction level 隔离级别; #只针对当前连接有效(连接,不是询问)
set GLOBAL session transaction level 隔离级别; # 设置数据库全局隔离级别
SET autocommit = 0; # 仅在当前询问有效
START TRANSACTION; # 可选
sql 语句 ... ;
SAVEPOINT a;
sql 语句 ... ;
ROllBACK TO a;
含义:虚拟表,和普通的表一样使用(MySQL 5.1 版本的新特性,是通过表动态生成的数据)
特点:只保存了 sql 逻辑,不保存查询结果
应用场景:
特点:
CREATE VIEW 视图名
AS
SELECT ... ... ;
方式一:
CREATE OR REPLACE VIEW 试图名 # 存在则修改
AS
查询语句;
方式二:
ALTER VIEW 视图名
AS
查询语句;
DROP VIEW 视图名1,试图名2,... ;
DESC 视图名;
SHOW CREATE VIEW 视图名;
注意: insert 对视图的修改会同步到原始表(因此一般给视图只读的权限)
+++
具有以下特点的视图不允许更新
join
等连接语句变量由系统提供,非用户定义,属于服务器局面
#① 查看所有的系统变量
SHOW GLOBAL|[SESSION] VARIABLES ;
#② 查看满足条件的部分系统变量
SHOW GLOBAL|[SESSION] VARIABLES LIKE '%char%';
#③ 查看指定的某个系统变量
SELECT @@[GLOBAL|SESSION.]系统变量名;
#④ 为某个系统变量赋值
SET GlOBAL|[SESSION] 系统变量名 = 值;
SET @@[GLOBAL|SESSION.]系统变量名 = 值;
**注:**如果是全局级别,需加 GLOBAL
如果是会话级别,可不写或写 SESSION
作用域:服务器每次启动将为所有的全局变量赋值,针对所有的会话(连接)有效。但不能跨重启!
作用域:聚聚针对当前会话(连接)有效
变量是用户自定义的,非系统定义
作用域:同于系统变量中的会话变量的作用域
可以应用在任何地方
#① 声明并初始化
SET @用户变量名 = 值 ;
SET @用户变量名 := 值 ;
SELECT @用户变量名 := 值 ;
#② 赋值(更新用户变量的值)
方式一: 再执行一遍①
方式二: SELECT 字段 INTO @用户变量名 FROM 表;
#③ 使用(查看、比较、运算等)
SELECT @用户变量名;
作用域:仅仅在定义它的 begin-end 中有效
注意 只能应用在 begin-end 中的第一句话
#① 声明(并声明)
DECLARE 变量名 类型 [ DEFAULT 值] ;
#② 赋值(更新)
SET 局部变量名 := 值;
SELECT @局部变量名 := 值;
SELECT 字段 INTO 局部变量名 FROM 表;
#③ 使用
SELECT 局部变量名;
存储过程和函数类似于 Java 中的方法
优点:
含义:一组预先编译好的 SQL 语句的集合,理解成批处理语句
优点:减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率。
DELIMITER 结束标记
CREATE PROCEDURE 存储过程名(参数列表)
BEGIN
存储过程体(方法体,一组合法的SQL语句)
END
# 调用
CALL 存储过程名(实参列表) 结束标记
注意
参数列表有三部分:参数模式、参数名、参数类型
如果存储过程体仅有一句话,则 begin-end 可以省略
存储过程中的每条 SQL 语句的结尾要求必须加分号
存储过程的结尾可以使用 DELIMITER 重新设置
DELIMITER 结束标记
####带空参
# 案例:插入到 admin 表中五条记录
DELIMITER $
CREATE PROCEDURE myp()
BEGIN
INSERT INTO admin(username,'password') VALUES
('john1',0000),
(...)
END $
####带 in 模式
# 案例:根据女神名,查询对应的男神信息
CREATE PROCEDURE myp(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('Lily')$
# 案例:验证用户是否登录成功
CREATE PROCEDURE myp(IN username VARCHAR(20),IN 'password' VARCHAR(20))
BEGIN
DECLARE result INT DEFAULT ''; # 声明并初始化
SELECT COUNT(*) INTO result #赋值
FROM admin a
WHERE a.username = username
AND a.'password' = 'password';
SELECT IF(result>0,'成功','失败'); #使用
END $
# 调用
CALL myp3('admin','123456') $
# 案例:根据女神名,返回男神名和魅力值
CREATE PROCEDURE myp(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT userCP INT)
BEGIN
SELECT bo.boyName,bo.userCP INTO boysName,userCP
FROM boys bo
INNER JOIN beauty b ON bo.id = b.boyfriend_id
WHERE b.name = beautyName
END $
# 调用
CALL myp('Lily',@bName,@userCP)$
# 案例1:翻倍
CREATE PROCEDURE myp(INOUT a INT,INOUT b INT)
BEGIN
SET a = a * 2;
SET b = b * 2;
END $
# 调用
SET @m = 8 $
SET @n = 10 $ # 先定义两个变量
CALL myp(@m,@n) $
SELECT @m,@n $
DROP PROCEDURE 存储过程名;
DROP PROCEDURE 存储过程名1,存储过程名2,...; ---> 不能这样用,一次只能删一个!!!
SHOW CREATE PROCEDURE 存储过程名;
注意 存储过程中逻辑语句不能修改
与存储过程的区别:
CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
BEGIN
函数体
RETURN 返回值; # 建议将 return 放在函数体的最后
END $
# 调用
SELECT 函数名(参数列表) $
参数列表:参数名 参数类型
# 案例:返回公司的员工个数
CREATE FUNCTION myf() RETURNS INT
BEGIN
DECLARE nums INT DEFAULT 0; # 声明变量并初始化
SELECT COUNT(*) INTO nums
FROM employees;
RETURN nums; # 返回变量
END $
# 调用
SELECT myf() $
# 案例:根据员名返回他的工资
CREATE FUNCTION myf(empName VARCHAR(20)) RETURNS DOUBLE
BEGIN
DECLARE sal DOUBLE DEFAULT 0;
SELECT salary INTO sal
FROM employees
WHERE last_name = empName;
RETURN sal;
END $
# 调用
SELECT myf('Lionel') $
SHOW CREATE FUNCTION 函数名;
DROP FUNCTION 函数名;
程序可以从两条或多条路径中选择一条执行
SELECT IF(表达式1,表达式2,表达式3);
若表达式1成立,则返回表达式2的值,否则返回表达式3的值
类似于 switch 语句,一般用于等值判断
CASE 变量|表达式|字段
WHEN 值1 THEN 要显示的(值1,)或(语句1;)
WHEN 值2 THEN 要显示的(值2,)或(语句2;)
...
ELSE 要显示的(值n,)或(语句n;)
END [CASE]; # 用在 begin—end 中 则需要加 case
类似于 多重 if…else 语句,一般用于实现区间判断
CASE
WHEN 条件1 THEN 要显示的(值1,)或(语句1;)
WHEN 条件2 THEN 要显示的(值2,)或(语句2;)
...
ELSE 要显示的(值n,)或(语句n;)
END [CASE]; # 用在 begin—end 中 则需要加 case
特点:
即可以作为表达式嵌套在其他语句中使用,可以放在任何地方
也可以作为独立的语句使用,则只能放在 begin-end 中
else 可以省略
如果省略了,且所有 when 条件都不满足,则返回 null
实现多重分支
IF 条件1 THEN 语句1;
ELSEIF 条件2 THEN 语句2;
... ...
[ELSE] 语句n;
END IF;
注意 只能应用在 begin-if 中
程序在满足一定条件的基础上,重复执行一段代码
分类:while、loop、repeat
循环控制:
[标签: ]WHILE 循环条件 DO
循环体;
END WHILE [标签] ;
# 案例:批量插入多条记录
CREATE PROCEDURE pro_while(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 0;
WHILE i
# 案例:批量插入多条记录,当次数大于20则停止
CREATE PROCEDURE pro_while(IN insertCount INT)
BEGIN
DECLARE i INT DEFAULT 0;
a: WHILE i20 THEN LEAVE a; # 跳出循环
END IF;
SET i = i + 1;
END WHILE a ;
END $
# 调用
CALL pro_while(100);
[标签:] LOOP
循环体
END LOOP [标签] ;
[标签:] REPEAT
循环体 ;
UNTIL 结束循环的条件
END REPEAT [标签] ;
当你在同一次连接中,执行一次 sql 语句时,会进行编译然后运行
若之后你再执行一次一模一样的 sql 语句,则会跳过编译直接执行