这篇文章上次修改于 864 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

主键

主键(primary key)一列(或一组列),其值能够唯一区分表中每个行。

表中的任何列都可以作为主键,只要它满足以下条件:

 任意两行都不具有相同的主键值;

 每个行都必须具有一个主键值(主键列不允许NULL值)。

 不更新主键列中的值;

 不重用主键列的值;

 不在主键列中使用可能会更改的值

show

SHOW TABLES;
//返回当前选择的数据库内可用表的列表。
SHOW COLUMNS from table1;
DESCRIBE customers;
//是 SHOW COLUMNS FROM customers;的一种快捷方式。

要 求 给 出 一 个 表 名 ( 这 个 例 子 中 的 FROM customers),它对每个字段返回一行,行中包含字段名、数据类型、是否允许NULL、键信息、默认值以及其他信息(如字段cust_id的 auto_increment)。

image-20211207091104096

HELP SHOW;显示允许的SHOW语句。

Select

select distinct  id from products;
//SELECT DISTINCT vend_id告诉MySQL只返回不同(唯一)的id行,使用DISTINCT关键字,它必须直接放在列名的前面

//不能部分使用DISTINCT DISTINCT关键字应用于所有列而 不仅是前置它的列。如果给出SELECT DISTINCT vend_id, prod_price,除非指定的两个列都不同,否则所有行都将被 检索出来
LIMIT 5指示MySQL返回 不多于5行。
LIMIT 5, 5指示MySQL返回从行5开始的5行。第一个数为开始位置,第二个数为要检索的行数。

行数从0

 LIMIT 4 OFFSET 3意为从行3开始取4行,就像LIMIT 3, 4一样

排序 order by

默认升序

为了明确地排序用SELECT语句检索出的数据,可使用ORDER BY子句。

ORDER BY子句取一个或多个列的名字,据此对输出进行排序。

可以使用非显示列 进行排序

select  id from products order by name;
多列排序

为了按多个列排序,只要指定列名,列名之间用逗号分开即可(就像选择多个列时所做的那样)。

select  id from products order by price,name;

先按price排序,相同price 按 name 排序

降序 order by desc
*** order by price desc;
//DESC关键字只应用到直接位于其前面的列名

*** order by price desc, name;
// 降序排price , 再排name

where

​ between low and high

​ where name IS NULL // 判断空值

where name='abc';
// abc和ABC mysql中默认相同

单引号用来限定字符串。如果将值与串类型的列进行比较,则需要限定引号。用来与数值列进行比较的值不
用引号。

and or

SQL(像多数语言一样)在处理OR操作符前,优先处理AND操作符。

where (a=1 or b=2 ) and c=3;

任何时候使用具有AND和OR操作符的WHERE子句,都应该使用圆括号明确地分组操作符。不要过分依赖默认计算次序,即使它确实是你想要的东西也是如此。使用圆括号没有什么坏处,它能消除歧义。

in not

IN操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN取合法值的由逗号分隔的清单,全都括在圆括号中。

where id in (100,200)   // 100 或 200 

为什么要使用IN操作符?其优点具体如下。
 在使用长的合法选项清单时,IN操作符的语法更清楚且更直观。
 在使用IN时,计算的次序更容易管理(因为使用的操作符更少)。
 IN操作符一般比OR操作符清单执行更快。
 IN的最大优点是可以包含其他SELECT语句,使得能够更动态地建立WHERE子句。

NOT WHERE子句中用来否定后跟条件的关键字。

not in (a,b)

like

为在搜索子句中使用通配符,必须使用LIKE操作符

LIKE指示 MySQL 后跟的搜索模式利用通配符匹配而不是直接相等匹配进行比较。

% 任何字符任意次数

最常使用的通配符是百分号(%)。在搜索串中,%表示任何字符出现任意次数

image-20211207101953246

还可以使用

%abc%     匹配  ( 100abc21 ,    abc3  , 1abc )

即使是WHERE prod_name LIKE '%'也不能匹配用值NULL作为产品名的行。

_ 任意字符 1 次

匹配任意字符 但下划线只匹配单个字符而不是多个字符。

正则

REGEXP 关键字

where name regexp '1000';

image-20211207104318527

LIKE匹配整个串而REGEXP匹配子串。利用定位符,通过用^开始每个表达式,用$结束每个表达式,可以使
REGEXP的作用与LIKE一样。

MySQL中的正则表达式匹配(自版本3.23.4后)不区分大小写(即,大写和小写都匹配)。为区分大
小写,可使用BINARY关键字,如

WHERE prod_name REGEXP BINARY 'JetPack .000'

两个以上的OR条件 可以给出两个以上的OR条件。例如,'1000 | 2000 | 3000'将匹配1000或2000或3000

转义 \\

为了匹配特殊字符,必须用\\为前导。

\\- 表示查找- \\.表示查找.

为了匹配反斜杠(\)字符本身,需要使用\\\

多数正则表达式实现使用单个反斜杠转义特殊字符,以便能使用这些字符本身。但MySQL要求两个反斜杠(MySQL
自己解释一个,正则表达式库解释另一个)

image-20211207104911297

image-20211207105037565

定位

image-20211207105144297

计算字段 和 函数

计算字段并 不实际存在于数据库表中。计算字段是运行时在SELECT语句内创建的。

拼接Concat()

在MySQL的SELECT语句中,可使用 Concat()函数来拼接两个列。

Concat()需要一个或多个指定的串,各个串之间用逗号分隔。

多数DBMS使用+或||来实现拼接,MySQL则使用Concat()函数来实现。当把SQL语句转换成MySQL语句时一定要把这个区别铭记在心。

image-20211207110011587

Trim()去空格

RTrim() LTrim() Trim()

select Concat( RTrim(name) , '(' , RTrim(country) , ')' ) from vendors order by name;

alias

从前面的输出中可以看到,SELECT语句拼接地址字段工作得很好。但此新计算列的名字是什么呢?实际上它没有名字,它只是一个值。一个未命名的列不能用于客户机应用中,因为客户机没有办法引用它。

别名用AS关键字赋予。

select Concat( RTrim(name) , '(' , RTrim(country) , ')' ) as myname  from vendors order by name;

client可以用 别名 当作列名 去使用

别名还有其他用途。常见的用途包括在实际 的表列名包含不符合规定的字符(如空格)时重新命名它,在
原来的名字含混或容易误解时扩充它

别名除了用于列名和计算字段外,SQL还允许给表名起别名。这样做有两个主要理由:
 缩短SQL语句;
 允许在单条SELECT语句中多次使用相同的表。

应该注意,表别名只在查询执行中使用。与列别名不一样,表别名不返回到客户机。

select 
from table1 as a, table2 as b
where

算术计算

计算字段的另一常见用途是对检索出的数据进行算术计算

image-20211207110735865

支持 加减乘除

数据处理函数

能运行在多个系统上的代码称 为可移植的(portable)。相对来说,多数SQL语句是可移植的,
在SQL实现之间有差异时,这些差异通常不那么难处理。而函 数的可移植性却不强。几乎每种主要的DBMS的实现都支持其 他实现不支持的函数,而且有时差异还很大。

文本处理函数

Trim()去空格

Upper()转大写

Length() 返回串长

Left() 返回串左边的字符

Locate() 找出串的一个子串

Lower() 将串转换为小写

LTrim() 去掉串左边的空格

Right() 返回串右边的字符

RTrim() 去掉串右边的空格

SubString() 返回子串的字符

Soundex() 返回串的SOUNDEX值

SOUNDEX是一个将任何文本串转换为描述其语音表示的字母数字模式的算法。SOUNDEX考虑了类似的发音字符和音节,使得能对串进行发音比较而不是字母比较。

image-20211207111511553

日期和时间处理函数

一般,应用程序不使用用来存储日期和时间的格式,因此日期和时间函数总是被用来读取、统计和处理这些值。由于这个原因,日期和时间函数在MySQL语言中具有重要的作用。

不管是插入或更新表值还是用WHERE子句进行过滤,日期必须为格式yyyy-mm-dd。因此,2005年9月1日,给出为2005-09-01。虽然其他的日期格式可能也行,但这是首选的日期格式,因为它排除了多义性

image-20211207112051616

基本的日期比较

where data='2002-05-15'

比 如 , 存 储 的 order_date 值 为 2005-09-01 11:30:05,则WHERE order_date = '2005-09-01'失败。

即使给出具有该日期的一行,也不会把它检索出来,因为WHERE匹配失败。

MySQL仅将给出的日期与列中的日期部分进行比 较,而不是将给出的日期与整个列值进行比较

为此,必须使用Date() 函数。Date(order_date)指示MySQL仅提取列的日期部分

where  Date(data)='2002-05-15'

如果你想检索出2005年9月下的 所有订单,怎么办?

where  Date(data) between '2002-05-01' and  '2002-05-31'

where Year(data)=2002 and Month(data)=5;

数值处理

这些函数一般主要用于代数、三角 或几何运算,

image-20211207112658152

汇总表本身信息

我们经常需要汇总数据而不用把它们实际检索出来,为此MySQL提 供了专门的函数。使用这些函数,MySQL查询可用于检索数据,以便分 析和报表生成。

确定表中行数(或者满足某个条件或包含某个特定值的行数)。

获得表中行组的和。

找出表列(或所有行或某些特定的行)的最大值、最小值和平均值

上述例子都需要对表中数据(而不是实际数据本身)汇总。因此 , 返回实际表数据是对时间和处理资源的一种浪费(更不用说带宽了)。重 复一遍,实际想要的是汇总信息。

image-20211207112943225

AVG

只用于单个列 AVG()只能用来确定特定数值列的平均值,而 且列名必须作为函数参数给出。为了获得多个列的平均值, 必须使用多个AVG()函数。

AVG()函数忽略列值为NULL的行。

Count

可利用COUNT()计算行的数目。

COUNT()函数有两种使用方式。

​ 使用COUNT(*)对表中行的数目进行计数,不管表列中包含的是空值(NULL)还是非空值。

​ 使用COUNT(column)对特定列中具有值的行进行计数,忽略NULL值

MAX / MIN

MAX()返回指定列中的最大值。MAX()要求指定列名

在用于文本数据时,如果数据按相应的列排序,则MAX()返回最后一行。MIN()返回最前面的行

忽略列值为NULL的行

SUM

SUM()用来返回指定列值的和(总计)。

distinct 排除
select AVG( DISTINCT price  ) from products where id =10086;

只对不同价格的商品计算平均值

分组

单个组 的聚集函数 可以统计 Count /Sum 等

但如果要返回多个有细微区别的 组的数据

这就是分组显身手的时候了。分组允许把数据分为多个逻辑组,以 便能对每个组进行聚集计算。

在具体使用GROUP BY子句前,需要知道一些重要的规定。

 GROUP BY子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供更细致的控制。

 如果在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总。换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别的列取回数据)。

 GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。如果在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式。不能使用别名。

 除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。

 如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。

 GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。

创建分组 group by

SELECT语句的GROUP BY子句中建立的

select id,count(*) from products group by id;

image-20211207114232745

使用ROLLUP 使用WITH ROLLUP关键字,可以得到每个分组以 及每个分组汇总级别(针对每个分组)的值

 select vend_id ,count(*) as num_prods from products group by vend_id with rollup ;

image-20211207114734309

过滤分组 having

HAVING非常类似于WHERE。事实上,目前为止所 学过的所有类型的WHERE子句都可以用HAVING来替代。唯一的差别是 WHERE过滤行,而HAVING过滤分组。

image-20211207125607913

分组不等于排序, 有了 Group By 不要忘记使用 Order By 来确保正确顺序

select vend_id ,count(*) as num_prods from products group by vend_id  having  num_prods >100  order by num_prods ;
// 此语句     用count 计算 num , 按照 id 分组 , 保留 num >50 , 并按照  num  排序

select 中 各个字句 先后顺序

select 
from
where
group by
having
order by
limit

子查询

SQL还允许创建子查询(subquery),即嵌套在其他查询中的查询

select id from others where order_num in (20005,20007)

select id from others where order_num in (
    select order_num from orderitems where prod_id = 'TNT2'
)

可见,在WHERE子句中使用子查询能够编写出功能很强并且很灵活的 SQL语句。对于能嵌套的子查询的数目没有限制,不过在实际使用时由于 性能的限制,不能嵌套太多的子查询。

image-20211207165247697

联结 join

外键(foreign key) 外键为某个表中的一列,它包含另一个表 的主键值,定义了两个表之间的关系。

// 情景模拟
假如有一个包含产品目录的数据库表,其中每种类别的物品占一行。对于每种物品要存储的信息包括产品描述和价格,以及生产该产品的供应商信息。假如有由同一供应商生产的多种物品,那么在何处存储供应商信息(如,供应商名、地址、联系方法等)呢

关系表的设计就是要保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(即关系设计中的关系(relational))互相关联。

在这个例子中,可建立两个表,一个存储供应商信息,另一个存储产品信息。vendors表包含所有供应商信息,每个供应商占一行,每个供应商具有唯一的标识。此标识称为主键(primary key)(在第1章中首次提到),可以是供应商ID或任何其他唯一值。

products表只存储产品信息,它除了存储供应商ID(vendors表的主键)外不存储其他供应商信息。vendors表的主键又叫作products的外键,它将vendors表与products表关联,利用供应商ID能从vendors表中找出相应供应商的详细信息。

这样做的好处如下:
 供应商信息不重复,从而不浪费时间和空间;
 如果供应商信息变动,可以只更新vendors表中的单个记录,相关表中的数据不用改动;
 由于数据无重复,显然数据是一致的,这使得处理数据更简单。

如果数据存储在多个表中,怎样用单条SELECT语句检索出数据?
答案是使用联结。简单地说,联结是一种机制,用来在一条SELECT
语句中关联表,因此称之为联结。使用特殊的语法,可以联结多个表返
回一组输出,联结在运行时关联表中正确的行。

如果在products表中插入拥有非法供应商ID(即没有在vendors表中出现)的供应商生产的产品,则这些
产品是不可访问的,因为它们没有关联到某个供应商。
为防止这种情况发生,可指示MySQL只允许在products表的供应商ID列中出现合法值(即出现在vendors表中的供应商)。
这就是维护引用完整性,它是通过在表的定义中指定主键和外键来实现的。

创建联结

where table1.id=table2.id

笛卡儿积(cartesian product) 由没有联结条件的表关系返回的结果为笛卡儿积。检索出的行的数目将是第一个表中的行数乘以第二个表中的行数。

内连结

目前为止所用的联结称为等值联结(equijoin),它基于两个表之间的相等测试。这种联结也称为内部联结

内连结有关键词 Inner Join on

select * 
from table1 inner join table2 on table1.id=table2.id

尽量不要使用 * 通配符在 内连结 ,有 笛卡尔积问题

自联结

select p1.id , p1.name 
from products as p1,products as p2
where p1.id=p2.id and p2.id='abc'

对表设置别名 对一张表设置两个别名 分别使用

用自联结而不用子查询 自联结通常作为外部语句用来替代 从相同表中检索数据时使用的子查询语句。虽然最终的结果是 相同的,但有时候处理联结远比处理子查询快得多。

自然联结

无论何时对表进行联结,应该至少有一个列出现在不止一个表中(被联结的列)。

内部联结)返回所有数据,甚 至相同的列多次出现。自然联结排除多次出现,使每个列只返回一次

系统不完成这项工作,由你自己完成它。自然联结是这样一种联结,其中你只能选择那些唯一的列。这一
般是通过对表使用通配符(SELECT *),对所有其他表的列使用明确的子集来完成的。

image-20211207192551674

外部联结

许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行

from table1 right outer join table2  on table1.id=table2.id

使用outer join 语法时必须指定 right 还是 left

在使用OUTER JOIN语法时,必须使用RIGHT或LEFT关键字 指定包括其所有行的表(RIGHT指出的是OUTER JOIN右边的表,而LEFT 指出的是OUTER JOIN左边的表)

image-20211207193124571

表中指定 left outer join 指定了 customers 为拥有所有行的表 , 所以 cust_id 不为空, orders 表可能有空

存在两种基本的外部联结形式:左外部联结 和右外部联结。它们之间的唯一差别是所关联的表的顺序不
同。换句话说,左外部联结可通过颠倒FROM或WHERE子句中 表的顺序转换为右外部联结。因此,两种类型的外部联结可互
换使用,而究竟使用哪一种纯粹是根据方便而定。

组合查询union

MySQL也允许执行多个查询(多条SELECT语句),并将结果作为单个
查询结果集返回。

有两种基本情况,其中需要使用组合查询:
 在单个查询中从不同的表返回类似结构的数据;
 对单个表执行多个查询,按单个查询返回数据。

利用UNION,可给出多条SELECT语句,将它们的结果组合成单个结果集。

UNION的使用很简单。所需做的只是给出每条SELECT语句,在各条语句之间放上关键字UNION。

image-20211207194637041

image-20211207194643905

select  1
union
select  2

//等价于

select 
where 1 or 2

在这个简单的例子中,使用UNION可能比使用WHERE子句更为复杂。但对于更复杂的过滤条件,或者从多个表(而不是单个表)中检索数据 的情形,使用UNION可能会使处理更简单。

UNION中的每个查询必须包含相同的列、表达式或聚集函数(不过各个列不需要以相同的次序列出)。

UNION从查询结果集中自动去除了重复的行

这是UNION的默认行为,但是如果需要,可以改变它。事实上,如果 想返回所有匹配行,可使用UNION ALL而不是UNION。

UNION ALL为UNION的一种形式,它完成 WHERE子句完成不了的工作。如果确实需要每个条件的匹配行全
部出现(包括重复行),则必须使用UNION ALL而不是WHERE。

对组合查询结果排序

最后一条 select 的 order by 对整个结果集 起作用

SELECT语句的输出用ORDER BY子句排序。在用UNION组合查询时,只 能使用一条ORDER BY子句,它必须出现在最后一条SELECT语句之后。对 于结果集,不存在用一种方式排序一部分,而又用另一种方式排序另一 部分的情况,因此不允许使用多条ORDER BY子句。

全文本搜索 (待补充)

并非所有引擎都支持全文本搜索 正如第21章所述,MySQL 支持几种基本的数据库引擎。并非所有的引擎都支持本书所描 述的全文本搜索。两个最常使用的引擎为MyISAM和InnoDB, 前者支持全文本搜索,而后者不支持

如果你的应用中需要全文本搜索功能,应该记住这一点

插入 更新 删除

 插入完整的行;
 插入行的一部分;
 插入多行;
 插入某些查询的结果

insert

insert into table1 (colum1,colum2,....) values ('a','b','c');

如果 检索 比 插入重要

insert low priority into .....

多行插入

insert into table1 (colum1,colum2,....) values 
('a','b','c'),
('b','c','d');

insert select ( 注意 不含主键 ??)

insert into table1 (colum1,colum2,....)
select  colum1,colum2,....
from table2;

INSERT SELECT中的列名不一定要求列名匹配。

事实上,MySQL甚至不关心SELECT返回的列名。它使用的是 列的位置,因此SELECT中的第一列(不管其列名)将用来填充 表列中指定的第一个列,第二列将用来填充表列中指定的第二个列,

update

省略 where 会 更新表所有 行

update table1 
set column1='2' ,column2='3' 
where   ...

在UPDATE语句中使用子查询 UPDATE语句中可以使用子查 询,使得能用SELECT语句检索出的数据更新列数据。

ignore 关键字 如果用UPDATE语句更新多行,并且在更新这些 行中的一行或多行时出一个现错误,则整个UPDATE操作被取消 (错误发生前更新的所有行被恢复到它们原来的值)。为即使是发生错误,也继续进行更新,可使用IGNORE关键字,如下所示:

UPDATE IGNORE ......

update set =null 置为空,删除效果

delete

省略 where 会 删除表所有 行

delete from table1
where

DELETE删除整行而不是删除列。为了 删除指定的列,请使用UPDATE语句。

创建摧毁表

create

create table name1
(
    column1 type1 ...  ,
    column1 type1 ...  ,
)Engine=InnoDB
PRIMARY KEY

表的主键可以在创建表时用 PRIMARY KEY关键字指定。

primary key ( column1 ,column2 )

image-20211207205757751

AUTO_INCREMENT 自增

每个表只允许一个AUTO_INCREMENT列,而且它必须被索引(如,通过使它成为主键)。

那么,如何在使用AUTO_INCREMENT列时获得这个值呢?

select last_insert_id() 

此语句返回最后一个AUTO_INCREMENT值,然后可以将它用于 后续的MySQL语句。

IF NOT EXISTS

如果你仅想在一个表不存在时创建它,应该在表名后给出IF NOT EXISTS。这样做不检查已有表的模式是否与你打算创建 的表模式相匹配。它只是查看表名是否存在,并且仅在表名不 存在时创建它。

NULL

创建表时 指定列 能否为空值

主键中只能使用不允许NULL值的列

default
 column1 type1  NOT NULL  DEFAULT 1 ,
engine

image-20211207210620031

外键不能跨引擎 混用引擎类型有一个大缺陷。外键(用于 强制实施引用完整性,如第1章所述)不能跨引擎,即使用一 个引擎的表不能引用具有使用不同引擎的表的外键。

foreign key
CREATE TABLE Orders
(
        O_Id int NOT NULL,
        OrderNo int NOT NULL,
        P_Id int,
    PRIMARY KEY (O_Id),
    
    FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
    //如需命名 FOREIGN KEY 约束,并定义多个列的 FOREIGN KEY 约束
    CONSTRAINT fk_PerOrders FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)
    
)

update

ALTER TABLE

add

alter table table1 add  
column1 type1  NOT NULL  DEFAULT 1 ;

drop

alter table table1 drop
column1 ;

外键

alter table table1
add 
foreign key ( table1.colnm1 ) references table2 (table2.colnm2 )

如需命名 FOREIGN KEY 约束,并定义多个列的 FOREIGN KEY 约束,请使用下面的 SQL 语法:

ALTER TABLE Orders
ADD CONSTRAINT fk_PerOrders
FOREIGN KEY (P_Id) REFERENCES Persons(P_Id)

撤销外键

ALTER TABLE Orders
DROP FOREIGN KEY fk_PerOrders

一个表中的 FOREIGN KEY 指向另一个表中的 UNIQUE KEY(唯一约束的键)。

drop

drop table table1;

rename

rename table table1 to table2;

视图

视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询。

作为视图,它不包含表中应该有的任何列或数据,它包含的是一个SQL查询的数据

下面是视图的一些常见应用。

 重用SQL语句。

 简化复杂的SQL操作。在编写查询后,可以方便地重用它而不必知道它的基本查询细节。

 使用表的组成部分而不是整个表。

 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。

 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。

重要的是知道视图仅仅是用来查看存储在别处的数据的一种设施。视图本身不包含数据,因此它们返回的数据是从其他表中检索出来的。在添加或更改这些表中的数据时,视图将返回改变过的数据。

最常见的规则和限制。

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

创建

CREATE VIEW语句

用SHOW CREATE VIEW viewname;来查看创建视图的语句。

DROP删除视图,其语法为DROP VIEW viewname;。

更新视图时,可以先用DROP再用CREATE,也可以直接用CREATE OR REPLACE VIEW。

create view viewname1 as 
select ...
....;
select * from viewname1;

常用来格式化一些 数据

image-20211208124935876

更新

更新一个视图将更新其基表

但是,并非所有视图都是可更新的。基本上可以说,如果MySQL不 能正确地确定被更新的基数据,则不允许更新(包括插入和删除)。这实 际上意味着,如果视图定义中有以下操作,则不能进行视图的更新

group by 
having
连结
子查询
并
聚集函数 Distinct
导出(计算)列。

将视图用于检索 一般,应该将视图用于检索(SELECT语句) 而不用于更新(INSERT、UPDATE和DELETE)

存储过程

存储过程简单来说,就是为以后的使用而保存 的一条或多条MySQL语句的集合。可将其视为批文件

调用

call funname1 ( 
    arg1, 
    arg2  // 可选参数
) 

创建

create procedure funname1( 可选参数 )
begin
    select .....
    from ... ;
end;

//如果存储过程接受参数,它们将在()中列举出来。此存储过程没
有参数,但后跟的()仍然需要。BEGIN和END语句用来限定存储过程体,过
程体本身仅是一个简单的SELECT语句

删除

drop procedure funame1;
drop procedure IF EXISTS funname1;

使用参数

创建
create procedure funname1( 
    out p1 decimal(8,2),
    out p2 decimal(8,2),
    out p3 decimal(8,2),
)
begin
    select Min(price)
    into p1
    from products;
    
    select Max(price)
    into p2
    from products;
    
    select Avg(price)
    into p3
    from products;
end;

解析

  1. 参数 p1,p2,p3 都是 out 参数 用来传出

    in  传入参数
    out 传出参数
    inout  传入传出参数
    
    decimal 十进制
  1. into 用来给变量赋值

记录集不是允许的类型,因此,不能通过一个参数返回 多个行和列。这就是前面的例子为什么要使用3个参数

调用方法

call funname1 (
            @min_arg,
             @max_arg,
             @avg_arg
);

所有MySQL变量都必须以@开始。

由于此存储过程要求3个参数,因此必须正好传递3个参数

拿取参数

image-20211208170936471

select @min_arg ;

显示存储过程

显示用来创建一个存储过程的CREATE语句

show create procedure funname1;

列出所有存储过程

SHOW PROCEDURE STATUS

游标 (待补充)

需要在检索出来的行中前进或后退一行或多行。这就是使用 游标的原因。游标(cursor)是一个存储在MySQL服务器上的数据库查询, 它不是一条SELECT语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。

不像多数DBMS,MySQL游标只能用于存储过程(和函数)。

触发器

MySQL语句在需要时被执行,存储过程也是如此。但是,如果你 想要某条语句(或某些语句)在事件发生时自动执行

所有这些例子的共同之处是它们都需要在某个表发生更改时自动 处理。这确切地说就是触发器。

触发器是MySQL响应以下任意语句而 自动执行的一条MySQL语句

DELETE;
INSERT;
UPDATE;
begin   ....   end;

其他MySQL语句不支持触发器

应该用触发器来保证数据的一致性(大小写、格式等)。在触发器
中执行这种类型的处理的优点是它总是进行这种处理,而且是透
明地进行,与客户机应用无关。

触发器的一种非常有意义的使用是创建审计跟踪。使用触发器,
把更改(如果需要,甚至还有之前和之后的状态)记录到另一个
表非常容易。

创建触发器

在创建触发器时,需要给出4条信息:
 唯一的触发器名;
 触发器关联的表;
 触发器应该响应的活动(DELETE、INSERT或UPDATE);
 触发器何时执行(处理之前或之后)。

create trigger name 
after|before         insert|update|delete      on table1
for each row   //这个触发器还指定 FOREACH ROW,因此代码对每个插入行执行。
select 'aaaaa';

只有表才支持触发器,视图不支持(临时表也不 支持)。

单一触发器不能与多个事件或多个表关联,所 以,如果你需要一个对INSERT和UPDATE操作执行的触发器,则应该定义 两个触发器。

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

删除触发器

drop trigger name;

触发器不能更新或覆盖。为了修改一个触发器,必须先删除它, 然后再重新创建。

insert

在INSERT触发器代码内,可引用一个名为NEW的虚拟表,访问被插入的行

对于AUTO_INCREMENT列,NEW在INSERT执行之前包含0,在INSERT执行之后包含新的自动生成值

image-20211208190029679

delete

在DELETE触发器代码内,你可以引用一个名为OLD的虚拟表,访问被删除的行;

OLD中的值全都是只读的,不能更新。

create trigger name1 
before delete on table1
for each row
begin
    insert into table2 (column1,column2 ...)
    values (old.column1, old.column2 ...) ;
end;

这个例子是 对每个删除行进行备份到 table2 中

update

在UPDATE触发器代码中,你可以引用一个名为OLD的虚拟表访问 以前(UPDATE语句前)的值,引用一个名为NEW的虚拟表访问新更新的值;

BEFORE UPDATE触发器中,NEW中的值可能也被更新(允许更改将要用于UPDATE语句中的值);

OLD中的值全都是只读的,不能更新。

事务

并非所有引擎都支持事务处理

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

事务(transaction)指一组SQL语句;

回退(rollback)指撤销指定SQL语句的过程;

提交(commit)指将未存储的SQL语句结果写入数据库表;

保留点(savepoint)指事务处理中设置的临时占位符(place-
holder),你可以对它发布回退(与回退整个事务处理不同)。

你不能回退CREATE或DROP操作

start transaction  ;
....
....
....
rollback ; // commit ;

当COMMIT或ROLLBACK语句执行后,事务会自 动关闭(将来的更改会隐含提交)。

使用保留点

为了支持回退部分事务处理,必须能在事务处理块中合适的位置放 置占位符。这样,如果需要回退,可以回退到某个占位符

savepoint  delete1;

rollback to delete1;

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

或者手动 release savepoint

更改默认提交行为

set autocommit =0;

字符集

字符集 character 为字母和符号的集合;

编码 为某个字符集成员的内部表示;

校对 collation 为规定字符如何比较的指令。

image-20211208192511630

image-20211208192556076

权限控制 (待补充)

备份

性能

EXPLAIN语句让MySQL解释它将如何执行一条SELECT语句。

决不要检索比需求还要多的数据。换言之,不要用SELECT *(除 非你真正需要每个列)。

必须索引数据库表以改善数据检索的性能。

索引改善数据检索的性能,但损害数据插入、删除和更新的性能

LIKE很慢。一般来说,最好是使用FULLTEXT而不是LIKE。

你的SELECT语句中有一系列复杂的OR条件吗?通过使用多条SELECT语句和连接它们的UNION语句,你能看到极大的性能改进。

数据类型

使用引号 不管使用何种形式的串数据类型,串值都必须括在
引号内(通常单引号更好)。

如果数值是计算(求和、平均等)中使 用的数值,则应该存储在数值数据类型列中。如果作为字符串(可能只包含数字)使用,则应该保存在串数据类型列中。

image-20211208193447550

数值

有符号或无符号 所有数值数据类型(除BIT和BOOLEAN外)都可以有符号或无符号。

默认情况为有符号,

可以使用UNSIGNED关键字,这样做将允许你存储两倍大小的值。

image-20211208193708795

日期时间

image-20211208193731910

二进制

image-20211208193749896

MySQL必知必会(文字版).pdf