总结MySQL中SQL语法的使用

--where子句操做符:html

where子句操做符
= 等于
<> 不等于(标准语法)
!= 不等于(非标准语法,可移植性差)
< 小于
<= 小于等于
> 大于
>= 大于等于
between                                   在指定的两个值之间
IS NULL 空值检查
IN(a, b) 在a与b之间
NOT 

注意NOT在复杂语句中的应用,好比NOT IN(A, B),在简单语句中,NOT没有什么特别之处,可是在复杂语句中,显得很重要mysql

在MySQL中使用NOT对IN、BETWEEN和EXISTS子句取反,这个多数其余DBMS容许使用NOT对各类条件取反有很大差异git

 --通配符:%与_程序员

%与_
%

%s正则表达式

s%sql

s%e数据库

%匹配的是单个或多个字符
_

_s浏览器

s_安全

s_e服务器

_匹配的是单个字符而不是多个字符

--正则表达式:注意[]是另外一种形式的OR,好比[123]Ton是[1|2|3]Ton的缩写,若是不使用[],则会匹配出其余行的数据,

                        如:1|2|3 ton就会检索出Jet 1000

        [1-9]、[a-Z],若是是匹配一些特殊的字符要使用\\进行转义,如\\.表示查找.  \\\表示查找\

        空白元字符:\\f换页  \\n换行    \\r回车    \\t制表   \\v纵向制表

--匹配字符类:

匹配字符类
[:alnum:] 任意字母和数字(同[a-xA-Z0-9])
[:alpha:] 任意字符(同[a-zA-Z])
[:blank:] 空格和制表(同[\\t])
[:cntrl:] ASCII控制字符(ASCII 0到31和127)
[:digit:] 任意数字(同[0-9])
[:graph:] 与[:print:]相同,但不包括空格
[:lower:] 任意小写字母(同[a-z])
[:print:] 任意可打印的字符
[:punct:] 既不在[:alnum:]又不在[:cntrl:]中的任意字符
[:space:] 包括空格在内的任意空白字符(同[\\f\\n\\r\\t\\v])
[:upper:] 任意大写字母([A-Z])
[:xdigit:] 任意十六进制数字(同[a-fA-F0-9])

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

匹配多个实例:

匹配多个实例
* 0个或多个匹配
+ 1个或多个匹配
? 0个或1个匹配(等于{1,})
{n} 指定数目的匹配
{n,} 很多于指定数目的匹配
{n,m}  匹配数目的范围(m不超过255)

 

 

 

 

 

 

 

 

--建立拼接字段

MySQL中使用concat(a,b)函数来拼接两个列,可是多数DBMS使用+或||来实现拼接

Trim函数去掉串左右两边的空格,RTrim()函数去掉值右边的全部空格,LTrim()函数去掉值左边的全部空格

--使用别名

关键字是as,固然as能够省略,但尽可能不省略,根据经验,有时候普as不写会报错

--执行算术计算

操做符:+加-减*乘/除

select NOW()返回当前日期和时间

--使用数据处理函数

文本处理函数:

文本处理函数
Left() 返回串左边的字符
Length() 返回串的长度
Locate() 找出串的一个字串
Lower() 将串转换为小写
LTrim() 去掉串左边的空格
Right() 返回串右边的字符
RTrim() 去掉串右边的空格
Soundex() 返回串的SOUNDEX的值
SubString() 返回字串的字符
Upper() 将串转换为大写

 

 

 

 

 

 

 

 

 

 

 

 

 

日期和时间处理函数:

日期和时间处理函数
AddDate() 增长一个日期(天、周等)
AddTime() 增长一个时间(时、分等)
CurDate() 返回当前的日期
CurTime() 返回当前的时间
Date() 返回日期时间的日期部分
DateDiff() 计算两个日期之差
Date_Add() 高度灵活的日期运算函数
Date_Format() 返回一个格式化的日期或时间串
Day() 返回一个日期的天数部分
DayOfWeek() 对于一个日期,返回对应的星期几
Hour() 返回一个时间的小时部分
Minute() 返回一个时间的分钟部分
Month() 返回一个日期的月份部分
Now() 返回当前日期和时间
Second() 返回一个时间的秒部分
Time() 返回一个日期时间的时间部分
Year() 返回一个日期的年份部分

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

数值处理函数:

数值处理函数
Abs() 返回一个数的绝对值
Cos() 返回一个角度的余弦
Exp() 返回一个数的指数值
Mod() 返回一个除操做的余数
Pi() 返回圆周率
Rand() 返回一个随机数
Sin() 返回一个角度的正弦
Sqrt() 返回一个数的平方根
Tan() 返回一个角度的正切

 

 

 

 

 

 

 

 

 

 

  

 

----汇总数据

--汇集函数:

汇集函数
AVG() 返回某列的平均值
COUNT() 返回某列的行数
MAX() 返回某列的最大值
MIN() 返回某列的最小值
SUM() 返回某列值之和

 

 

 

 

 

 

 

 

--汇集不一样值

上述的5个汇集函数均可以以下使用:

  一、对全部的行执行计算,指定ALL参数或不给参数(由于ALL是默认行为)

  二、只包含不一样的值,指定DISTINCT参数

若是指定列名,则DISTINCT只能用于COUNT(),按技术上来讲,DISTINCT能够用于MAX()和MIN(),可是没有意义

--组合汇集函数

意思就是select能够包含多个汇集函数

--分组数据

关键字GROUP BY

规定:

一、GROUP BY子句能够包含任意数目的列

二、若是在GROUP BY子句中嵌套了分组,数据将在最后规定的分组上进行汇总,换句话说,在创建分组时,指定的全部列都一块儿计算(因此不能从个别的列取回数据)

三、GROUP BY子句中列出的每一个列都必须时检索列或者有效的表达式(但不能是汇集函数),若是在select中使用表达式,则必须在GROUP BY子句中指定

  相同的表达式,不能使用别名

四、除汇集计算语句外,select语句中的每一个列都必须在GROUP BY子句中给出

五、若是分组列中具备NULL值,则NULL将做为一个分组返回。若是列中有多行NULL值,它们将分为一组

六、GROUP BY子句必须出如今WHERE子句以后,ORDER BY子句以前

使用ROLLUP,使用WITH ROLLUP关键字,能够获得每一个分组以及每一个分组汇总界别级别(针对每一个分组)的值

过滤分组:

关键字HAVING

除了能用GROUP BY分组数据外,MySQL还容许使用过滤分组,规定包括哪些分组,排除哪些分组。由于WHERE没有分组的概念,因此WHERE过滤指定的是行而不是分组。

目前为止所学过的全部类型的WHERE子句均可以用HAVING来替代,惟一的差异是WHERE是过滤行,而HAVING过滤分组。过滤是基于分组汇集值而不是特定行值的。

另外一种思惟区分HAVING和WHERE:

WHERE在数据分组前进行过滤,HAVING在数据分组后进行过滤。这是一个重要区别,WHERE排除的行不包括在分组中,这可能会改变计算值,从而影响HAVING子句中基于这些值过滤掉的分组。

分组和排序:

ORDER BY和GOURP BY区别
ORDER BY   GROUP BY
排序产生的输出 分组行。但输出可能不是分组的顺序
任意列均可以使用(甚至非选择的列也可使用) 只可能使用选择列或表达式列,并且必须使用每一个选择列表达式
不必定须要 若是和汇集函数一块儿使用列(或表达式),则必须使用

 

 

 

 

 

 

 

PS:通常在使用GROUP BY子句时,应该也给出ORDER BY子句。这是保证数据正确排序的惟一方法,千万不要依赖于GROUP BY排序数据

SELECT子句顺序:

SELECT子句及其顺序
子句 说明 是否必须使用
SELECT 要返回的列或表达式
FROM 从中检索数据的表 仅在从表选择数据时使用
WHERE 行级过滤
GROUP BY  分组说明 仅在按组计算汇集时使用
HAVING 组级过滤
ORDER BY 输出排序顺序
LIMIT 要检索的行数

 

 

 

 

 

 

 

 

 

 

 

--使用子查询

在select中建立多个select

利用子查询进行过过滤

做为计算字段使用子查询,就是子查询做为一个字段

----联结表

PS:叉联结(cross join),有时咱们会听到返回成为叉联结的笛卡尔积的联结类型

 --内部联结

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

ANSI SQL规范首选INNER JOIN语法,此外尽管使用WHERE子句定义联结的确比较简单,可是使用明确的联结语法可以确保不会忘记联结条件,有时候这样作也能影响性能。

----建立高级联结

 除了使用别名引用呗检索的表列,给列起别名的用法以下,写的缘由主要是没见过这种concat的用法:

SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title FROM vendors ORDER BY vend_name

----使用不一样类型的联结

内部联结或等值联结都是简单联结,其实还有其余联结,分别是自联结、天然联结和外部联结

--自联结

用自联结而不用子查询:天然联结一般做为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是同样的,但有时候处理联结远比处理子查询快得多。应该试一下两种方法,以肯定哪种的性能更好。

select prod_id,prod_name   from products   where vend_id = (select vend_id   from products   where prod_id = 'DTNTR');
---------------------------------------------------
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';


 

--天然联结

PS:事实上,迄今为止,咱们创建的每一个内部联结都是天然联结,极可能咱们永远都不会用到不是天然联结的内部联结

--外部联结

联结包含了那些在相关表中没有关联行的行,这种类型的联结称为外部联结

select customer.cust_id, orders.order_num from customers inner join orders on customers.cust_id = orders.cust_id; select customer.cust_id, orders.order_num from customers left join orders on customers.cust_id = orders.cust_id;

PS:

        一、没有*=操做符,MySQL不支持简化字符*=和=*的使用,这两种操做符在其余DBMS中很流行

   二、外部联结的类型:存在两种基本的外部联结形式:左外部联结和右外部联结。它们之间的惟一差异是所关联的表的顺序不一样。换句话说,左外部联结可经过颠倒from或where子句中表的顺序转化为右外部联结。所以,两种类型的外部联结可互换使用,而究竟使用哪种纯粹是根据方便而定。

--使用带汇集函数的联结

select customer.cust_id, customer.cust_name, count(orders.order_num) as num_ord from customer inner join orders on customer.cust_id = orders.cust_id group by customer.cust_id

--使用联结和联结条件

要点:

  一、注意所使用的联结类型。通常咱们使用内部联结,但使用外部联结也是有效的

  二、保证使用正确的联结条件,不然将返回不正确的数据

  三、应该老是提供联结条件,不然会得出笛卡尔积

  四、在一个联结中能够包含多个表,甚至对于每一个联结能够采起不一样的联结类型。虽然这样作是合法的,通常也颇有用,但应该在一块儿测试它们前,分别测试每一个联结。这将是故障排除更为简单。

----组合查询

--组合查询

MySQL容许执行多个查询(多条select语句),并将结果做为单位查询结果集返回。这些组合查询一般成为并(union)或复合查询(compound query)。

有两种基本状况,其中须要使用组合查询:

一、在单个查询中从不一样的表返回相似结构的数据;

二、对单个表执行多个查询,按单个查询返回数据。

组合查询和多个where条件:多数状况下,组合相同表的两个查询完成的工做与具备多个where子句条件的单条查询完成的工做相同。换句话说,任何具备多个where子句的select语句均可以做为一个组合查询给出,在如下段落中能够看到这一点。这两种技术在不一样的查询中,性能也不一样。所以,应该试一下两种技术,以肯定对特定的查询哪种性能更好。

--使用union建立组合查询

给出每条select语句,在各条语句之间放上关键字union,下述写法就是将两个select查询的东西合并在一块儿(3列)

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比where复杂,可是遇到复杂的过滤条件,或者从多个表(而不是单个表)中检索数据的情形,使用union可能会使处理更简单。

--union规则

注意:

  一、union必须由两条以上的select语句组成,语句之间用关键字union分隔(所以,若是组合4条select语句,将要使用3个union关键字)

  二、union中的每一个查询必须包含相同的列、表达式或汇集函数(不过各个列不须要以相同的次序列出)

  三、列数据类型必须兼容:类型没必要彻底相同,但必须是DBMS能够隐含地转换的类型(例如,不一样的数值类型或不一样的日期类型)

若是遵照了这些基本规则或限制,则能够将并用于任何数据检索任务。

--包含或取消重复的行

在union的默认行为中,是取消了重复行的,可是可使用union all来返回全部匹配行

ps:union与where:union几乎老是完成与多个where条件相同的工做。union all为union的一种形式,它完成where子句完成不了的工做。若是确实须要每一个条件的匹配行所有出现(包括重复行),则必须使用union all而不是where。

--对组合查询结果排序

在用union组合查询时,只能使用一条order by子句,它必须出如今最后一条select语句以后。对于结果集,不存在用一种方式排序一部分,而有用另外一种方式排序另外一部分的状况,所以不容许使用多条order by子句。

ps:组合不一样的表:使用union的组合查询能够应用不一样的表。

----全文本搜索

并不是全部引擎都支持全文本搜索:MySQL支持几种基本的数据库引擎。并不是全部的引擎都支持该文章所描述的全文本搜索。两个最常使用的引擎为MyISAM和InnoDB。前者支持全文本搜索,然后者不支持。

like和正则表达式等搜索机制存在几个重要的限制:

  一、性能:通配符和正则表达式匹配一般要求MySQL尝试匹配表中全部行(并且这些搜索极少使用)。所以,因为被搜索行数不断增长,这些搜索可能很是耗时

  二、明确控制:使用通配符和正则表达式匹配,很难(并且并不老是能)明确地控制匹配什么和不匹配什么。例如,指定一个词必须匹配,一个词必须不匹配,而一个词仅在第一个词确实匹配的状况下才能够匹配或者才能够不匹配

  三、智能化的结果:虽然基于通配符和正则表达式的搜索提供了很是灵活的搜索,但它们都不能提供一种智能化的选择结果的方法。例如,一个特殊词的搜索将会返回多个包含该词的全部行,而不区分包含单个匹配的行和包含多个匹配的行(按照可能时更好的匹配来排列它们)。相似,一个特殊词的搜索将不会找出不包含该词但包含其余相关词的行。

全部这些限制以及更多的限制均可以用全文本搜索来解决。在使用全文本搜索时,MySQL不须要分别查看每一个行,不须要分别分析和处理每一个词。MySQL建立指定列中各词的一个索引,搜索能够针对这些词进行。这样,MySQL能够快速有效地决定哪些词匹配(哪些行包含它们),哪些词不匹配,它们匹配的频率,等等。

--使用全文本搜索

为了进行全文本搜索,必须索引被搜索的列,并且要随着数据的改变不断地从新搜索。在对表列进行适当设计后,MySQL会自动进行全部的索引和从新索引。

在索引以后,select可与match()和against()一块儿使用以实际执行执行搜索。

-------演示FULLTEXT子句的使用
create table productnotes ( note_id int not null auto_increment, prod_id char(10) not null, note_date datetime not null, PRIMARY KEY(note_id), FULLTEXT(note_text) ) ENGINE=MyISAM;

ps:不要在导入数据时使用FULLTEXT:更新索引要花时间,虽然不是不少,但毕竟要花时间。若是正在导入数据到一个新表,此时不该该启用FULLTEXT索引。应该首先导入全部数据,而后再修改表,定义FULLTEXT。这样有助于更快地导入数据(并且使索引数据的总时间小于在导入每行时分别进行索引所须要的总时间)。

--进行全文本搜索

在索引以后,使用两个函数match()和against()执行全文本搜索,其中match()指定被搜索的列,against()指定要使用的搜索表达式。

关于match()和against()函数的解释:

函数 MATCH() 对照一个文本集(包含在一个 FULLTEXT 索引中的一个或多个列的列集)执行一个天然语言搜索一个字符串。搜索字符串作为 AGAINST() 的参数被给定。搜索以忽略字母大小写的方式执行。对于表中的每一个记录行,MATCH() 返回一个相关性值。即,在搜索字符串与记录行在 MATCH() 列表中指定的列的文本之间的类似性尺度。当 MATCH() 被使用在一个 WHERE 子句中时 (参看上面的例子),返回的记录行被自动地以相关性从高到底的次序排序。相关性值是非负的浮点数字。零相关性意味着不类似。相关性的计算是基于:词在记录行中的数目、在行中惟一词的数目、在集中词的所有数目和包含一个特殊词的文档(记录行)的数目。它也能够执行一个逻辑模式的搜索。

ps:使用完整的match()说明:传递给match()的值必须与FULLTEXT()定义中的相同。若是指定多个列,则必须列出它们(并且次序正确);

  搜索不区分大小写:除非使用binary方式,不然全文本搜索不区分大小写;

  排序多个搜索项:若是指定多个搜索项,则包含多数匹配词的那些行将具备比包含较少词(或仅有一个匹配)的那些行高的等级值。

全文本搜索时对结果排序,具备较高等级的行先返回。全文本提供了简单like搜索不能提供的功能。并且因为数据是索引,全文本搜索还至关快。

--使用查询扩展

在使用查询扩展时,MySQL对数据和索引进行两遍扫描来完成搜索:

  一、首先,进行一个基本的全文本搜索,找出与搜索条件匹配的全部行

  二、其次,MySQL检查这些匹配行并选择全部有用的词

  三、再其次,MySQL再次进行全文本搜索,此次不只使用原来的条件,并且还使用全部有用的词。

查询扩展增长了返回的行数,,但这样作也增长了实际上并不想要的数目。

ps:行越多越好:表中的行越多(这些行中的文本就越多),使用查询扩展返回的结果越好。

--布尔文本搜索

以布尔方式,能够提供关于以下内容的细节:

  一、要匹配的词

  二、要排斥的词(若是某行包含这个词,则不反悔该行,即便它包含其余指定的词也是如此)

  三、排列提示(指定某些词比其余词更重要,更重要的词等级更高)

  四、表达式分组

  五、另一些内容

ps:即便没有FULLTEXT索引也可使用:布尔方式不一样于迄今为止使用的全文本搜索语法的地方在于,即便没有定义FULLTEXT索引,也可使用它。但这是一种很是缓慢的操做(其性能将随着数据量的增长而下降)

  IN BOOLEAN MODE的行为差别

全文本布尔操做符
布尔操做符 说明
+ 包含,词必须存在
- 排除,词必须不出现
> 包含,并且增长等级值
< 包含,且减小等级值
() 把词组成子表达式(容许这些子表达式做为一个组被包含、排除、排列等)
~ 取下一个词的排序值
* 词尾的通配符
"" 定义一个短语(与单个词的列表不同,它匹配整个短语以便包含或排除这个短语)

ps:排列而不排序:在布尔方式中,不按等级值降序排序返回的行

-全文本搜索的使用说明

  一、在索引全文本数据时,短词被忽略且从索引中排除。短语定义为那些具备3个或3个如下字符的词(若是须要,这个数目能够更改)

  二、MySQL带有一个内建的非用词(stopword)列表,这些词在索引全文本数据时老是被忽略。若是须要,能够覆盖这个列表

  三、许多词出现的频率很高,搜索它们没有用处(返回太多的结果)。所以,MySQL规定了一条50%规则,若是一个词出如今50%以上的行中,则将它做为一个非用词忽略。50%规则不用于IN BOOLEAN MODE

  四、若是表中的行数少于3行,则全文本搜索不返回结果(由于每一个词或者不出现,或者至少出如今50%的行中)

  五、忽略此中的单引号。例如,don't索引为dont

  六、不具备词分隔符(包括日语和汉语)的语言不能恰当地返回全文本搜索结果

  七、仅在MyISAM数据库引擎中支持全文本搜索

----插入数据

--数据插入

插入能够用几种方式使用:

  一、插入完整的行

  二、插入行的一部分

  三、插入多行

  四、插入某些查询的结果

插入及系统安全:可针对每一个表或每一个用户,利用MySQL的安全机制机制禁止使用INSERT语句

--插入完整的行

insert into customers values (null, 'LeeMichael', '100 street', 'los angle', null, 'USA');
-----------------------------------
insert into customers(
cust_name,
cust_addr,
cust_city,
cust_country) values ( 'LeeMichael', '100 street', 'los angle', 'USA');

ps:老是使用列的列表:通常不要使用没有明确给出列的列表的INSERT语句。使用列的列表能使SQL代码继续发挥做用,即便表结构发生了变化。

  仔细地给出值:无论使用哪一种INSERT语法,都必须给出values的正确数目。若是不提供列名,则必须给每一个表列提供一个值。若是提供列名,则必须对梅格列出的列给出一个值。若是不这样,将产生一条错误信息,相应的行插入不成功。

  省略列:若是表的定义容许,则能够在INSERT操做中省略某些列。省略的列必须知足如下某个条件:

      一、该列定义为容许null值(无值或空值)

      二、在表定义中给出默认值。这表示若是不给出值,将使用默认值

      若是对表中不容许null值且没有默认值的列不给出值,则MySQL将产生一条错误消息,而且相应的行插入不成功。

  提升总体性能:数据库常常被多个客户访问,对处理什么请求以及用什么次序处理进行管理是MySQL的任务。INSERT操做可能很耗时(特别是有不少索引须要更新时),并且它可能下降等待处理的select语句的性能

    若是数据检索是最重要的(一般是这样),则你能够经过在INSERT和INTO之间添加关键字LOW_PRIORITY,指示MySQL下降INSERT语句的优先级,如:INSERT LOW_PRIORITY INTO,这也适用于UPDATE和DELETE。

--插入多个行

insert into customers( cust_name, cust_addr, cust_city, cust_country) values ( 'LeeMichael', '100 street', 'los angle', 'USA'); insert into customers( cust_name, cust_addr, cust_city, cust_country) values ( 'LGQMichael', '100 street', 'los angle', 'USA');

多个语句,用 ; 隔开

或者能够这样(这样写能够提升性能):

insert into customers( cust_name, cust_addr, cust_city, cust_country) values ( 'LeeMichael', '100 street', 'los angle', 'USA'), ( 'LGQMichael', '100 street', 'los angle', 'USA'),

ps:提升insert的性能:此技术能够提升数据库处理的性能,由于MySQL用单条INSERT语句处理多个插入比使用多条INSERT语句快。

--插入检索出的数据

新例子的说明:这个例子把一个名为custnew的表中的数据导入customers表中。为了试验这个例子,应该首先建立和填充custnew表。custnew表的结构于customers表相同。在填充custnew时,不该该使用已经在customers中使用过的cust_id值(若是主键值重复,后续的INSERT操做将会失败)或仅省略这列值让MySQL在导入数据的过程当中产生新值。

insert into customers (cust_id, cust_contact, cust_email, cust_name, cust_addr, cust_city) select cust_id, cust_contact, cust_email, cust_name, cust_addr, cust_city from custnew

ps:INSERT SELECT中的别名:为简单起见,这个例子在INSERT和SELECT语句中使用了相同的列名。可是,不必定要求列名匹配。事实上,MySQL甚至不关心SELECT返回的列名。它使用的是列的位置,所以SELECT中的第一列(无论其列名)将用来填充表列中指定的第一列,第二列将用来填充表列中指定的第二个列,如此等等。这对于从使用不一样列名的表中导入数据时很是有用的。

INSERT SELECT中SELECT语句中能够包含where子句以过滤插入的数据。

----更新和删除数据

--更新数据

为了更新(修改)表中的数据,可以使用UPDATE语句。可采用两种方式使用UPDATE:

  一、更新表中特定行

  二、更新表总全部行

ps:不要省略WHERE子句:在使用UPDATE时必定要注意细心。由于稍不注意,就会更新表中全部行。

  UPDATE与安全:能够限制和控制UPDATE语句的使用。

基本的UPDATE语句由3个部分组成,分别是:

  一、要更新的表

  二、列名和它们的新值

  三、肯定要更新行的过滤条件

update customers set cust_email = 'lgq@163.com'
where cust_id = 1005;

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

   IGNORE关键字:若是能用UPDATE语句更新多行,而且在更新这些行中的一行

--删除数据

为了从一个表中删除(去掉)数据,使用delete语句。分为两种方式:

  一、从表中删除特定的行

  二、从表中删除全部行

ps:不要省略where子句:在使用delete时必定要注意细心。由于稍不注意,就会错误地删除表中全部行。

  delete与安全:能够限制和控制delete语句的使用

  删除表的内容而不是表:delete语句从表中删除行,甚至是删除表中全部行。可是,delete不是删除表自己。

  更快的删除:若是想从表中删除全部行,不要使用delete。可使用TRUNCATE TABLE语句,它完成相同的工做,但速度更快(TRUNCATE实际是删除原来的 表并不从新建立一个表,而不是逐行删除表中的数据)

--更新和删除的指导原则

许多SQL程序员使用UPDATE和DELETE时所遵循的习惯:

  一、除非确实打算更新和删除每一行,不然绝对不要使用不带where子句的UPDATE和DELETE

  二、保证每一个表都有主键,尽量想where子句那样使用它(能够指定各主键、多个值或值的范围)

  三、在对UPDATE或DELETE语句使用where子句前,应该先用SELECT进行测试,保证它过滤的是正确的记录,以防编写的where子句不正确

  四、使用强制实施引用完整性的数据库,这样MySQL将不容许删除与其余相关联的数据的行

ps:当心使用:MySQL没有撤销(undo)按钮。应该很是当心地使用UPDATE和DELETE,不然你会发现本身更新或删除了错误的数据。

----建立和操纵表

--建立表

方法:

  一、使用具备交互式建立和管理表的工具

  二、表也能够直接用MySQL语句操纵

--表建立基础

一、新表的名字,在关键字create table以后给出

二、表列的名字和定义,用逗号分隔开

create table customers ( cust_id int    not null auto_increment, cust_name char(50)    not null, primary key (cust_id) )ENGINE=InnoDB;

语句格式化:MySQL语句中忽略空格。语句能够在一个长行上输出,也能够分红许多行。它们的做用都相同。这容许你以最适合本身的方式安排语句的格式。强烈建议采用某种缩进格式。

处理现有的表:在建立新表时,指定的表名必须不存在,不然将出错。若是要防止意外覆盖已有的表,SQL要求首先手工删除该表,而后再重建它,而不是简单地用建立表语句覆盖它。若是你仅想在一个表不存在时建立它,应该在表名后给出IF NOT EXISTS。这样作不检查已有表的模式是否与你打算建立的表模式相匹配。它只是查看表名是否存在,而且仅在表名不存在时建立它。

--使用NULL值

NULL值就是没有值或缺值。容许NULL值的列也容许在插入行时不给出该列的值。不容许NULL值的列不接受该列没有值的行,换句话说,在插入或更新行时,该列必须有值。每一个表列或者是NULL列,或者是NOT NULL列,这种状态在建立时由表的定义规定。

理解NULL:不要把NULL值与空串相混淆。NULL值是没有值,它不是空串。若是指定  ''  (两个单引号,其间没有字符),这在NOT NULL列中是容许的。空串是一个有效的值,它不是无值。NULL值用关键字而不是空串指定。

--主键再介绍

主键值必须惟一。即,表中的每一个行必须具备惟一的主键值。若是主键使用单个列,则它的值必须惟一。若是使用多个列,则这些列的组合值必须惟一。建立多个列组成的主键primary key(a, b)

主键能够在建立表时定义,或者在建立表以后定义

ps:主键和NULL值:主键为其值惟一标识表中每一个行的列。主键中只能使用不容许NULL值的列。容许NULL值的列不能做为惟一标识。

--使用AUTO_INCREMENT

ATUO_INCREMENT告诉MySQL,本列每当增长一行时自动增量。每次执行一个INSERT操纵时,告诉MySQL自动对该列增量(从而才有这个关键字),给该列赋予下一个可用的值。这样给每一个行分配一个惟一的id,从而能够用做主键。

每一个表只容许一个AUTO_INCREMENT列,并且它必须被索引(如,经过使它成为主键)

ps:覆盖AUTO_INCREMENT:若是一个列被指定为AUTO_INCREMENT,则它须要使用特殊的值吗?你能够简单地在INSERT语句中指定一个值,只要它是惟一的便可,该值将被用来替代自动生成的值。后续的增量将开始使用该手工插入的值

  肯定AUTO_INCREMENT值:让MySQL生成(经过自动增量)主键的一个缺点是你不知道这些值都是谁。

--指定默认值

create table orderitems ( order_num int    not null, order_item int    not null, prod_id char(10)    not null, quantity int    not null    default   1, item_price decimal(8,2)    not null, primary_key(order_num, order_item) )ENGINE=InnoDB;

上述代码中就设置了quantity的默认值位1.

ps:不容许函数:与大多数DBMS不同,MySQL不容许使用函数做为默认值,它只支持常量

  使用默认值而不是NULL值:许多数据库开发人员使用默认值而不是NULL值,特别是对用于计算或数据分组的列更是如此。

--引擎类型

与其余DBMS同样,MySQL有一个具体管理和处理数据的内部引擎。在你使用CREATE TABLE语句时,该引擎具体建立表,而在你使用SELECT语句或进行其余数据库处理时,该引擎在内部处理你的请求。多数时候,此引擎都隐藏在DBMS内,不须要过多关注它

但MySQL与其余DBMS不同,它具备多种引擎。它打包多个引擎,这些引擎都隐藏在MySQL服务器内,全都能执行CREATE TABLE和SELECT等命令。这些引擎具备各自不一样的功能和特性,为不一样的任务选择正确的引擎能得到良好的功能和灵活性。若是省略ENGINE=语句,则使用默认引擎MyISAM,多数SQL语句都会默认使用它。但并非全部语句都默认使用它,这就是为何ENGINE=语句很重要的缘由。

引擎介绍:

  一、InnoDB是一个可靠的事务处理引擎,它不支持全文本搜索

  二、MEMORY在功能等同于MyISAM,但因为数据存储在内存(不是磁盘)中,速度很快(特别适用于临时表)

  三、NyISAM是一个性能极高的引擎,它支持全文本搜索,但不支持事务处理。

引擎类型能够混用。

ps:更多知识:所支持引擎的完整列表(及它们之间的不一样),参阅https://dev.mysql.com/doc/refman/5.0/en/storage_engines.html

  外键不能跨引擎:混用引擎类型有一个大缺陷。外键(用于强制实施引用完整性)不能跨引擎,即便用一个引擎的表不能引用具备使用不一样引擎的表的外键。

--更新表

为更新表定义,可以使用ALTER TABLE语句。可是,在理想状态下,当表中存储数据以后,该表就不该该再被更新。在表的设计过程当中须要花费大量时间来考虑,以便后期不对该表进行大的改动。

为了使用ALTER TABLE更改表结构,必须给出下面的信息:

  一、在ALTER TABLE以后给出要更改的表名(该表必须存在,不然将出错)

  二、所做更改的列表

ALTER TABLE vendors ADD vend_phone char(20); --------------------------------------
ALTER TABLE vendors DROP COLUMN vend_phone;

复杂表结构更改通常须要手动删除过程,它设计如下步骤:

  一、用新的列布局建立一个新表

  二、使用INSERT SELECT语句从旧表复制数据到新表,若有必要可以使用转换函数和计算字段

  三、检验包含所需数据的新表

  四、重命名旧表(若是肯定,能够删除它)

  五、用旧表原来的名字重命名新表

  六、根据须要,从新建立触发器、存储过程、索引和外键

ps:当心使用ALTER TABLE:使用ALTER TABLE要极为当心,应该在进行改动前作一个完整的备份(模式和数据的备份)。数据库表的更改不能撤销,若是增长了不须要的列,可能不能删除它们。相似的,若是删除了不该该删除的列,可能会丢失该列中的全部数据。

--删除表

DROP TABLE customers;

--重命名表

使用RENAME TABLE语句能够重命名一个表

RENAME TABLE backup_customers TO customers, backup_vendors TO vendors;

----使用视图

视图的一些常见应用:

  一、重用SQL语句

  二、简单复杂的SQL操做。在编写查询后,能够方便地重用它而没必要知道它的基本查询细节

  三、使用表的组成部分而不是整个表

  四、保护数据。能够给用户授予表的特定部分的访问权限而不是整个表的访问权限

  五、更改数据格式和表示。视图可返回与底层表的表示和格式不一样的数据。

重点:视图仅仅是用来查看存储在别处的数据的一种设施。视图自己不包含数据,所以它们返回的数据是从其余表中检索出来的。在添加或更改这些表中的数据时,视图将返回改变过的数据。

ps:性能问题:由于视图不包含数据,因此每次使用视图时,都必须处理查询执行时所需的任一个检索。若是你用多个联结和过滤建立一个复杂的视图或者嵌套了视图,可能会发现性能降低的很厉害。所以,在部署使用了大量视图的应用前,应该进行测试。

--视图的规则和限制

  一、与表同样,视图必须惟一命名(不能给视图取与别的视图或表相同的名字)

  二、对于能够建立的视图数目没有限制

  三、为了建立视图,必须具备足够的访问权限。这些限制一般由数据库管理人员授予

  四、视图能够嵌套,便可以利用从其余视图中检索数据的查询来构造一个视图

  五、ORDER BY能够用在视图中,但若是从该视图检索数据的SELECT语句中也含有ORDER BY,那么该视图中的ORDER BY将被覆盖

  六、视图中不能索引,也不能有关联的触发器或默认值

  七、视图能够和表一块儿使用。例如,编写一条联结表和视图的SELECT语句。

--使用视图

视图的建立:

  一、视图用CREATE VIEW语句来建立

  二、使用SHOW CREATE VIEW viewname;来查看建立视图的语句

  三、用DROP删除视图,能够先用DROP再用CREATE,也能够直接用CREATE OR REPLACE VIEW。若是要更新的视图不存在,则第2条更新语句会建立一个视图;若是要更新的视图存在,则第2条更新语句会替换原有视图。

--利用视图简化复杂的联结

视图最多见的应用之一就是隐藏复杂的SQL,这一般会涉及到联结。

CREATE VIEW productcustomers AS
SELECT cust_name, cust_contact, prod_id FROM customers, orders, orderitems WHERE customer.cust_id = orders.cust_id AND orderitems.order_num = orders.order_num;

ps:建立可重用的视图:建立不受特定数据限制的视图是一种好办法。

--用视图从新格式化检索出的数据

SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')') AS vend_title FROM vendors ORDER BY vend_name;
-------------------------------------------------------------------
CREATE VIEW vendorlocations AS
SELECT Concat(RTrim(vend_name), '(', RTrim(vend_country), ')')
AS vend_title
FROM vendors
ORDER BY vend_name;

--用视图过滤不想要的数据

视图对于应用普通的WHERE子句也颇有用,过滤掉一些不用的字段。

ps:WHERE子句与WHERE子句:若是从视图检索数据时使用了一条WHERE子句,则两组子句(一组在视图中,另外一组是传递给视图的)将自动组合。

--使用视图与计算字段

SELECT prod_id, quantity, item_price, quantity * item_price AS expanded_price FROM orderitems WHERE order_num = 20005;

--更新视图

迄今为止的全部视图都是和SELECT语句使用的。然而,视图的数据可否更新?答案视状况而定。

一般视图是可更新的(即,能够对它们使用INSERT、UPDATE和DELET)。更新一个视图将更新其基表(能够回忆一下,视图自己没有数据)。若是你对视图增长或删除行,其实是对其基表增长或删除行。

可是,并不是全部的视图都是可更新的。基本能够说,若是MySQL不能正确地肯定被更新的基数据,则不容许更新(包括插入和删除)。这实际上意味着,若是视图定义中有如下操做,则不能进行视图的更新:

  一、分组(使用GROUP BY和HAVING)

  二、联结

  三、子查询

  四、并

  五、汇集函数(Min()、Count()、Sum()等)

  六、DISTINCT

  七、导出(计算)列

要记住视图主要是用于数据检索。

ps:可能的变更:将来的MySQL极可能会取消某些限制

  将视图用于检索:通常,应该将视图用于检索(SELECT语句)而不用于更新(INSERtT、UPDATE和DELETE)

----使用存储过程

--存储过程

迄今位置,使用的大多数SQL语句都是针对一个或多个表的单条语句。并不是全部操做都这么简单,常常会有一个完整的操做须要多条语句才能完成。

单独编写每条语句,并根据结果有条件地执行另外的语句。在每次须要这个处理时(以及每一个须要它的应用中)都必须作这些工做。

能够建立存储过程。存储过程简单来讲,就是为之后的使用而保存的一条或多条MySQL语句的集合。可将其视为批文件,虽然它的做用不只限于批处理。

--为何要使用存储过程

缘由以下:

  一、经过把处理封装在容易使用的单元中,简单复杂的操做

  二、因为不要求反复创建一系列处理步骤,这保证了数据的完整性。若是全部开发人员和应用程序都使用同一(试验和测试)存储过程,则所使用的代码都是相同的。这一点的延伸就是防止错误。须要执行的步骤越多,出错的可能性就越大。防止错误保证了数据的一致性。

  三、简化对变更的管理。若是表名、列名或业务逻辑(或别的内容)有变化。只须要更改存储过程的代码。使用它的人员甚至不须要知道这些变化。

这一点的延伸就是为了安全性。经过存储过程限制对基础数据的访问减小了数据讹误(无心识的或别的缘由所致使的数据讹误)的机会。

  一、提升性能。由于适应存储过程比使用单独的SQL语句要快

  二、存在一些只能用在单个请求中的MySQL元素和特性,存储过程可使用它们来编写功能更强更灵活的代码。

总的来讲,使用存储过程的3个主要好处就是,简单、安全和高性能。

通常来讲,编写存储过程须要安全访问权限。

ps:MySQL将编写存储过程的安全和访问与执行存储过程的安全和访问区分开。即便你不能(或不想)编写本身的存储过程,也仍然能够在适当的时候执行别的存储过程。

--使用存储过程

MySQL称存储过程的执行为调用,所以MySQL执行存储过程的语句为CALL。CALL接受存储过程的名字以及须要传递给它的任意参数。

----------执行叫作productpricing的存储过程
CALL productpricing (
@pricelow, @pricehigh, @priceaverage );

--建立存储过程

CREATE PROCEDURE productpricing() BEGIN 
        SELECT Avg(prod_price)    AS priceaverage FROM products; END

BEGIN和END是用来限定存储过程体,过程仅是简单的SELECT语句。

 在MySQL处理这段代码时,它建立一个新的存储过程product-pricing。没有返回数据,由于这段代码并未调用存储过程,这里知识为了之后使用而建立。

ps:MySQL命令行客户机的分隔符:若是你使用的是MySQL命令行使用程序,应该仔细阅读此说明。

  默认的MySQL语句分隔符为;(正如你已经在迄今为止所使用的MySQL语句中所看到的那样)。MySQL命令行实用程序也使用;做为语句分隔符。若是命令行实用程序要解释存储过程自身内的;字符,则它们最终不会成为存储过程的成分,这会使存储过程当中的SQL出现语法错误。

  解决办法是临时更改命令行使用程序的语句分隔符,以下所示:

DELIMITER //
CREATE PROCEDURE productpricing() BEGIN
    SELECT Avg(prod_price) AS priceaverage FROM products; END //
DELIMITER;

其中,DELIMITER //告诉命令行实用程序使用 // 做为新的语句结束分隔符,能够看到标志存储过程结束的END定义为END //而不是END;。这样,存储过程体内的;仍然保持不动,而且正确地传递给数据库引擎。最后,为恢复为原来的语句分隔符,可以使用DELIMITER  ;。

除 \ 符号外,任何字符均可以用做语句分隔符。

使用存储过程关键字是CALL

CALL productpricing();

--删除存储过程

存储过程建立以后,被保存在服务器上以供使用,直至被删除。删除命令从服务器中删除存储过程。

DROP PROCEDURE productpricing;

ps:仅当存在时删除:若是指定的国策灰姑娘不存在,则DROP PROCEDURE将产生一个错误。当过程存在想删除它时(若是过程不存在也产生)可以使用DROP PROCEDURE IF EXISTS。

--使用参数

存储通常不显示结果,而是把结果返回给你指定的变量。

变量(variable):内存中一个特定的位置,用来临时存储过程。

如下时productpricing的修改版本(若是不先删除此存储过程,则不能再次建立它):

CREATE 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;

ps:参数的数据类型:存储过程的参数容许的数据类型与表中使用的数据类型相同。

  注意,记录集不是容许的类型,所以,不能经过一个参数返回多个行和列。这就是前面的例子为何要使用3个参数的缘由。

为调用此修改过的存储过程,必须指定3个变量名:

CALL productpricing( @pricelow, @pricehigh, @priceaverage ); ----------------------------------------
SELECT @priceaverage; ----------------------------------------
SELECT @pricelow, @pricehigh, @priceaverage;

变量名:全部MySQL变量都必须以@开始

 

----------------使用IN和OUT参数 CREATE PROCEDRUE ordertotal( IN onumber INT, OUT ototal DECIMAL(8,2) ) BEGIN SELECT Sum(item_price * quantity) FROM orderitems WHERE order_num = onumber INTO ototal; END;

onumber定义为IN,由于订单号被传入存储过程。ototal定义为OUT,由于要从存储过程当中返回合计。SELECT语句使用这两个参数,WHERE子句使用onumber选择正确的行,INTO使用ototal存储计算出来的合计。

为调用这个新存储过程,可使用如下语句:

CALL ordertotal(20005, @total);

--创建智能存储过程

只有在存储过程内包含业务规则和智能处理时,它们的威力才能真正显现出来。

如下的demo演示下面几个事情:

  一、得到合计;

  二、把营业税有条件地添加到合计;

  三、返回合计(带或不带税)

 

create procedure ordertotal( in onumber int, in taxable boolean, out ototal decimal(8,2) )comment 'obtain order total , optionally adding tax'
begin
    declare total decimal(8,2); declare taxrate int default 6; select sum(item_price * quantity) from orderitems where order_num = onumber into total if taxable then
    select total+(total/100*taxrate) into total; end if; select total into ototal; end;

 

DECLARE语句定义局部变量,要求指定变量名和数据类型,也支持可选的默认值。

ps:COMMENT关键字:不是必需的,但若是给出,将在SHOW PROCEDURE STATUS的结果中显示。

--检查存储过程

为显示用来建立一个存储过程的create语句,使用show create procedure语句;

show create procedure ordertotal;

ps:限制过程状态结果:SHOW PROCEDURE STATUS列出全部存储过程。为限制其输出,可以使用LIKE指定一个过滤模式,

  例如:show procedure status like 'ordertotal'

----使用游标

--游标

MySQL5增长了对游标的使用。

MySQL检索操做返回一组称为结果集的行。这组返回的行都是与SQL语句相匹配的行(零行或者多行)。使用简单的SELECT语句,例如,没有办法获得第一行、下一行或前10行,也不存在每次一行地处理全部行的简单方法(相对于成批地处理它们)。

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

游标主要用于交互式应用,其中用户须要滚动屏幕上的数据,并对数据进行浏览或作出更改。

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

--使用游标

使用游标涉及几个明确的步骤:

  一、在可以使用游标前,必须声明(定义)它。这个过程实际上没有检索数据,它只是定义要使用的select语句。

  二、一旦声明后,必须打开游标以供使用。这个过程用前面定义的select语句把数据实际检索出来。

  三、对于填有数据的游标,根据须要取出(检索)各行。

  四、在结束游标使用时,必须关闭游标。

--建立游标

游标用DECLARE语句建立。DECLARE命名游标,并定义相应的SELECT语句,根据须要带WHERE和其余子句。例如,下面的语句定义了名为ordernumbers的游标,使用了能够检索全部订单的SELECT语句。

CREATE PROCEDURE processorders() BEGIN
    DECLARE ordernumbers CURSOR
    FOR
    SELECT order_num FROM orders; END;

--打开和关闭游标

游标用OPEN CURSOR语句来打开。。

OPEN ordernumbers;

关闭用CLOSE CURSOR,close释放游标使用的全部内部内存和资源,所以在每一个游标再也不须要时都用改关闭。

CLOSE ordernumbers;

ps:隐含关闭:若是你不明确关闭游标,MySQL将会在到达END语句时自动关闭它。

--使用游标数据

在一个游标被打开后,可使用FETCH语句分别访问它的每一行。FETCH指定检索什么数据(所需的列),检索出来的数据存储在什么地方。它还向前移动游标中的内部行指针,使下一条(不重复读取同一行)。

ps:DECLARE语句的次序:DECLARE语句的发布存在特定的次序。用DECLARE语句定义的局部变量必须在定义任意游标或句柄以前定义,而句柄必须在游标以后定义。不遵照此顺序将产生错误信息。

  重复或循环?“除这里使用的REPEAT语句外,MySQL还支持循环语句,它可用来重复执行代码,直到使用LEAVE语句手动退出位置。一般REPEAT语句的语法使它更适合于对游标进行循环。

-----使用触发器

--触发器

须要MySQL5:对触发器的支持是在MySQL5中增长的。所以,本章内容适用于MySQL5或以后。

MySQL语句在须要时被执行,存储过程也是如此。可是,若是你想要某条语句(或某些语句)在事件发生时自动执行,就须要使用触发器。

触发器时MySQL响应如下任意语句而自动执行的一条SQL语句(或位于BEGIN或END语句之间的一组语句):

  DECLARE

  INSERT

  UPDATE

其余MySQL语句不支持触发器。

--建立触发器

在建立触发器时,须要给出4条信息:

  一、惟一的触发器名

  二、触发器关联的表

  三、触发器应该响应的活动(DECLARE、INSERT或UODATE)

  四、触发器什么时候执行(处理以前或以后)

ps:保持每一个数据库的触发器名惟一:在MySQL5中,触发器名必须在每一个表中的惟一,但不是在每一个数据库中惟一。这表示同一个数据库中的两个表可具备相同的名字的触发器。这在其余每一个数据库触发器名必须惟一的DBMS中是不容许的,并且之后的MySQL版本极可能会使命名规则更为严格。所以,如今最好是在数据库范围捏使用惟一的触发器名。

CREATE TRIGGER newproduct AFTER INSERT ON products FOR EACH ROW SELECT 'Product added'

ps:仅支持表:只有表才支持触发器,试图不支持(临时表也不支持)

触发器按每一个表每一个事件每次地定义,每一个表每一个事件每次只容许一个触发器。所以,每一个表最多支持6个触发器(每条INSERT、UPDATE和DELETE的以前和以后)。单一触发器不能与多个事件或多个表关联,因此,若是你须要一个对INSERT和UPDATE操做执行的触发器,则应该定义两个触发器。

ps:触发器失败:若是BEFORE触发器失败,则MySQL将不执行请求的操做。此外,若是BEFORE触发器或语句自己失败,MySQL将不执行AFTER触发器(若是有的话)

--删除触发器

使用DROP TRIGGER语句

DROP TRIGGER newproduct;

--使用触发器

-INSERT触发器

INSERT触发器在INSERT语句执行以前或以后执行。须要知道如下几点:

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

  二、在BEFORE INSERT触发器内,NEW中的值也能够被更新(容许更改被插入的值)

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

 如下代码,建立一个名为neworder的触发器,它按照AFTER INSERT ON orders执行。在插入一个新订单到orders表时,MySQL生成一个新订单号并保存到order_num中。触发器从NEW.order_num取得这个值并返回它:

CREATE TRIGGER neworder AFTER INSERT ON orders FOR EACH ROW SELECT NEW.order_num;

ps:BEFORE或AFTER?:一般,将BEFORE用于数据验证和净化(目的是保证插入表中的数据确实是须要的数据)。本提示也适用于UPDATE触发器。

--DELETE触发器

DELETE触发器在DELETE语句执行以前或以后执行。须要知道如下几点:

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

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

如下代码,使用OLD保存将要被删除的行到一个存档表中:

 

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;

ps:多语句触发器:正如所见,触发器deleteorder使用BEGIN和END语句标记触发器体。这在此例子中并非必需的,不过也没有害处。使用BEGIN END块的好处是触发器能容纳多条SQL语句(在BEGIN END块中一条挨着一条)。

--UPDATE触发器

UPDATE触发器在UPDATE语句执行以前或以后执行。须要知道如下几点:

  一、在UPDATE触发器代码中,你能够引用一个名为OLD的虚拟表访问之前的值,引用一个名为NEW的虚拟表访问更新的值

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

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

下面的例子是保证周明缩写老是大写(无论UPDATE语句中给出的是大写仍是小写):

CREATE TRIGGER updatevendor BEFORE UPDATE ON vendors FOR EACH ROW SET NEW.vend_state = Upper(NEW.vend_stats);

--关于触发器的进一步介绍

重点:

  一、与其余DBMS相比,MySQL5中支持的触发器至关初级。将来的MySQL版本中有一些改进和加强触发器支持的计划

  二、建立触发器可能须要特殊的安全访问权限,可是,触发器的执行是自动的。若是INSERT、UPDATE或DELETE语句可以执行,则相关的触发器也能执行

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

  四、触发器的一种很是有意义的使用是建立审计跟踪。使用触发器,把更改(若是须要,甚至还有以前和以后的状态)记录到另外一个表很是容易

  五、遗憾的是,MySQL触发器中不支持CALL语句。这表示不能从触发器内调用存储过程。所需的存储过程代码须要复制到触发器内。

 ----管理事务的处理

--事务处理

ps:并不是全部引擎都支持事务处理:MySQL支持几种基本的数据库引擎。并不是全部引擎都支持明确的事务处理管理。MyISAM和InnoDB是两种最常使用的引擎。前者不支持明确的事务处理管理,然后者支持。若是你的应用中须要事务处理功能,则必定要使用正确的引擎类型。

事务处理(transaction processing)能够用来维护数据库的完整性,它保证成批的MySQL操做要么彻底执行,要么彻底不执行。

在使用事务和事务处理时,有几个关键字会反复出现。下面关于事务处理须要知道的几个术语:

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

  二、回退(rollbac)指撤销指定SQL语句的过程

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

  四、保留点(savepoint)指事务处理中设置的临时占位符(placeholder),你能够对它发布回退(与回退整个事务处理不一样)

--控制事务处理

管理事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据什么时候应该回退,什么时候不该该回退。

MySQL使用下面的语句来标识事务的开始:

START TRANSACTION;

--使用ROLLBACK

MySQL使用ROLLBACK命令用来回退(撤销)MySQL语句:

SELECT * FROM ordertotals; START TRANSACTION; DELETE FROM ordertotals; SELECT * FROM ordertotals; ROLLBACK; SELECT * FROM ordertotals;

根据上述例子可知,ROLLBACK只能在一个事务处理内使用(在执行一条START TRANSACTION命令以后)。

ps:哪些语句能够回退:事务管理用来管理INSERT、UPDATE和DELETE语句。你不能回退SELECT语句(由于这么作没有意义)。你不能回退CREATE和DROP操做。事务处理块中可使用这两条语句,但若是你执行回退,它们不会被撤销。

--使用COMMIT

通常的MySQL语句都是直接针对数据库表执行和编写的。这就是所谓的隐含提交(implict commit),即提交(写或保存)操做是自动进行的。可是,在事务处理某块中,提交不会隐含地进行。为进行明确的提交,使用COMMIT语句,以下所示:

START TRANSACTION; DELETE FROM orderitems WHERE order_num = 20010; DELETE FROM orders WHERE order_num = 20010; COMMIT;

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

--使用保留点

为了支持回退部分事务处理,必须能在事务处理块中合适的位置放置占位符。这样,若是须要回退,能够回退到某个占位符。这些占位符称为保留点。为了建立占位符,可以下使用SAVEPOINT语句:

SAVEPOINT delete1;

每一个占位符都取标识它的惟一名字,以便在回退时,MySQL知道要回退到何处。为了回退到本例给出的保留点,可以下进行:

ROLLBACK TO delete1;

ps:保留点越多越好:能够在MySQL代码中设置任意多的保留点,越多越好。由于保留点越多,你就越能按本身的意愿灵活地进行回退。

  释放保留点:保留点在事务处理完成(执行一条ROLLBACK或COMMIT)后自动释放。自MySQL5以来,也能够用RELEASE SAVEPOINT明确地释放保留点。

--更改默认的提交行为

正如所述,默认的MySQL行为是自动提交全部更改。换句话说,任什么时候候你执行一条MySQL语句,该语句实际上都是针对表执行的,并且所作的更改当即生效。为提示MySQL不自动提交更改,须要使用如下语句:

SET sutocommit=0;

autocommit标志决定是都自动提交更改,无论有没有COMMIT语句。设置autocommit为0(假)只是MySQL不自动提交更改(直到autocommit被设置为真为止)。

ps:标志为链接专用:autocommit标志是针对每一个链接而不是服务器的。

----全球化和本地化

 --字符集和校对顺序

数据库表被用来存储和检索数据。不一样的语言和字符集须要以不一样的方式存储和检索。所以,MySQL须要使用不一样的字符集(不一样的字母和字符),适应不一样的排序和检索数据的方法。

重要属于:

  一、字符集为字母和符号的集合

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

  三、校对为规定字符如何比较的指令

ps:校对很重要,由于不一样的字符集排序方式不一样,好比大小写就是一种校对顺序,还有就是法文或德文等字符,状况更复杂,在不基于拉丁文的字符集(日文、希伯来语、俄文等)时,状况就更为复杂了。

--使用字符集和校对顺序

MySQL支持众多的字符集。为查看所支持的字符集完整列表,使用如下语句:

--------这条语句显示全部可用的字符集以及每一个字符集的描述和默认校对。
SHOW CHARACTER SET;
-------此语句显示全部可用的校对,以及它们适用的字符集
SHOW COLLATION;

一般系统管理在安装定义时定义一个默认的字符集和校对。此外,也能够在建立数据库时,指定默认的字符集和校对。为了肯定所用的字符集和校对,可使用如下语句:

SHOW VARIABLES LIKE 'character%'; SHOW VARIABLES LIKE 'collation%';

实际上,字符集不多是服务器范围(甚至是数据库范围)的设置。不一样的表,甚至不一样的列均可能须要不一样的字符集,并且二者均可以在建立表时指定。

为了给表指定字符集和校对,可以使用带子句的CREATE TABLE,如下语句建立包含两列的表,而且指定一个字符集和一个校对顺序,这个例子中指定了CHARACTER SET和COLLATE。通常,MySQL以下肯定使用什么样子的字符集和校对。

  一、若是指定CHARACTER SET和COLLATE二者,则使用这些值

  二、若是只指定CHARACTER SET,则使用此字符集及其默认的校对(若是SHOW CHARACTER SET的结果中所示)

  三、若是既不指定CHARACTER SET,也不指定COLLATE,则使用数据库默认。

CREATE TABLE mytable ( colum1 INT , colum2 VARCHAR(10) ) DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci;

除了能指定字符集和校对的表范围外,MySQL还容许对每一个列设置它们,以下所示:

CREATE TABLE mytable ( colum1 INT, colum2 VARCAHR(10), colum3 VARCAHR(10) CHARACTER SET latin1 COLLATE latin1_general_ci ) DEFAULT CHARACTER SET hebrew COLLATE hebrew_general_ci; -------这里对整个表以及一个特定的列指定了CHARACTER SET和COLLATE

如前所述,校对在对用ORDER BY子句检索出来的数据排序时起很重要的做用。若是你须要用与建立表时不一样的校对顺序排序特定的SELECT语句,能够在SELECT语句自身中进行:

SELECT * FROM customers ORDER BY lastname, fistname COLLATE latin1_general_cs; ----此SELECT使用COLLATE指定一个备用的校对顺序(在这个例子中,为区分大小写的校对)。这显然会影响到结果排序的次序。

ps:临时区分大小写:上面的SELECT语句演示了在一般不区分大小写的表上进行区分大小写搜索的一种技术。固然,反过来也是能够的。

  SELECT的其余COLLATE子句:除了这里能够看到的在ORDER BY子句中使用之外,COLLATE还能够用于GROUP BY、HAVING、汇集函数、别名等。

**值得注意的是,若是绝对须要,串能够在字符集之间进行转换。为此,使用Cast()或Convert()函数。

----安全管理

--访问控制

MySQL服务器的安全基础是:用户应该对他们须要的数据具备适当的访问权,既不能多也不能少。换句话说,用户不能对过多的数据具备过多的访问权。

考虑如下内容:

  一、多数用户只须要对表进行读和写,但少数用户甚至须要能建立和删除表

  二、某些用户须要读表,但可能不须要更新表

  三、你可能想容许添加数据,但不容许他们删除数据

  四、某些用户(管理员)可能须要处理用户帐号的权限,但多数用户不须要

  五、你可能想让用户经过存储过程访问数据,但不容许他们直接访问数据

  六、你可能想根据用户登陆的地点限制对某些功能的访问

这些都只是例子,但有助于说明一个重要的事实,即你须要给用户提供他们所需的访问权,且仅提供他们所需的访问权。这就是所谓的访问控制,管理访问控制须要建立和管理用户帐号。

ps:使用MySQL Administrator:MySQL Administrator提供了一个图形用户界面,可用来管理用户及帐户权限。MySQL Administrator在内部利用本章介绍的语句,使用能交互地、方便地管理访问控制。

咱们知道,为了执行数据库操做,须要登陆MySQL。MySQL建立一个名为root的用户帐户,它对整个MySQL服务器具备彻底的控制。但在实际应用中,应该建立一系列的帐号,有的用于管理,有的供用户使用,有的供开发人员使用。

ps:防止无心的错误:重要的是注意到,访问控制的目的不只仅是防止用户的恶意企图。数据梦魇更为常见的是无心识错误的结果,如打错MySQL语句,在不适合的数据库中操做或其余一些用户错误。经过保证用户不能执行他们不该该执行的语句,访问控制有助于避免这些状况的发生。

  不要使用root:应该严肃对待root登陆的使用。仅在绝对须要时使用它(或许在你不能登陆其余管理帐号时使用)。不该该在平常的MySQL操做中使用root。

--管理用户

MySQL用户帐号和信息存储在名为mysql数据表中。通常不须要直接访问mysql数据库和表,但有时须要直接访问。须要直接访问它的时机之一是在须要得到全部用户帐号列表时。为此,可以使用如下代码:

USE mysql; SELECT user FROM user;

ps:用多个客户机进行试验:试验对用户帐号和权限进行更改的最好办法是打开多个数据库客户机(如mysql命令行实用程序的多个副本),一个做为管理登陆,其余做为被测试的用户登陆。

--建立用户帐号

为建立一个新用户帐号,使用CREATE USER语句,以下所示:

CREATE USER ben IDENTIFIED BY 'p@$$w0rd'; ----CREATE USER建立一个新用户帐号。在建立用户帐号时不必定须要口令,不过这个例子用IDENTIFIED BY 'p@$$w0rd'给出了一个口令,若是你再次列出用户帐号,将会在输出中看到新帐号。

ps:指定散列口令:IDENTIFIED BY指定的口令为纯文本,MySQL将在保存到user表以前对其进行加密。为了做为散列值指定口令,使用IDENTIFIED BY PASSWORD.

  使用GRANT或INSERT:GRANT语句也能够建立用户帐号,但通常来讲CREATE USER是最清楚和最简单的句子。此外,也能够经过直接插入行到user表来增长用户,不过为安全起见,通常不建议这么作。MySQL用来存储用户帐号信息的表(以及表模式等)极为重要,对他们的任何毁坏均可能严重地伤害到MySQL服务器。所以,相对于直接处理来讲,最好是用标记和函数来处理这些表。

为从新命名一个用户帐号,使用RENAME USER语句,以下所示:

RENAME USER ben TO bforta;

--删除用户帐号

为了删除一个用户帐号(以及相关的权限),使用DROP USER语句,以下所示:

DROP USER bforta;

ps:MySQL 5以前:自MySQL 5以来,DROP USER删除用户帐号和全部相关的帐号和权限。在MySQL5之前,DROP USER只能用来删除用户帐号,不能删除相关的 权限。所以,若是使用旧版本的MySQL,须要先用REVOKE删除与帐号相关的权限,而后再用DROP USER删除帐号。

--设置访问权限

在建立用户帐号后,必须接着分配访问权限。新建立的用户帐号没有访问权限。它们能登陆MySQL,但不能看到数据,不能执行任何数据库操做。

为看到赋予用户帐号的权限,使用SHOW GRANT FOR,以下所示:

SHOW GRANT FOR bforta;

输出结果显示用户bforta有一个权限USAGE ON *.*。USAGE表示根本没有权限,因此此结果表示在任意数据库和任意表上对任何东西没有权限。

ps:用户定义为user@host:MySQL的权限用用户名和主机名结合定义。若是不指定主机名,则使用默认的主机名%(授予用户访问权限而无论主机名)。

为设置权限,使用GRANT语句。GRANT要求你至少给出如下信息:

  一、要授予的权限

  二、被授予访问权限的数据库或表

  三、用户名

如下给出GRANT的用法:

GRANT SELECT ON crashcourse.* TO bforta;

SHOW GRANT反应这个更改:

SHOW GRANT FOE beforta;

GRANT的反操做为REVOKE,用它来撤销特定的权限,举个例子:

REVOKE SELECT ON crashcourse.* FROM bforta;

GRANT和REVOKE可在几个层次上控制访问权限:

  一、整个服务器,使用GRANT ALL和REVOKE ALL

  二、整个数据库,使用ON database.*

  三、特定的表,使用ON database.table

  四、特定的列

  五、特定的存储过程

如下列出能够授予或撤销的每一个权限:

权限
权限 说明
ALL 除GRANT OPTION外的全部权限
ALTER ROUNTINE 使用ALTER TABLE
CREATE 使用ALTER PROCEDURE和DROP PROCEDURE
CREATE ROUTINE 使用CREATE PROCEDURE
CREATE TEMPORARY TABLES 使用CREATE TEMPORARY TABLE
CREATE USER 使用CREATE USER、DROP USER、RENAME USER和REVOKE ALL PRIVILEGES
CREATE VIEW 使用CREATE VIEW
DELETE 使用DELETE
DROP 使用DROP TABLE
EXECUTE 使用CALL和存储过程
FILE 使用SELECT INTO OUTFILE和LOAD DATA INFILE
GRANT OPTION 使用GRANT和REVOKE
INDEX 使用CREATE INDEX和DROP INDEX
INSERT 使用INSERT
LOCK TABLES 使用LOCK TABLES
PROCESS 使用SHOW FULL PROCESSLIST
RELOAD 使用FLUSH
REPLICATION CLIENT 服务器位置的访问
REPLICATION SLAVE 由复制从属使用
SELECT 使用SELECT
SHOW DATABASES 使用SHOW DATABASES
SHOW VIEW 使用SHOW CREATE VIEW
SHUT DOWN 使用mysqladmin shutdown(用来关闭MySQL)
SUPER 使用CHANGE MASTER、KILL、LOGS、PURGE、MASTER和SER GLOBAL。还容许mysqladmin调试登陆
UPDATE 使用UPDATE
USAGE 无访问权限

使用GRANT和REVOKE,在结合上表列出权限,你能用户能够就你的宝贵数据作什么事情和不能作什么事情具备彻底的控制。

ps:将来的受权:在使用GRANT和REVOKE时,用户帐号必须存在,但对所涉及的对象没有这个要求。还容许管理员在建立数据库的和表以前设计和实现安全措施。这样作的反作用是,当某个数据库或表被删除时(用DROP语句),相关的访问权限仍然存在,并且,若是未来从新建立该数据库或表,这些权限仍然起做用。

   简化屡次受权:可经过列出各权限并用逗号分隔,将多条GRANT语句串在一块儿,以下所示:

GRANT SELECT, INSERT, ON crashcourse.* TO bforeta;

--更改口令

为了更改用户口令,可以使用SET PASSWORD语句。新口令必须以下加密:

SELECT PASSWORD FOR bforta = Password('n3w p@$$w0rd');
-----分析:SET PASSWORD更新用户口令。新口令必须传递到Password()函数进行加密。

SET PASSWORD还能够用来设置你本身的口令:

SET PASSWORD = Password('n3w p@$$w0rd'); ----在不指定用户名时,SET PASSWORD更新当前登陆用户的口令。

----数据库维护

--备份数据

解决普通的文件副本不必定老是有效的方案:

  一、使用命令行使用程序mysqldump转储全部数据库内容到某个外部文件。在进行常规备份前这个实用程序应该正常运行,以便能正确地备份转储文件

  二、可用命令行实用程序mysqlhotcopy从一个数据库复制全部数据(并不是全部数据库引擎都支持这个实用程序)

  三、可使用MySQL的BACKUP TABLE或SELECT INTO OUTFILE转储全部数据到某个外部文件。这两条语句都接受将要建立的系统文件名,此系统文件必须不存在,不然会出错。数据能够用RESTORE TABLE来复原

ps:首先刷新未写数据:为了保证全部数据被写道磁盘(包括索引数据),可能须要在进行备份前使用FLUSH TABLES语句。

--进行数据库维护

MySQL提供了一系列的语句,能够(应该)用来保证数据库正确和正常运行。

-ANALYZE TABLE,用来检查表键是否正确

ANALIZE TABLE orders;

-CHECK TABLE,用来针对许多问题对表进行检查。在MyISAM表上还对索引进行检查。CHECK TABLE支持一系列的用于MyISAM表的方式。CHANGED检查自最后一次检查以来改动过的表。EXTENDED执行最完全的检查,FAST只检查未正常关闭的表,MEDIUM检查全部被删除的连接并进行键检查,QUICK只进行快速扫描。以下所示,CHECK TABLE发现和修复问题:

CHECK TABLE orders, orderitems;

-若是MyISAM表访问产生不正确和不一致的结果,可能须要用REPAIR TABLE来修复相应的表。这条语句不该该常用,若是须要常用,可能会有更大的问题要解决。

-若是从一个表中删除大量数据,应该使用OPTIMIZE TABLE来收回全部的空间,从而优化表的性能。

--诊断启动问题

服务器启动问题一般在对MySQL配置或服务器自己进行更改时出现。MySQL在这个问题上发生时报告错误,但因为多数MySQL服务器是做为系统进程或服务自动启动的,这些消息可能看不到。

在排除系统启动问题时,首先应该尽可能用手动启动服务器。MySQL服务器自身经过在命令行上执行mysqld启动。下面是几个重要的mysqld命令行选项:

  一、--help显示帮助———一个选项列表

  二、--safe-mode装载减去某些最佳配置的服务器

  三、--verbose显示全文本消息(为得到更详细的帮助消息与--help联合使用)

  四、--version显示版本信息而后退出

--查看日志文件

MySQL维护管理员依赖的一系列日志文件。主要的日志文件有如下几种:

  一、错误日志。它包含启动和关闭问题以及任意关键错误的细节。此日志一般名为hostname.err,位于data目录中。此日志名可用--log-error命令行选项更改。

  二、查询日志。它记录全部MySQL活动,在诊断问题时很是有用。此日志文件可能会很快地变得很是大,所以不该该长期使用它。此日志文件一般名为hostname.log,位于data目录中。此名字能够用--log命令行选项更改。

  三、二进制日志。它记录更新过数据(或者可能更新过的数据)的全部语句。此日志一般名为hostname-bin,位于data目录内。此名字能够用--log-bin命令行选项更改。注意,这个日志文件是MySQL5中添加的,之前的MySQL版本中使用的是更新日志。

  四、缓慢查询日志。此日志记录执行缓慢的任何查询。这个日志在肯定数据库何处须要优化颇有用。此日志一般名为hostname-slow.log,位于data目录中。此名字能够用--log-slo-queries命令行选项更改。

在使用日志时,可用FLUSH LOGS语句来刷新和从新开始全部日志文件。

----改善性能

  一、首先,MySQL(与全部DBMS同样)具备特定的硬件建议。在学习和研究MySQL时,使用任何旧的计算机做为服务器均可以。但对用于生产的服务器来讲,应该坚持遵循这些硬件建议

  二、通常来讲,关键的生产DBMS应该运行在本身的专用服务器上

  三、MySQL是用一系列的默认设置预先设置的,这些设置开始一般是很好的。但过一段时间后你可能须要调整内存分配、缓冲区大小等。(为查看当前设置,可以使用SHOW VARIABLES;和SHOW STATUS;)

  四、MySQL是一个多用户多线程的DBMS,换言之,它常常同时执行多个任务。若是这些任务中的某一个执行缓慢,则全部请求都会执行缓慢。若是你遇到显著的性能不良,可以使用SHOW PROCESSLIST显示全部活动进程(以及它们的线程ID和执行时间)。你还能够用KILL命令终结某个特定的进程(使用这个命令须要做为管理员登陆)

  五、老是有不止一种方法编写同一条SELECT语句。应该试验联结、并、子查询等,找出最佳方法

  六、使用EXPLAIN语句让MySQL解释它将如何执行一条SELECT语句

  七、通常来讲,存储过程执行的比一条一条地执行其中的各条MySQL语句快

  八、应该老是使用正确的数据类型

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

  十、有的操做(包括INSERT)支持一个可选的DELAYED关键字,若是使用它,将把控制当即返回给调用程序,而且一旦有可能就实际执行该操做

  十一、在导入数据时,应该关闭自动提交。你可能还想删除索引(包括FULLTEXT索引),而后在导入完成后再重建它们

  十二、必须索引数据库表以改善数据检索的性能。肯定索引什么不是一件微不足道的任务,须要分析使用的SELECT语句以找出重复的WHERE和ORDER BY子句。若是一个简单的WHERE子句返回结果所花的时间太长,则能够判定其中使用的列(或几个列)就是须要索引的对象

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

  1四、索引改善数据索引的性能,但损害数据插入、删除和更行的性能。若是你有一些表,它们收集数据且不常常被搜索,则在有必要以前不要索引它们。(索引可根据须要添加和删除)

  1五、LIKE很慢。通常来讲,最好使用FULLTEXT而不是LIKE

  1六、数据库是不断变化的实体。一组优化良好的表一下子后可能就面目全非了。因为表的使用和内容的更改,理想的优化和配置也会改变

  17 、最重要的规则就是,每条规则在某些条件下都会被打破

ps:浏览文档:http://dev.mysql.com/doc,更多的内容参考MySQL手册

 ------------------------------------------------

本文章参考自《mysql必知必会》

相关文章
相关标签/搜索