logo头像

我有一个梦想

mysql必知必会

本文于 1610 天之前发表,文中内容可能已经过时。

[TOC]

mysql是不区分大小写的

查看数据表的列表 ==== 设计表

1
show columns from xxx;

查看数据表的所有数据
1
select * from xxx;

distinct (只返回不同的值)

只返回不同vend_id的vend_id行

1
2
select distinct vend_id 
from products;

limit (限制结果)

返回前5行

1
2
select prod_name 
from products limit 5;

返回从第5行开始的后4行
1
2
select prod_name 
from products limit 5,4;

Mysql 5的语法
1
2
select prod_name 
from products limit 4 offset 3 ;

order by(排序)

按字母顺序排列

1
2
3
select prod_name 
from products
order by prod_name;

按两个列排序
1
2
3
select prod_id,prod_price,prod_name 
from products
order by prod_proce,prod_name;

desc (指定排序方向—逆序) asc(顺序)

按字母逆序排

1
2
3
select prod_id,prod_price,prod_name 
from products
order by prod_price desc;

按价格逆序,产品名顺序排

1
2
3
select prod_id,prod_price,prod_name 
from products
order by prod_price desc,prod_name;

where(过滤)

只返回prod_price的值为2.50的行

1
select prod_name,prod_price form products where prod_pricce = 2.50;

返回不是1003的行

1
2
3
select vend_id,prod_name 
from products
where vend_id != 1003; // != ====== <>

between(之间)

加载个5,10美元之间的所有产品

1
2
3
select prod_name,prod_price 
from products
where prod_price between 5 and 10;

检查具有NULL值的列

1
2
3
select prod_name 
from products
where prod_price is NULL;

and(满足所有给定条件的行) or(满足任意给定条件的行)

供应商1003制造且价格小于等于10美元的所有产品的名称和价格

1
2
3
select prod_id,prod_price,prod_name
from products
where vend_id = 1003 and prod_price <= 10;

供应商1003和1002制造的所有产品的产品名称和价格

1
2
3
select prod_name,prod_price
from products
where vend_id = 1002 or vend_id = 1003;

价格10美元以上且由1002或1003制造的产品

1
2
3
select prod_name,prod_price
from products
where vend_id = 1002 or vend_id = 1003 or prod_price >= 10;

in(制定条件范围)

检索供应商1002和1003制造的所有产品

1
2
3
4
5
6
7
8
9
10
11
select prod_name,prod_price 
from products
where vend_id in (1002,1003)
order by prod_name;

等效于

select prod_name,prod_price
from products
where vend_id = 1002 or vend_id == 1003
order by prod_name;

优点:

  1. 在使用长的合法选项清单时,in操作符的语法更清楚更直观
  2. 在使用in时,计算的次序更容易管理(因为使用的操作符更少)
  3. in操作符一般比or操作符清单执行更快
  4. in的最大有点事可以包含其他select语句,使得能够更加动态地建立where字句

not (否定where之后的所有的任何条件)

列出1002和1003之外的所有供应商制造的产品

1
2
3
4
select prod_name,prod_price
from products
where vend_id not in (1002,1003)
order by prod_name;

MySQL支持使用NOTINBETWEENEXISTS字句取反

like(用来匹配值的一部分的特殊字符,由字面值、通配符或两者组合构成的搜索条件)

通配符 :%(任何字符出现的任意次数)

检索任意以jet起头的词

1
2
3
select prod_id,prod_name
from products
where prod_name like 'jet%';

在搜索模式中任意位置是用,并且可以使用多个通配符

包含anvil值的行

1
2
3
select prod_id,prod_name
from products
where prod_name like '%anvil%';
通配符 :_ (与%用途一样,但只能匹配单个字符而不是多个字符)
1
2
3
select prod_id,prod_name
from products
where prod_name like '_ ton anvil';

注意:

  1. 通配符的处理一般花费的时间更长。所以不要过度使用。
  2. 除非绝对必要,否则不要将它们用在搜索模式的开始处,搜索起来是最慢的。
  3. 注意通配符的使用位置

正则表达式nanixie

检索prod_name包含文本1000的所有行

1
2
3
4
select prod_name
from products
where prod_name regexp '1000'
order by prod_name;
1
2
3
4
select prod_name
from products
where prod_name like '1000'
order by prod_name; xxxxxxxxxxxxxxxxxxxxxxxxxxxx

like的不会返回数据,like匹配整个列。如果被匹配的文本在列值中出现,like将不会找到他,除非使用通配符

Mysql正则表达式3.23.4后不区分大小写(即,大写和小写都匹配),为了区分可以使用binary关键字

如:

1
where prod_name regexp binary 'JetPack .000';

Concat()函数 (拼接两个列)

合并vend_name和vend_country为一个新列 vend_name(vend_country)

1
2
3
select Concat(vend_name,'(',vend_country,')')
from vendors
order by vend_name;
RTrim() (删除数据右侧多余的空格)
LTrim() (删除数据左侧多余的空格)

as(别名)

字段命名为vend_title

1
2
3
select Concat(RTrim(vend_name),'(',RTrim(vend_country),')') as vend_title
from vendors
order by vend_name;

数据表使用别名

1
2
3
4
5
select cust_name,cust_contact
from customers as c,orders as o,orderitems as oi
where c.cust_id = o.cust_id
and oi.order_num = o.order_num
and prod_id = 'TNT2';

创建计算字段

1
2
3
4
select pro_id,quantity,item_price,
quantity*item_price as expanded_price
from orderitems
where order_num = 20005;

Upper() (将文本转换为大写)

本例子中每个供应商都列出两次,第一次为vendors表中存储的值,第二次作为列vend_name_upcase转换为大写

1
2
3
select vend_name,Upper(vend_name) as vend_name_upcase
from vendors
order by vend_name;

常用文本处理函数

函数 说明
Left() 返回串左边的字符
Right() 返回串右边的字符
Length() 返回串的长度
Locate() 找出串的一个字串
Lower() 将串转换为小写
Upper() 将串转换为大写
RTrim() 删除数据右侧多余的空格
LTrim() 删除数据左侧多余的空格
Soundex() 返回串的SOUNDEX值(发音类似)
SubString() 返回字串的字符

1559722964(1)

注意:不管是插入或更新表值还是用WHERE字句进行过滤,日期必须为格式yyyy-mm-dd

1559723123(1)

1559723180(1)

DISTINCT (排除重复的值)

从 Company” 列中仅选取唯一不同的值

1
2
SELECT DISTINCT Company 
FROM Orders;

组合聚合函数

1
2
3
4
5
select COUNT(*) as num_items
MIN(prod_price) as price_min,
MAX(prod_price) as price_max,
AVG(prod_price) as price_avg
from products;

having(与where非常类似,where过滤行,having过滤组)

group by 子句指示MySQL分组数据,然后对每个组而不是整个结果集进行聚集

group by和order by的羁绊

order by group by
排序产生的输出 分组行。但输出可能不是分组的顺序
任意列都可以使用(甚至非选择的列也可以使用) 之坑内使用选择列或表达式列,而且必须使用每个选择列表达式
不一定需要 如果与聚集函数一期使用列(或表达式),则必须使用

一般在使用group by字句时,应该也给出order by字句。这是保证数据正确排序的唯一方法。千万不要仅依赖group by排序数据

检索总计订单价格大于等于50的订单的订单号和总计订单价格,按照ordertotal排序

1
2
3
4
5
select order_num,SUM(quantity*item_price) as ordertotal
from orderitems
group by order_num
having SUM(quantity*item_price) >= 50;
order by ordertotal;

子查询

定义:是嵌套其他查询的查询 等价于 联结

联结

inner join,left join,right join,full join的图

left join === left outer join

right join === right outer join

1161502-20170525223247919-507739436

内部联结

外键:某个表中存在其他表的主键即为该表的外键

两个表的关系是inner join指定,on的意义和where相同

1
2
3
select vend_name,prod_name,prod_price
from vendors inner join products
on vendors.vend_id = products.vend_id;
笛卡儿积

定义:由没有联结条件的表关系返回的结果为笛卡儿积

1
2
3
4
5
select prod_name,vend_name,prod_price,quantity
from orderitems,products,vendors
where products.vend_id = vendors.vend_id
and orderitems.prod_id = products.prod_id
and order_num = 20005;

联结的表越多,mysql的性能越差

自联结
1
2
3
4
5
select prod_id,prod_name
from products
where vend_id = (select vend_id
from products
where prod_id = 'DTNTR')

自己的表和自己的表进行联结查询

1
2
3
4
select p1.prod_id,p1.prod_name
from products as p1,products as p2
where p1.vend_id = p2.vend_id
and p2.prod_id = 'DTNTR';

有时候自联结比子查询查询的快得多

自然联结

定义:排除多次出现,使每个列只返回一次

迄今为止我们建立的每个内部联结都是自然联结,很有可能我们永远都不会用到不是自然联结的内部联结

外部联结

定义:相关表中没有关联行的行。这种类型的联结成为外部联结

1
2
3
select customers.cust_id,orders.order_num
from customers left outer join orders
on customers.cust_id = orders.cust_id

left outer join ,right outer join 所以存在左外部联结和右外部联结

mysql不支持简化字符=和=\的使用

使用联结和联结条件
  • 注意所使用的联结类型。一般我们使用内部联结,但使用外部联结也是有效的
  • 保证使用正确的联结条件,否则将返回不正确的数据
  • 应该总是提供联结条件,否则会得出笛卡儿积

select的字句顺序

select—–>from—–>where—–>group by—–>having—–>order by—–limit

组合查询

union操作符组合多条sql查询

1
2
3
4
5
6
7
select vend_id,prod_id,prod_price
from products
where prod_price <= 5
union
select vend_id,prod_id,prod_price
from products
where vend_id in (1001,1002)

union规则:

  • union必须由两条或两条以上的select语句组成,语句之间用关键字union分隔
  • union中的每个查询必须包含相同的列、表达式或聚集函数
  • 列数据类型兼容:类型不必完全相同,但必须是DBMS可以隐含地转换的类型

union自动去除重复的行,若不想去除重复行应该用union all

使用order by 会将返回的总结果集进行排序

搜索

  • 性能——通配符和正则表达式匹配通常要求MySQL尝试匹配表中所有行(而且这些搜索极少使用表索引)。因此,由于被搜索行数不断增加,这些搜索可能非常耗时。
  • 明确控制——使用通配符和正则表达式匹配,很难(而且并不总是能)明确地控制匹配什么和不匹配什么。例如,指定一个词必须匹配,一个词必须不匹配,而一个词仅在第一个词确实匹配地情况下才可以匹配或者才可以不匹配
  • 智能化地结果——虽然基于通配符和正则表达式地搜索提供了非常灵活地搜索,但他们都不能提供一种智能化的选择结果的方法。例如,一个特殊词的搜索将会返回包含该词的所有行,而不区分包含单个匹配的行和包含多个匹配的行(按照可能是最好的匹配来排列他们)。类似,一个特殊词的搜索将不会找出不包含该词但包含其他相关词的行。
1
2
3
4
5
6
7
8
9
CREATE TABLE productnotes
(
note_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;

MySQL根据字句FULLTEXT(note_text)的指示对它进行索引。

1
2
3
select note_text
from productnotes
where Macth(note_text) Against('rabbit');

查找productnotes中note_text中包含rabbit的note_text

等效于

1
2
3
select note_text
from productnotes
where note_text like '%rabbit%';

…………………………………………………………

插入数据

  • 插入完整的行
  • 插入行的一部分
  • 插入多行
  • 插入某些查询的结果
1
2
insert into Customers
values(NULL,'USA','zhangsan');
1
2
insert into Customers(cust_no,cust_country,cust_name) 
values(NULL,'USA','zhangsan');

在很多索引需要更新时,insert的操作可能会很耗时,而且他可能降低等待处理的select语句的性能。

如果数据检索式最重要的,则你可以通过在insert和into之间添加关键字LOW_PRIORITY,指示MySQL降低insert语句的优先级,如下所示:

INSERT LOW_PRIORITY INTO

顺便说一下,这也适用update和delete

多条insert语句,一次提交他们,每条语句用一个分号结束

1
2
insert xxxxx;
insert xxxxx;

只要insert中列名相同,则可以

1
2
insert into A(xx)
values(xx),(xx);

插入检索出的数据:把custnew中的数据参加到customers中,不会校验列名和类型

1
2
3
4
insert into customers(xxxx)
select xxxx
from custnew
where xxx;

更新和插入数据

  • 更新表中特定行
  • 更新表中所有行
1
2
3
update customers
set cust_email = 'xxx@163.com'
where cust_id = 10005;

update中可以使用子查询,

若更新多个数据,一旦出现一个错误,则整个update操作被取消(错误发生前更新的所有行被恢复到他们原来的值)。所以为了及时发生错误,也要继续进行更新,可以使用ignore关键字

1
update ignore customers...

delete删除整行,删除整列需要使用update语句

遵循的规则:

  • 除非确实打算更新和删除每一行,否则绝对不要使用不带where字句的update或delete语句
  • 保证每个表都有主键,尽可能像where字句那样使用它(可以指定各主键、多个值或值的范围)。
  • 在对update或delete语句使用where子句前,应该先用select进行测试,保证它过滤的是正确的记录,以防编写的where字句不正确。
  • 使用强制实施引用完整性的数据库,这样MySQL将不允许删除具有与其他表相关联的数据的行。

创建表

1
2
3
4
5
6
7
8
9
CREATE TABLE productnotes
(
note_id int NOT NULL AUTO_INCREMENT,
prod_id char(10) NOT NULL,
note_date datetime NOT NULL,
note_text text NULL,
PRIMARY KEY(note_id),
FULLTEXT(note_text)
) ENGINE=MyISAM;

AUTO_INCREMENT 自增列

DEFAULT 默认值

MySQL引擎

  • InnoDB是一个可靠的事务处理引擎,他不支持全文本搜索
  • MEMORY在功能等同于MyISAM,但由于数据存储在内存中,速度很快(特别适合于临时表)
  • MyISAM是一个性能极高的引擎,他支持全文本搜索,但不支持事务处理

更新表

1
2
3
4
5
6
7
8
9
10
11
12
//给表添加一个列
alter table vendors
add vend_phone char(20);

//删除刚刚添加的列
alter table vendors
drop column vend_phone;

//定义外键
alter table orderitems
add constraint fk_orderitems_orders
foreign key (order_num) references orders (order_num);

重命名表

多个表的重命名

1
2
3
rename table backup_customers to customers,
backup_vendors to vendors,
backup_products to products;

视图

  • 重用SQL语句
  • 简化复杂的SQL操作。在编写查询后,可以方便地重用他而不必知道他地基本查询细节
  • 使用表的组成部分而不是整个表
  • 保护数据。可以给用户授予表地特定部分地访问权限而不是整个表地访问权限。(我的理解————封装)
  • 更改数据格式和表示。视图可返回于底层表地表示和格式不同地数据

视图本身并不包含数据,所以每次使用视图时,都必须处理查询执行时所需的任一个检索

规则和限制:

  • 与表一样,视图必须唯一命名(不能给视图取与别的视图或表相同的名字)
  • 对于可以创建的视图数目没有限制
  • 为了创建视图,必须具有足够的访问权限。这些限制通常由数据库管理人员授予
  • 视图可以嵌套,即可以利用从其他视图中检索数据的查询来构造一个视图
  • order by可以用在视图中,但如果从该视图检索数据select中也含有order by,那么该视图中的order by将被覆盖
  • 视图不能索引,也不能有关联的触发器或默认值
  • 视图可以和表一期使用。例如,编写一条联结表和视图的select语句

创建一个名为productcustomers的视图,他联结了3个表,以返回已订购了任意产品的所有客户的列表

1
2
3
4
5
create view productcustomers as
select cust_name,cust_contact,prod_id
from customers,orders,orderitems
where customers.cust_id = orders.cust_id
and orderitems.order_num = orders.order_num;

为了检索订购了产品TNT2的客户,可如下进行:

1
2
3
select cust_name,cust_contact
from productcustomers
where prod_id = 'TNT2';

视图极大地简化了复杂SQL语句地使用

视图重新格式化检索出地数据

就是重新一直获取该数据,该数据可能随时变化

如果视图定义中存在以下操作,则不能进行视图地更新:

  • 分组(使用group by和having)
  • 联结
  • 子查询
  • 聚集函数
  • distinct
  • 导出(计算)列

存储过程

定义:为以后的使用而保存的一条或多条MySQL语句的集合

优势:

  • 把处理封装在容易使用的单元中,简化复杂的操作
  • 由于不要求反复建立一系列处理步骤,这保证了数据的完整性
  • 简化对变动的管理(封装后的安全性,改动少)
  • 提高性能,因为使用存储过程比使用单独的SQL语句要快
  • 存在一些只能在单个请求中的MySQL元素和特性,存储过程可以使用他们来编写功能更强更灵活的代码

总结:简单安全高性能

缺陷:

  • 存储过程的编写比基本SQL语句复杂,编写存储过程需要更高的技能,更丰富的经验
  • 你可能没有创建存储过程的访问安全权限

执行存储过程 函数式的mysql,存在参数

1
2
3
call productprcing(@pricelow
@pricehigh
@priceaverage);

其中,执行名为productpricing的存储过程,他计算并返回产品的最低、最高和平均价格

创建存储过程

一个返回产品平均价格的存储过程

1
2
3
4
5
create procedure productpricing()
begin
select avg(prod_price) as priceaverage
from products;
end;

mysql命令行客户机的分隔符

1
2
3
4
5
6
7
8
9
DELTMITER //

create procedure productpricing()
begin
select avg(prod_price) as priceaverage
from products;
end //

DELTMITER ;

DELIMITER // 告诉命令行使用程序使用//作为新的语句结束分割符

删除存储过程

1
drop procedure productpricing;

如果制定的过程不存在,则drop procedure将产生一个错误。当过程在想删除它时(如果过程不存在也不产生错误)可使用drop procedure if exists

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
CREARE PROCEDURE productpricing(
OUT pl DECIMAL(8,2),
OUT ph DECIMAL(8,2),
OUT pa DECIMAL(8,2)
)
BEGIN
SELECT Min(prod_price)
INTO pl
FROM products;
SELECT Max(prod_price)
INTO ph
FROM products;
SELECT Avg(prod_price)
INTO pa
FROM products:
END;

IN(传递给存储过程)、OUT(从存储过程传出,如这里使用)、INOUT(对存储过程传入和传出)

变量:内存中一个特定的位置,用来临时存储数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CALL productpricing(@pricelow,
@pricehigh,
@proceaverage);

SELECT @priceaverage;

SELECT @pricehigh,@pricelow,@priceaverage

CREAT PROCEDURE ordertotal(
IN onumber INT,
OUT ototal DECIMAL(8,2)
)
BEGIN
SELECT Sum(item_price * quantity)
FROM orderitems
WHERE order_num = onumber
INTO ototal;
END;

CALL ordertotal(20005,@total);

智能存储过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-- NAME:ordertotal
-- Parameters: onumber = order number
-- texable = 0 if not taxable,l if taxable
-- ototal = order total variable

CREATE PROCEDURE ordertotal(
IN onumber INT,
IN taxable BOOLEAN,
OUT ototal DECIMAL(8,2)
) COMMENT 'Obtain order total, optionlly adding tax'
BEGIN

-- Declare variable for total
DECLARE total DECIMAL(8,2);
-- Declare tax percentage
DECLARE taxrate INT DEFAULT 6;

-- GET the order total
SELECT Sum(item_price*quantity)
FROM orderitems
WHERE order_num = onumber
INTO total;

-- IS this taxable?
IF taxable THEN
-- Yes, so add taxrate to the total
SELECT total+(total/100*taxrate) INTO total;
END IF;

-- And finally, save to out variable
SELECT total INTO ototal;

END;

COMMENT

他不是必需的,但如果给出,将在SHOW PROCEDURE STATUS的结果中显示

SHOW PROCEDURE STATUS

获得包括何时、由谁创建等详细信息的存储过程列表

为限制其输出,可使用LIKE制定一个过滤模式

1
SHOW PROCEDURE STATUS LIKE 'ordertotal';

游标(cursor)

只能用于存储过程(函数)

使用过程:

  • 在能够使用游标前,必选声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的SELECT语句
  • 一旦声明后,必须打开游标以供使用。这个过程用前面定义的select语句把数据实际检索出来
  • 对于填有数据的游标,根据需要取出(检索)各行
  • 在结束使用时,必须关闭游标
1
2
3
4
5
6
7
8
9
CREATE PROCEDURE processorders()
BEGIN
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;
END;

OPEN ordernumbers;
CLOSE ordernumbers;

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE PROCEDURE processorders()
BEGIN

-- Declare local variables
DECLARE o INT;

-- Declare the cusor
DECLARE ordernumbers CURSOR
FOR
SELECT order_num FROM orders;

-- Open the cursor
OPEN ordernumbers;

-- Get oder number
FETCH ordernumbers INTO 0;

-- Close the cursor
CLOSE ordernumbers;
END;

其中FETCH用来检索当前行的order_num列(将自动从第一行开始)到一个名为o的局部声明变量中。

将获取的结果存储在游标中。

触发器

DELETE、INSERT、UPDATE中触发,其他MySQL语句都不支持触发器

创建时:

  • 唯一的触发器名
  • 触发器关联的表

  • 触发器应该响应的活动( DELETE、INSERT或UPDATE)

  • 触发器何时执行(处理之前或之后)
1
2
CREATE TRIGGER newproduct AFTER INSERT ON products
FOR EACH ROW SELECT 'Product added';

创建名为newproduct的新触发器,此触发器将在INSERT语句成功执行后执行,还指定FOR EACH ROW,因此代码对每个插入行执行。

使用INSERT语句添加一行或多行到products中,你将看到对每个成功的插入,显示Product added消息

只有表才支持触发器,视图和临时表都不支持

每个表最多支持6个触发器

触发器失败:

如果BEFORE触发器失败,则MySQL将不执行请求的操作。此外,如果BEFORE触发器或语句本身失败,MySQL将不执行AFTER触发器(如果有的话)

删除触发器

1
DROP TRIGGER newproduct;
INSERT触发器(适用于UPDATE)
  • 在INSERT触发器大麻中,可引用一个名为NEW的虚拟表,访问被插入的行
  • 在BEFORE INSERT触发器中,NEW中的值也可以被更新(允许更改被插入的值)
  • 对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值
1
2
CREATE TRIGGER neworder AFTER INSERT ON orders
FOR EACH ROW SELECT NEW.order_num;

触发器名为neworder ,在orders的INSERT方法中返回NEW.order_num数值

BEFORE或AFTER?

通常,将BEFORE用于数据验证和净化(目的是保证插入表中的数据确实是需要的数据)

DELETE触发器
  • 在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行
  • OLD中的值全都是只读的,不能更新
1
2
3
4
5
6
CREATE TRIGGER deleteorder BEFORE DELETE ON orders
FOR EACH ROW
BEGIN
INSERT INTO archive_orders(order_num,order_date,cust_id)
VALUES(OLD.order_num,OLD.order_date,OLD.cust_id);
END;

在任意订单删除前将执行此触发器,它使用一条INSERT语句将OLD中的值(要被删除的订单)保存到一个名为archive_orders的存档表中(为实际使用这个例子,你需要用与orders相同的列创建一个名为archive_orders的表)

使用BEFORE EDLETE触发器的优点(相对于AFTER DELETE触发器来说)为,如果由于某种原因,订单不能存档,SELETE本身将被废弃

使用BEGIN和END语句标记触发器体。在这个例子中并不是必需的,不过也没有害处,使用BEGIN END块的好处是触发器能容纳多条SQL语句

UPDATE触发器
  • 在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新更新的值
  • 在BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值)
  • OLD中的值全都是只读的,不能更新
1
2
CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors
FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_state);

每次更新一个行时,NEW.vend_state中的值(将用来更新表行的值)都用Upper(NEW.vend_state)替换

注意
  • 与其他DBMS想比,MYSQL 5中支持的触发器相当初级。未来的MySQL版本中有一些改进和增强触发器支持的计划
  • 创建触发器可能需要特殊的安全访问权限,但是,触发器的执行是自动的。如果INSERT、UPDATE或DELETE语句能够执行,则相关的触发器也能执行
  • 应该用触发器来保证数据的一致性(大小写、格式等)。在触发器中执行这种类型的处理的有点是它总是进行这种处理,而且是透明地进行,与客户机应用无关
  • 触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,把更改(如果需要,甚至还有之前和之后的状态)记录到另一个表非常容易
  • 遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码需要复制到触发器内。

事务

定义:事务处理可以用来维护数据库的完整性,它保证成批的MySQL操作要么完全执行,要么完全不执行

  • 事务(transaction)指一组SQL语句
  • 回退(rollback)指撤销指定SQL语句的过程
  • 提交(commit)指将未存储的SQL语句结果写入数据库表
  • 保留点(savepoint)指事务处理中设置的临时占位符(place-holder),你可以对它发布回退(与回退整个事务处理不同)
1
2
3
4
5
6
SELECT * FROM ordertotals;
START TRANSACTION;
DELETE FROM ordertotals;
SELECT * FROM ordertotals;
ROLLBACK;
SELECT * FROM ordertotals;

ROLLBACK只能在一个事务处理内使用(在执行一条START TRANSACTION命令之后)

事务处理用来管理INSERT、UPDATE和DELETE语句。SELECT、CREATE、DROP无法被回退

1
2
3
4
START TRANSACTION;
DELETE FROM orderitems WHERE order_num = 20010;
DELETE FROM orders WHERE order_num = 20010;
COMMIT;

如果第一条DELETE起作用,但第二条失败,则DELETE不会提交(实际上,他是被自动撤销的)

1
2
3
4
5
-- 新建保留点
SAVEPOINT delete1;

-- 回退到保留点
ROLLBACK TO delete1;

保留点越多越好,就能案子的意愿灵活的进行回退

释放保留点,事务完成(执行一条ROLLBACK或COMMIT)后自动释放,

​ 也可用 RELEASE SAVEPORINT 明确地释放保留点

1
2
-- 指示MySQL不自动提交更改
SET autocommit=0;

全球化和本地化

字符集:字母和符号地集合

编码:某个字符集成员地内部表示

校对:规定字符如何比较地指令

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 显示所有可用地字符集以及每个字符集的描述和默认校对
SHOW CHARACTER SET;

-- 显示所有可用的校对,以及他们使用的字符集
SHOW COLLATION;

--
CREATE TABLE mytable
(
columnn1 INT,
columnn2 VARCHAR(10)
)DEFAULT CHARACTER SET hebrew
COLLATE hebrew_general_ci;

此语句创建一个包含两列的表,并且指定一个字符集和一个校对顺序

这个例子中指定了CHARACTER SET和COLLATE两者。一般,MySQL如下确定使用什么样的字符集和校对

  • 如果指定CHARACTER SET和COLLATE两者,则使用这些值。
  • 如果只指定CHARACTER SET,则使用此字符集及其默认的校对
  • 如果既不指定CHARACTER SET,也不指定COLLATE,则使用数据库默认

安全管理

数据库维护

改善性能

数据库范式

第一范式(1NF)

数据库表的每一列都是不可分割的原子数据项,无重复的域

第二范式(2NF)

满足第二范式,则必定符合第一范式。数据库表中的每个实例或记录必须可以被唯一的区分。

要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性

第三范式(3NF)

在2NF的基础上,任何非主属性不依赖于其他非主属性,表中不能存在非其它表中非主键的字段。(排除冗余)