MySQL基础知识和基本操作
第一章 了解mysql
保存有组织的数据的容器。(通常是一个文件或一组文件)
人们经常使用数据库这个术语代替他们使用的软件。这是不正确的,确切的说,数据库软件应称为dbms(数据库管理),数据库是通过dbms创建和操纵的容器。漱口可以是保存在硬件设备上的文件,但也可以不是。你使用dbms来代替自己访问数据库。
表 表是一种结构化的文件可用来存储某种特定的类型的数据。
某种特定类型数据的结构化清单。
模式 关于数据库和标的布局及特性的信息
列 表中的一个字段。表由列组成。列中存储着表里某部分的信息。
数据类型 所容许的数据的类型。每个表列都有相应的数据类型,它限制(或容许)该列中存储的数据。
行 表中的一个记录
主键 一列(或一组列),其值能够唯一区分表中的每个行。
虽然不是必须的,但是一般都建立主键。便于以后的数据管理
表中任何列都可以作为主键,只要满足以下条件:
1 任意两行都不具有相同的主键值。
2 每个行都必须有一主键值(主键值不允许为null)
主键的最好习惯:
不更新主键列的值
不重用主键列的值
不在主键列中使用可能会更改的值
什么是sql
sql是结构化查询语言的缩写。sql是一种专门用类与数据库通信的语言。
第二章 mysql简介
什么是mysql mysql是一种dbms,即它是一种数据库软件。
mysql版本主要更改
4-——innodb引擎,增加了事务处理、并、改进全文搜索等支持
4.1——对函数库、子查询、集成帮助等的重要增加、
5——存储过程、触发器、游标、试图等。
第三章 使用mysql
连接
主机名端口 一个合法用户用户口令
mysql -uroot -p -hmyserver -p9999
选择数据库
可使用use关键字,mysql语言组成部分的一个关键字,绝不要使用关键字命名一个表或列
use dataname;
显示数据库列表
show databases;
一个数据库内的表的列表(use进入数据库的情况下)
show tables;
show也可以用来显示表列
show columns from column;
describe 是show columns的一种快捷方式;describe cust;
其他的show语句
show status 显示广泛的服务器状态信息
show create database 显示创建特定数据库的mysql语句
show create table 显示创建特定表的mysql语句
show grants 显示授权用户的安全权限
show errors 显示服务器的错误信息
show warnings 显示服务器的警告信息
mysql必知必会笔记(二)select语句 检索 排序 过滤 通配符搜索 正则表达式搜索
第四章 检索数据
检索单列
selectcolumnonefrom table;
检索多列
selectcolumnone,columntwo,columnthireform table;
检索所有列
select*from products; //一般,除非你确实需要表中的每个列,否则最好不要用*通配符
检索不同的行
检索出来的数据不重复distinct关键字,顾名思义返回不同的值
selectdistinctcolumnonefrom table; //检索出来的columnone没有重复值
distinct关键字应用于所有列而不仅是前置它的列
selectdistinct vend_id,prod_price......要求vend_id,prod_price这两列都不出现重复的值
限制结果条数
sql语句后面加入下面sql语句
limit 5 显示结果的前5条
limit3,4 从行3开始的后4行
limit 4 offset 3 从行3开始的后4行
第五章 排序检索数据
子句 sql语句是由子句构成,有些子句是必须的,有些事可选的。一个子句通常是由一个关键字和所提供的数据组成。
按单列排序
select columnone from table order by columnone;
select columnone from table order by columntwo; //用非检索列也是可以的,如根据columntwo
按多列排序
select columnone,columntwo,columnthire from products order byprod_price,prod_name;
排序是先根据前面的columnone排序,如果一样再根据后面的columntwo排序
指定排序方向
asc 升序默认 desc 降序 关键字仅作用到直接位于前面的列名
select columnone,columntwo,columnthirefrom table order by columnone asc,columntwo desc; //先按columnone正排序再按columntwo倒序排序
第六章 过滤数据
使用where语句
select columnone,columntwo from table where columnone = 3;
where子句操作符
操作符 说明
= 等于
<> 不等于(数字比较)
!= 不等于(数字和字符串比较)
< 小于
> 大于
<= 小于等于
> 大于
>= 大于等于
between在指定的两个指之间必须指定2个值。这两个值必须使用and连接
selectcolumnone,columntwo, from table where columnone between 3 and 8; // 检索columnone值为3到8之间的行
空值检查
select 语句中有一个子句检查具有null值的列,is null子句。
select columnone from table where columnone is null; //检索 columnone值为null的行
注意:在数据库中null是不能被匹配和不匹配的语句找出来,所以一定要注意表中是否存在null值。
第七章 数据过滤
组合where子句
组合方式
and组合和or组合
必须满足所有条件
selectcolumnone,columntwo,columnthire from table where columnone = 2009 and columntwo <=10; //检索columnone =2009且columntwo <= 10的行
满足任意一个条件
selectcolumnone,columntwo,columnthire from table where columnone = 2009 or columntwo <=10;//检索columnone =2009或columntwo <= 10的行
计算次序
先计算and再计算or,不要过分依赖默认计算次序,可以使用括号改变计算次序,它能消除歧义。
in操作符 in操作符用来指定范围,范围中的每个条件进行匹配。in取合法值的逗号分隔的清单。
selectcolumnone,columntwo from table where columnone in (1002,1005,1006) orderby columntwo; //检索columnone为1002或1005或1006的行并且按columntwo分组
in操作符完成与or相同的功能,优点如下:
1 使用长的合法选项清单时,in操作符的预防更清楚且直观
2 使用in时,计算的次序更容易管理(以为使用的操作符更少)
3 in操作符一般比or操作符执行更快
4 in操作符最大的优点可以包含其他select语句,使得能够更动态的创建where子句。
not操作符 where子句中的not操作符有且只有一个功能,那就是否定它之后所跟的任何条件
selectcolumnone,columntwo from table where columnone notin (1002,1005,1006) orderby columntwo; //检索columnone不为1002或1005或1006的行并且按columntwo分组
mysql支持使用not对in、between和exists子句取反。
第八章 用通配符进行过滤
link操作符
通配符:用来匹配值的一部分的特殊字符。
搜索模式:又字面值、通配符或两者组成构成的搜索条件
% 任何字符出现任何位置区分大小写
//检索以jet开头的词或句子
selectcolumnone,columntwo from table where columnone link ' jet% ';
//检索以jet结尾的词或句子
selectcolumnone,columntwo from table where columnone link ' %jet ';
//检索以jet包含的词或句子
selectcolumnone,columntwo from table where columnone link ' %jet% ';
//检索以e开头,以u结尾的词或句子
//检索' e%u ';
%还可以匹配0字符,注意尾空格会影响搜索模式的结果。
_ 匹配单个字符
selectcolumnone,columntwo from table where columnone link '_abc'
//匹配aabc eabc eabc 等前面一个字母的词
让like区分大小写的方法
在where和列名之间加binary关键字,或者再建立表时就指定区分大小写name varhar(50)binary
使用通配符是有代价的,提供以下的技巧:
不要过度的使用通配符
除非是必要的,否则通配符不要用在搜索模式的开始处
仔细注意通配符的位置。不要放错位置
第九章 用正则表达式进行搜索
仅支持正则表达式的一小部分
基本字符匹配
检索列prod_name包含1000的所有行
select columnone from table where columnone regexp'1000'orderby columnone
. 匹配任意一个字符1000 2000 3000 a000
select columnone from table where columnone regexp'.000'orderby columnone
正则匹配不区分大小写,如想区分匹配可在regexp后面加上binary关键字
进行or匹配
为搜索两个或n个字符串之一
select columnone from table where columnone regexp'1000|2000|3000' ;
匹配单个字符
select columnone from table where columnone regexp '[123] ton'; //匹配1 ton或2 ton或3 ton
当有非匹配的内容时使用[],它是|的另一种形式,如1|2|3 ton这时匹配的只有3带有ton
如果想要得到非匹配的内容可以使用[^123]的形式
匹配范围 [0-9] [a-z][a-z]
select columnone from table where columnone regexp '[1-5] ton' ;
匹配特殊字符
想要匹配 . [ ] | 这些字符串怎么办呢,可以在这些字符前加 \\ 进行转义,第一个\ mysql自己解释,第二个给正则解释的
元字符 说明
\\\ \
\\f 换页
\\n 换行
\\r 回车
\\t 制表
\\v 纵向制表
匹配字符串类
自己经常使用的数字、所有字母或所有数字字母字符等的匹配。为了方便工作,可以使用预定义的字符集,称为字符集:
类 说明
[:alnum:] 任意字母和数字,同[0-9a-za-z]
[:alpha:] 任意字符,同[a-za-z]
[:blank:] 空格和制表,同\\t
[:cntrl:] ascii控制字符,ascii0到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个匹配
{n} 指定数目匹配
{n,} 不少于n个匹配
{n,m} 匹配数目的范围m不超过255
列:select columnone from table where columnone regexp '\\([0-9]sticks?)\\';
sticks?匹配的是 stick 或sticks(?号决定前面的s出现一次或0次)
列:select columnone from table where columnone regexp'[[:digit:]]'orderby columnone;
[:digit:]匹配任意的数字,{4}要求前面匹配的数字出现4次
定位符
前面的所有例子都是匹配一个串中的任意位置的文本。为了匹配特定位置的文本
元字符 说明
^ 文本的开始
$ 文本的结束
[[:<:]] 词的开始
[[:>:]] 词的结束
例如:你要找一个数(包括以小数点开始的数)开始的所有产品,怎么办,前面都是在行内任意位置匹配。所以不行
select columnone from table where columnone regexp '^[0-9\\ . ]';
简单的正则测试,可以不在数据库操作的情况下练习
select 'hello' regexp '[0-9]';
mysql必知必会笔记(三)select语句 计算字段 数据处理函数 汇总函数 分组数据 子查询
第十章 创建计算字段
计算字段
存储在表中的数据一般不是应用程序所需要的格式。我们需要直接从数据库中检索出转换、计算或格式化的数据。而不只是检索出数据,然后再到应用程序或报告程序中区格式化。
这就发挥了计算字段的作用了。与前面的字段不同,计算字段并不实际存在于数据库中。计算字段是运行时在select 语句中创建的。
需要注意的是,只有select语句知道那些列是实际列,哪些列不是,客户机的角度来看,计算字段和其他字段是一样的。
拼接字段
拼接:将值联结到一起构成单个值。
生成供应商 columnone(columntwo) 的格式
selectconcat(columnone, '(' ,columntwo, ')')from table orderby columnone;
使用别名
别名使用as关键字赋予
执行算术运算
另一常见的用途就是对检索出来的数据进行算术运算。
例如:检索出column_id 为2005的columnone乘以columntwo的值
select column_id,columnone, columntwo, columnone*columntwoascolumn_pricefrom table where column_id = 2005
操作符 + - * /
select 3*2;将返回6
select now(); 返回当前的日期和时间
第十一章 使用数据处理函数
sql实现了一下类型的函数
1 用于处理文本串,如删除、填充、装换大小写
2 用于数据上进行的算术操作,如返回绝对值,进行代数运算
3用于处理日期和时间值并从这些值中提取特定的成分,如返回两个日期差,检查日期有效性
4 返回dbms正使用的特殊信息,如用户登录信息,检查版本细节信息
文本处理函数
upper() 将文本转换为大写
select vend_name, upper(vend_name)as vend_name_upcase from vendors orderby vend_name;
常用的文本处理函数
left() 返回串左边的字符
length() 返回串的长度
locate() 找出串的一个子串
lower() 将串转换为小写
right() 返回右边的字符
soundex() 返回串的soundex值
substring() 返回串的字符
upper() 将串转换ewing大写
soundex()是一个将任何文字串转换为描述语音表示的字母数字模式的算法。他考虑了类似发信字符和音节,使得能对串进行发音的比较而不是字母比较,如:y.lee搜索可以匹配y.lie
select cust_name ,cust_contact from customers wheresoundex(cust_contact) = soundex('y lie')
删除多余空格的函数
rtrim() ltrim() trim() 依次是删除右边 左边 两边的空格
selectconcat(rtrim(vend_name), '( ' ,rtrim(vend_country), ') from vendors orderby vend_name;
日期和时间处理函数
日期和时间常用相应的数据类型和特色的格式存储,以便能快速和有效的排序或过滤,并节省物理存储空间。
adddate() 增加一个日期 天、周等
addtime() 增加一个时间 时、分等
curdate() 返回当前日期
curtime() 返回当前时间
date() 返回日期时间的日期部分
datediff() 计算两个日期之差
date_add() 高度灵活的日期或时间串
date_format() 返回一个格式的日期或时间串
day() 返回一个日期的天数部分
dayofweek() 对于一个日期,返回对于星期几
hour() 返回一个时间的小时部分
minute() 返回一个时间的分钟部分
moth() 返回一个日期的月份部分
now() 返回当前的日期和时间
second() 返回一个时间的秒部分
time() 返回一个日期时间的时间部分
year() 返回一个日期的年份部分
mysql日期格式必须为yyyy-mm-dd,如2010-05-03。虽然其他日期格式也行,但这是首选格式,因为他排除了多义性。
例如,存储的日期列中的日期是2010-11-05 15:23:05 如果想找出2010-11-05这天的数据,使用前面的语句就不行了。这是要使用date()函数指示mysql提取列的日期的部分
select cust_id, order_numfrom orders wheredate(order_date) ='2010-11-05';
检索出2005-5月份的订单怎么办呢?可以使用between
select cust_id,order_num from orders wheredate(order_date) between '2005-05-01' and'2005-05-30';
还有一种不需要记住天数的函数month(),使年份相等,再让月份相等就行了
select cust_id,order_num from orders whereyear(order_date) = 2005andmonth(order_date) = 5;
数值处理函数
abs() 返回一个数的绝对值
cos() 返回一个角度的余弦
exp() 返回一个数的指数值
mod() 返回除操作的余数
pi() 返回圆周率
rand() 返回一个随机数
sin() 返回一个角度的正弦值
sqrt() 返回一个数的平方根
tan() 返回一角度的正切
第十二章 汇总函数
msyql提供这些函数以便分析和报表生成,这种类型的检索例子有以下几种:
汇聚函数 :运行在行组上,计算和返回单个值的函数
1确定表中的行数(或者满足某个条件或包括某个特定的值的行数)
2获得表中行组的和
3找出表列(或所有行或某特定行的)最大值、最小值和平均值
avg() 返回某列的平均值
count() 返回某列的行数
max() 返回某列的最大值
min() 返回某列的最小值
sum() 返回某列值之和
求products表中产品的平均价格
selectavg(prod_price) as avg_price from products;
求products表中编号为1003产品的平均价格
selectavg(prod_price) as avg_price from products where vend_id = 1003;
avg()函数只能用来确定特定数值列的平均值,而且名必须作为函数参数给出。为了获得多个平均值,必须使用多个avg()函数,avg()函数忽略列值为null的行
count()函数的两种使用方式:
1 count(*) 对表中的数目进行计数,不管表列中包含的是null值还是非空值
2 count(column) 对特定的列中具有值的进行计数,忽略null值
select count(*) as num_cust from customers;
select count(cust_email) as num_cust from customers;
max()函数 ,忽略列值为null的行
select max() as max_price from products;
min() 与max()函数一样
sum()函数
selectsum(quantity) as items_ordered from orderitems where order_num = 2005
下面是mysql5以后的函数 在mysql4中不能正常运行
distinct 参数,作用是返回不相同的值
下面是返回供应商提供的产品的平均值,它与上面的select 语句相同,但使用了distict参数,因此平均值只考虑各个不同价格合起来的平均值
selectavg(distinctprod_price) as avg_price from products wherevend_id=10003;
如果指定了列名,distinct参数只能用于count(),distinct参数不能用于count(*)应为distinct必须使用列名。
第十三章 分组数据
分组允许把数据分成多个逻辑组,比便能对每个组进行聚集计算。
分组是在select 语句的 group by 子句中建立的。
返回每个厂商提供了几个产品
select vend_id, count(*) as num_prods from products groupby vend_id;
group by一些重要规定
1 group by 子句可以包含任意数目的列。这使得能对分组进行嵌套,为数据分组提供了更细致的控制
2 如果在group by 子句中嵌套了分组,数据将在最后规定的分组上进行汇总,换句话说,在建立分组时,指定的所有列都一起计算(所以不能从个别列取回数据)
3 group by 子句列出的每个列都必须是检索列或有效的表达式,(但不能是聚集函数)如果。在select 中使用了表达式,则必须在group by 子句中指定相同的表达式,不能使用别名。
4 除聚集计算语句外,select 语句中的每个列都必须在group by 子句中给出
5 如果分组列中具有null值,不管一个或多个都将作为一个分组返回
6 group by 子句必须出现在where 子句之后,group by 子句之前
过滤分组
如想要得到大于3的不同产品订单
where 是过滤指定的行而不是列。 having 支持所有 where 操作符。
select cust_id, count(*) as orders from orders groupby cust_id havingcount(*) >3;
where 是在分组前进行过滤, having 是在分组后进行过滤
分组和排序区别
order by group by
排序产生的输出 分组行,单输出可能不是分组的顺序
任意列都可以使用(甚至只可能使用选择列或表达式,而且必须使用每个选择列表达式
是分选择列也可以使用)如果与聚集哈思楠一起使用列(或表达式)则必须使用
不一定需要
例子:检索总计订单价格大于50的订单号和总计订单
select order_num , sum(quantity*item_price) as ordertotal from orderitems group by order_num having sum(quantity*item_price)>= 50;
按订单价格进行排序,后面加 order byordertotal;
select子句顺序
select 要返回的列或表达式
from 从中检索数据的表
where 行级过滤
grounp by 分组说明
having 组级过滤
order by 输出排序顺序
limit 要检索的行数
第十四章 使用子查询
sql还允许使用子查询,即嵌套在其他查询中的查询。
利用子查询进行过滤
select cust_id from orders where order_num in(
select order_num from orderitems where prod_id = 'tnt2'
)
可以把一条select语句返回的结果用于另一条select语句的where 子句
格式化sql 包含子查询的sql语句难以,可以使用适当的缩进。
得到了订购物品tnt2的所有客户id,下一步是检索这些客户的信息,总语句是
select cust_name ,cust_contact from customers where cust_id in(
select cust_id from orders where order_num in (
select order_num from orderitems where prod_id = 'tnt2'
)
)
列必须匹配在where子句中使用子查询,应该保证select语句具有where子句中相同数目的列。通常子查询将返回的单个列于单个列匹配,但如果需要也可以多个列。
虽然子查询一般与in操作符结婚使用,但也可以用于测试等于、不等于等符号
作为计算字段使用子查询
使用子查询的另一个方法是创建计算字段。
假设需要显示sustomers表中每个客户的订单总数。
select cust_name ,cust_state,(
selectcount(*) from orders where orders,coust_id =customers . cust_id
) as orders from customers orderby cust_name;
mysql必知必会笔记(四)select语句 联结表 高级联结 组合查询 全文本搜索
第十五章 联结表
sql最强大的功能之一就是能在数据检索查询的执行中联结(join)表。联结是利用sql的select能执行的最重要的操作,能很好的理解联结及其语法是学习sql的一个极为重要的组成部分。
外键:外键为某个表中的一列,它包含另一个表的主键值,定义了两个表之间的关系。
好处:供应商信息不重复,不浪费空间和时间,方便日后修改,一个表信息改动不影响另一个表的信息
联结是一种机制,使用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。
创建联结
selectvend_name , prod_name , prod_price
fromvendors , products
wherevendors.vend_id = products . vend_id
order byvend_name , prod_name; ;
如果没有where子句,表一中的每行将于表二中的每行配对,而不管他们逻辑是否可以配在一起。其配对的结果是笛卡尔积。就是表一行数*表二行数
内部联结
前面讲的联结称为等值联结,它基于两个表之间的相等测试。这种联结也称为内部联结。前其实这种联结可以使用稍微不同的语法来明确指定联结的类型。下面是语句与上面返回一样
selectvend_name ,prod_name , prod_price
fromvendors
inner join products on vendors . vend_id = products . vend_id;
这里的两个表之间的关系是由from 子句组成的。以 inner jion指定。使用这种语法时。联结子句的条件用特定的on子句而不是where子句给出。传递给on的跟传递给where的子句相同。
首选使用inner join语法,这样不会忘记联结的条件,虽然where子句定义联结比较简单。
联结多个表
selectprod_name ,vend_name ,prod_price , quantity
fromorderitems , products , vendors
whereproducts . vend_id = vendors.vend_id
and orderitems.prod_id =products.prod_id
andorder_num = 20005;
考虑到多个表联结时会耗费资源,所以尽量不要联结不必要的表。
第十六章 创建高级联结
使用别名
select concat(rtrim(vend_name) , '(' , rtrim(vend_country) , ')')as vend_title
from vendors order by vend_name;
别名除了用于列名和计算字段外,sql还允许给表名起别名。一可以缩短sql语句,二允许在单条select 语句中多次使用相同的表
selectcust_name ,cust_contact
fromcustomers as c , orders as o , orderitems as oi
wherec.cust_id = o.cust_id andoi.order_num = o.order_num and prod_id = 'tn2'
表的别名和列的别名不一样,表的别名不返回给客户端
使用不同类型的联结
前面为止我们使用的只是称为内部联结或等值联结的简单联结。现在来看其他3中联结。分别是自联结、自然联结和外部联结
自联结
使用表别名的主要原因之一是能在单条select语句中不止一次引用相同的表。举个例子:
如果发现某物品(id为abc)存在问题,因此想知道生产该物品的生产商生产的其他物品是否也存在问题。此程序要求首先找到生产id为abc的物品的生产商,然后找出这个生产商生产的其他的物品。下面一种解决方法:
selectprod_id , prod_namefrom products where vend_id = (
selectvend_id from products where prod_id = 'abc'
);
上面使用的子查询,现在看使用联结的相同查询:
selectp1.prod_id ,prod_name
fromproductsasp1 , productsasp2
where p1.vend_id =p2.vend_id and p2.prod_id ='abc';
此联结查询需要的两个表实际上同一个表,
用自联结不用子查询 子联结通常作为外部语句用来代替从相同表中检索数据时使用的子查询语句,虽然结果一样,但是处理联结远不处理子查询要快的多。
自然联结
select * 改为 select 表名1.列名1 , 表名2.列名3 这样可以去除无用的列。执行效率更快
外部联结
许多联结将一个表中的行与另一个表中的行相关联。但有时候会需要包含没有关联行的那些行。
例如完成需要使用联结完成以下任务:
1对每个用户下了多少订单进行计数,包括那些至今尚未下订单的客户
2 列出所有产品以及订购数量,包括那些没有人订购的产品
3 计数平均销售规模,包括那些至今未下订单的客户
上述例子中,联结包含了那些在相关表中没有关联的行,这种联结类型的联结称为外部联结。
下面是select 语句给出一个简单的内部联结。它检索出了所有客户以及订单:
selectcustomers.cust_id , orders.order_num from customers
inner join orders on customers.cust_id = orders.cust_id;
外部联结语法类似。为了检索所有用户,包含那些没有订单的客户。可如下进行:
selectcustomers.cust_id , orders.order_num from customers
left outer join orders on customers.cust_id = order_cust_id;
这条sql语句使用了关键字outer join 来指定联结的类型(而不是where指定)。但是与内部联结关联两个表中的行不同的是,外部联结还包括没有关联的行。
使用outer join必须使用left或 right关键字指定包括其所有含的表。
使用带聚集函数的联结
聚集函数是用来汇总数据。它可以中单个表中汇总数据,也可以在联结中一起使用。
例子:检索所有客户及每个客户所下的订单数。。下面使用了count()函数的代码完成。
selectcustomer.cust_name, customer . cust_id , count(order.order_num) as num_ord
fromcustomers
inner joijnorders on customers.cust_id = orders.cust_id
group by customers.cust;
group by子句按客户分组数据。因此,函数调用count(orders.order_num)对每个客户的订单计数,将他作为num_ord返回
聚集函数也可以方便地与其他联结一起使用
selectcustomers.cust_name, customers.cust_id , count(order.order_num) as num_ord
from customers
left outer join orders on customers.cust_id = order.cust_id
group by customers.cust_id;
使用联结和联结条件
1注意所使用的联结类型,一般我们使用内部联结,但使用外部联结也是有效的。
2保证使用正确的联结条件,否则将返回不正确的数据;
3应该始终提供联结条件,否则会得出笛卡尔积
4在一个联结中可以包含多个表,甚至对于每个联结可以采用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在测试它们之前,分别测试每个联结。这将使故障排除更为简单。
第十七章 组合查询
前面的都是从一个或多个表中返回数据的单条select 语句。mysql也允许执行多个查询(多条select语句),并将结果作为单条查询结果集返回。这些组合查询通常称为 并union或复合查询
有两种情况需要使用组合查询
1在单个查询中从不同的表返回累世结构的数据
2对单个表执行多个查询,按单个查询返回数据
组合查询和多个where条件多数情况下,组合相同表的两个查询完成的工作与具有多个where子句完成的工作相同,换句话说,任何具有多个where子句的select语句都可以作为一个组合查询给出。
创建组合查询
可用union操作符来组合数条sql查询。给出多条select语句,将它们的结合组合成单个结果返回
使用union
使用很简单,在多条select语句之间放上关键词union。
例如:需要价格不大于5元,但是又要包含供应商1002和1001的所有产品,(不考虑价格)
selectvend_id,prod_id , prod_price fromproducts where prod_price <= 5
union
selectvend_id,prod_id , prod_price fromproducts where vend_id in(1001,1002)
or语句也能实现上面的查询
selectvend_id,prod_id , prod_price fromproducts
where prod_price <= 5 or vend_id in (1001,1002)
从上面这个简单的例子中,使用union可能比使用where子句更为复杂。但对于更复杂的过滤条件,或者从多个表而不是单个表中检索数据的情形,使用union肯会使处理更简单
union规则
正如所见,并是非常容易使用的,但在进行并时有几条规则需要注意
1 union必须由两条或两条以上的select语句组成,语句之间用关键字union分隔
2 union中的每个查询必须包含相同的列、表达式或聚集函数(不过各列不需要以相同的次序列出)
3列数据类型必须兼容:类型不完全相同,但不想是dbms可以隐含滴转换的类型。
包含或取消重复的行
如果select语句中返回的行相同,union会自动的去除重复的行。这是他的默认行为,但是如果需要,可以改变它,可以使用union all而不是union
selectvend_id,prod_id , prod_price fromproducts where prod_price <= 5
union all
selectvend_id,prod_id , prod_price fromproducts where vend_id in (1001,1002)
对组合查询结果排序
select语句的输出用order by子句排序。在union组合查询时,只能使用一条order by子句,它必须出现在最后一条select语句之后。
selectvend_id,prod_id , prod_price fromproducts where prod_price <= 5
union all
selectvend_id,prod_id , prod_price fromproducts where vend_id in (1001,1002)
group byvend_id,prod_price;
第十八章 全文本搜索
理解全文本搜索
并非所有的引擎都支持全文本搜索。最常使用的是myisam和innodb,前者支持全文本搜索,而后者不支持。如果你需要全文本搜索功能,应该记住这一点
关键字like,它利用通配操作匹配的文本(和部分文本)。使用like,能够查找包含特殊值或部分值的行(不管这些值位于那些位置)
基于文本的搜索作为正则表达式匹配列值的更进一步的介绍。使用正则表达式,可以编写查找所有行的非常复杂的匹配模式
虽然这些搜索机制非常有用。但存在几个重要的限制:
1性能——通配符和正则表达式匹配通常要求mysql尝试匹配表中所有的行(而且这些搜索极少使用表索引),因此,由于被搜索行数不断增加,这些搜索非常耗时
2明确控制——使用通配符和正则表达式匹配,很难(而且并不总能)明确的控制匹配什么和不匹配什么
3智能化的结果——虽然前两者都能提供了非常灵活的搜索,但它们都不能提供非常智能化的匹配结果。
前面的很多限制都可以使用全文本搜索来解决。使用全文本搜索。mysql创建指定列中各词的一个索引, 搜索可以针对这些词进行。
使用全文本搜索
启用全文本搜索
一般在创建表时启用全文本搜索。create table语句接受fulltext子句。它给出被索引列的一个逗号分隔的列表。
create tableproductontes
(
note_id intnot_nullauto_increment,
prod_id char(10) not_null,
note_date datetimenot_null,
note_text text not_null,
primary key(note_id),
fulltext(note_text)
)engine=myisam;
为了进行全文本搜索,mysql根据子句fulltext(note_text)的指示对它进行索引。这里funll_text索引了单个列,如果需要可以索引多个列,多列之间用逗号分隔
在定义之后mysql对自动维护该索引,在增加、更新和删除行时,索引随之自动更新。
不要在导入数据时使用funlltext,否则会耗费很多时间,应该先导入数据,再定义fulltext这样有助于更快的导入数据
进行全文本搜索
在索引之后,使用两个函数match()和against()执行全文本搜索,其中match()指定被搜索的列against()指定要使用的搜索表达式。
selectnote_text from productnotes wherematch(note_text) against('rabbit');
使用完整的match()说明:传递给match()的值必须和与fulltext()定义中的相同。如果指定了多个列,则必须列出它们(而且次序正确)
除非使用binary方式,否则全文本搜索不区分大小写
使用select 语句同样可以检索出两行,但次序不同。
全文本搜索返回一文本匹配的良好程度的数据。具有较高等级的行先返回。
使用查询扩展
查询扩展用来设法放宽所返回的全文本搜索结果的范围。想找出与搜索有关的其他行。不包含要搜索才字母。
如select note_text from productnotes where match(note_text) against('anvils');
返回一行数据
使用查询扩展
selectnote_text from productnotes
where match(note_text) against('anvils' with query expansion);
返回7行
布尔文本搜索
mysql支持全文本搜索的另一种形式,称为布尔方式。布尔方式可以提供以下细节:
1要匹配的词
2要排斥的词(如果该行包含这个词,则不返回该行,即使它已经包含指定的词也是如此)
3排列提示(指定某些词比其他词重要,更重要的词的词等级更高)
4表达式分组
5另外一些内容
即使没有fulltext索引也可以使用 布尔方式不同迄今为止使用的全文本搜索语法的地方在于,即使没有定义fulltext索引,也可以使用它,但这是一种非常缓慢的操作(其性能将随着数据量的增加而降低)
例如:匹配包含heavy但不包含任意以rope开始的词的行,可以使用以下查询:
selectnote_text from productnotes
where match(note_text) against('heavy -rope*' inboolean mode)
全文本布尔操作符
+包含,词必须存在
-排除,词必须不出现
>包含,而且增加等级值
<包含,而且减少等级值
()吧词组成子表达式(允许这些子表达式作为一个组被包含)
~取消一个词的排序值
*词尾的通配符
""定义一个短语,(与单词不一样,它匹配整个短语以便包含或排除这个短语)
selectnote_text from productnotes
where match(note_text) against('+hea +rop' in boolean mode)
//包含hea和rop的行
selectnote_text from productnotes
where match(note_text) against('hea rop' in boolean mode)
//包含hea和rop至少一个就行的行
selectnote_text from productnotes
where match(note_text) against('"hea rop"' in boolean mode)
//包含hea rop这个短语而不是hea和rop的行
selectnote_text from productnotes
where match(note_text) against('>hea
//包含hea和rop的行,增加前者的等级,降低后者的等级
selectnote_text from productnotes
where match(note_text) against('+hea +(
//包含hea和rop的行降低后者的等级
全文本搜索使用说明:
1在索引全文本数据时,短语被忽略且从索引中排除,短语定义为那些具有3个或3个以下字符的词,如果需要,这个数目可以更改
2 mysql内建一个非用词(stopword)列表,这些词在索引全文本数据时总是被忽略,如果需要,可以覆盖这个列表
3许多词出现的频率高,搜索它们没有用处(返回太多的结果),因此mysql规定了一条50%的规则,如果一个词出现在50%以上的行中,则它将作为一个非用词忽略,50%规则不适用与in boolean mode
4如果表中的行数少于3行,则全文本搜索不返回结果(因为每个词或者不出现,或者少于出现在50%的行中)
5忽略词中的单引号,例如 don't 索引为 dont
6不具有词分隔符(包含日语和汉语)的语言不能恰当地返回全文本搜索结果
7如前所述,仅在myisam数据库引擎中是支持全文本搜索的
mysql必知必会笔记(五)插入数据 创建和操纵表
第十九章 插入数据
insert是用来插入(或添加)行到数据库表的。插入数据的几种方式:
1 插入完整的行
2 插入行的一部分
3 插入多行
4 插入某些查询结果
insertselect语句
insert intocustomers(cust_id,cust_name,cust_email)
selectcust_id,cust_name,cust_email from custnew;
列省略
如果表中定义允许,则可以在insert操作中省略某些列,省略的列必须满足以下某个条件。
1 该列定义为允许为null
2 在表定义中给出默认值,
提高整体性能
数据库经常多个客户访问,对处理什么请求以及用什么次序处理进行管理mysql的任务。insert操作可能很耗时(特别是由很多索引需要更新时),而且它可能降低等待处理的select语句性能。
如果数据检索是最重要的(通常是这样的),则你可以通过在insert 和into之间添加关键字 low_priority 指示mysql降低insert语句的优先集
第二十章 更新和删除数据
更新和删除数据
为了更新(修该)表中的数据,可使用update语句,可采用两种方式使用update
1 更新表中特定的行
2 更新表中所有的行
更新行和删除行的时候一定要加上where子句,否则后果自负
update bname set zda ='acontent' , zdb = 'bcontent' where zdid='20005';
ignore 关键字 如果使用update更新多行,并且在更新这些行中的一行或多行时出现一个错误,则整个update操作被取消,(错误发生前更新的所有行被恢复到他们原来的值)为即使发生错误也继续进行更新。可使用ignore关键字
update ignore bname;
删除数据
为了从表中删除(去掉)数据,使用delete语句,可以使用两种方式:
1 从表中删除特定的行
2 从表中删除所有的行
不要省略where子句
更快的删除 如果想从表中删除所有的行,不要使用delete,可以使用truncate table语句,他完成相同的工作,但速度更快(truncate实际上是删除原来的表并重新创建一个表,而不是逐行去删除表中的数据)
更新和删除的指导原则
下面是许多sql程序员使用的update或delete是所遵循的习惯
1 除非确实打算更新和删除每一行,否则绝对不要使用不带where子句的update或delete语句。
2 保证每个表都有主键,尽可能的像where子句那样使用它(可以指定各主键、多个值、和值的范围)
3 在对update和delete语句操作使用where前,应该先用select进行测试,保证它过滤的数据是正确的记录,以防编写的where子句不正确。
4 使用强制实施引用完整的数据库,这样mysql将不允许删除具有与其他表相关联的数据的行
第二十一章 创建和操纵表
创建表
一般两种创建表的方法
1 使用具有交互式创建和管理表的工具
2 表也可以直接用mysql语句操纵
在使用交互式工具时,工具也是生成mysql语句操纵数据库
表创建基础
为了利用create table创建表,必须给出下列信息:
1 新表的名字,在关键字create table之后给出
2 表列的名字和定义,用逗号分隔
create table table
(
column_id int not null auto_incrment,
columnone char(20) not null default 1,
columnone char(20) not null ,
column char(20) not null ,
.....
primary key ( column_id)
) engine = innodb
如果表已经存在,则必须先删除后在创建他,不可以直接覆盖。如果仅想在表没有存在的情况下创建它,应该在表名后给出ifnot exists
使用null值 如果不指定列为not null则它默认是null
主键再介绍 主键的值必须是唯一的。创建主键时可以用单列做主键primary key(columnone,columntwo),也可以使用多列做主键primary key(columnone,columntwo).主键值不允许为null
索引创建
create index indexname on tablename(column [asc|desc],....);
使用auto_increment
每个表只允许使用一个auto_increment列,而且它必须被索引,(如通过使它为主键)
如果两个表关联,添加时一表时需要另一表的主键,该怎么获得呢:
可以使用last_insert_id()函数获得这个值 此语句返回最后一个auto_crement的值。
指定默认值
如果在插入行时没有给出值,mysql允许指定此时使用默认值。默认值是在createtable语句的列定义中的default关键字定义的。
columnone char(20) not null default 1,
mysql不允许使用函数作为默认值,它只支持常量
引擎搜索
你可能已经注意到,迄今为止使用的create table语句全都以engine = innodb语句结束
与其他的dbms一样,mysql有一个具体管理和处理数据的内部引擎,在你使用createtable语句是,该引擎具体创建表,在其他应用中区修改读取删除表等处理你的请求,多数时候它隐藏在dbms内,不需要过多的关注它。
但mysql与其他的dbms不一样,它具有多种引擎,它打包多个引擎,这些引擎都隐藏在mysql服务器内,全都能处理用户的请求。
为什么要发行多种引擎呢,因为他们具有各自不同的功能和特性,为了不同的任务选择正确的引擎能获得良好的功能和灵活性
当然你也可以省略这些数据库引擎,如果省略engine=语句,则使用默认引擎(很可能为myisam),多数sql语句都会默认使用它,但并不是所有的语句都默认使用它,这就是为什么engine=语句很重要的原因。
以下几个需要知道的引擎
1 innodb是一个可靠的事务处理引擎,它不支持全文本搜索。
2 memory 在功能上等同于mysam,但由于数据存储在内存,所以速度更快(特别适用于临时表)
3 mysam是一个性能极高的引擎,它支持全文本搜索,但不支持事务处理
引擎类型可以混用。混用引擎类型的一个大缺陷。外键不能跨引擎,即使用一个引擎的表不能引用具有使用不同引擎的表的外键
更新表
为了更新表,可以使用alter table语句,但是在理想状态下,当表中存储了数据后就不应该再去更新表了。所以在设计表时需要花费大量的时间去考虑,以便后期不做太大的改动。
alert table更改表结构,必须给出下面的信息:
1 在alert table之后给出要修改的表名
2 所做更改的列表
添加一列alert table column add columnfour char(90);必须指明数据类型
删除一列alert table column dorpcolumnfour ;
定义外键
alert table tableone add constraintcolumnone
foreign key (column_id) peferences tabletwo(column_id)
可以单条alter table语句对单个表进行多个修改,每个修改用逗号分隔开。
复杂的表结构一般需要手动删除过程
1 用新的列布局创建一个新表
2 使用insert select 语句从旧表复制数据当道新表。如果有必要,可以使用转换函数和计算字段
3 检验包含所需数据的新表
4 重名名旧表
5 用旧表原来的名字重命名新表
6 根据需要,重新创建触发器、存储过程、索引和外键
小心使用alter table 因为它是不可逆的操作,最好操作前完成已备份。
删除表
dorp table table; 不可撤销,永久删除表
重命名表
rename table table to table2; 多个表重命名 逗号分隔开
create databse [if not exists] dataname;
dorp databses [if exists] databses;
在整型数据列后加上 unsigned 属性可禁止负数,取值从0开始。范围扩大一倍-125---125 0-250
zerofill 数据字段属性,在数值之前自动用0补足不足的位数,声明一个int(3)zerofill插入5 返回005
create table tablename(
id int(5) unsigned.......
num ind(3) zerofill....
sex int(1) default 0 ......
namevarchar(10) not null......
)
mysql默认字符集设置:win my.ini linux /etc/my.cnf
character-set-server =gbk;
collation-server=gbk_chinese_ci;
创建数据库时设置字符集语句:
create database if notmydb default character set utf8 collate utf8_general_ci;
数据库文件结构
一个myisam数据表会有三个文件,以.frm为后缀的结构定义文件,以.myd为后缀名的数据文件,一个以.myi为后缀名的索引文件
一个innodb数据表只有一个文件
create table t (i int) engine =innodb;
create table t (i int) type = myisam;
mysql_db_query(''sql........,$linke) 当文件连接两个数据库时指定在哪个数据库上执行
当query函数出错时可以用mysql_errno()【错误号】和mysql_error()函数来确定
当query函数执行后可以使用mysql_affected_rows()来查看他们到底修改了多少行
还可以mysql_insert_id()查看最后插入的自增字段(id)值
查询结果集处理
$result =mysql_query(select * from books);
$rows=mysql_num_rows($result); 显示结果的行数
$cols =mysql_num_fields($result);显示结果的列数
mysql_fetch_row();将一条结果记录返回并以一个普通索引数组的形式保存
mysql_fetch_assoc();将一条结果记录返回并以一个普通关联数组的形式保存
mysql_fetch_array();将一条结果记录返回一个关联数组或索引数组,或同同时获得索引关联数组,通过传递mysql_assoc 、mysql_nummysql_both中的一个常量返回不同的数组形态。默认使用mysql_both常量
mysql_fetch_object(); 以一个对象的形式返回一条结果记录,它的各个记录需要以对象的方式进行访问。
获取列数信息(数据类型,长度,索引) mysql_fetch_fields()
php默认把结果集一直保存到php脚本执行结束为止,如果想提前释放结果集,使用mysql_free_result()函数。
mysql必知必会笔记(六)存储过程 游标 触发器
第二十三章 使用存储过程
mysql5 中添加了存储过程的支持。
大多数sql语句都是针对一个或多个表的单条语句。并非所有的操作都怎么简单。经常会有一个完整的操作需要多条才能完成
存储过程简单来说,就是为以后的使用而保存的一条或多条mysql语句的集合。可将其视为批文件。虽然他们的作用不仅限于批处理。
为什么要使用存储过程:优点
1 通过吧处理封装在容易使用的单元中,简化复杂的操作
2 由于不要求反复建立一系列处理步骤,这保证了数据的完整性。如果开发人员和应用程序都使用了同一存储过程,则所使用的代码是相同的。还有就是防止错误,需要执行的步骤越多,出错的可能性越大。防止错误保证了数据的一致性。
3 简化对变动的管理。如果表名、列名或业务逻辑有变化。只需要更改存储过程的代码,使用它的人员不会改自己的代码了都。
4 提高性能,因为使用存储过程比使用单条sql语句要快
5 存在一些职能用在单个请求中的mysql元素和特性,存储过程可以使用它们来编写功能更强更灵活的代码
换句话说3个主要好处简单、安全、高性能
缺点
1 一般来说,存储过程的编写要比基本的sql语句复杂,编写存储过程需要更高的技能,更丰富的经验。
2 你可能没有创建存储过程的安全访问权限。许多数据库管理员限制存储过程的创建,允许用户使用存储过程,但不允许创建存储过程
存储过程是非常有用的,应该尽可能的使用它们
执行存储过程
mysql称存储过程的执行为调用,因此mysql执行存储过程的语句为call .call接受存储过程的名字以及需要传递给它的任意参数
call productpricing(@pricelow ,@pricehigh , @priceaverage);
//执行名为productpricing的存储过程,它计算并返回产品的最低、最高和平均价格
创建存储过程
create procedure存储过程名()
一个例子说明:一个返回产品平均价格的存储过程如下代码:
create procedure productpricing()
begin
select avg(prod_price) as priceaverage
from products;
end;
//创建存储过程名为productpricing,如果存储过程需要接受参数,可以在()中列举出来。即使没有参数后面仍然要跟()。begin和end语句用来限定存储过程体,过程体本身是个简单的select语句
在mysql处理这段代码时会创建一个新的存储过程productpricing。没有返回数据。因为这段代码时创建而不是使用存储过程。
mysql命令行客户机的分隔符
默认的mysql语句分隔符为分号 ; 。mysql命令行实用程序也是 ; 作为语句分隔符。如果命令行实用程序要解释存储过程自身的 ; 字符,则他们最终不会成为存储过程的成分,这会使存储过程中的sql出现句法错误
解决方法是临时更改命令实用程序的语句分隔符
delimiter // //定义新的语句分隔符为//
create procedure productpricing()
begin
select avg(prod_price) as priceaverage
from products;
end//
delimiter ; //改回原来的语句分隔符为;
除\符号外,任何字符都可以作为语句分隔符
callproductpricing(); //使用productpricing存储过程
执行刚创建的存储过程并显示返回的结果。因为存储过程实际上是一种函数,所以存储过程名后面要有()符号
删除存储过程
drop procedure productpricing ; //删除存储过程后面不需要跟(),只给出存储过程名
为了删除存储过程不存在时删除产生错误,可以判断仅存储过程存在时删除
drop procedure ifexists
使用参数
productpricing只是一个简单的存储过程,他简单地显示select语句的结果。
一般存储过程并不显示结果,而是把结果返回给你指定的变量
create procedure productpricing(
out p1 decimal(8,2),
out ph decimal(8,2),
out pa decimal(8,2),
)
begin
select min(prod_price)
into p1
from products;
select max(prod_price)
into ph
from products;
selectavg(prod_price)
into pa
from products;
end;
此存储过程接受3个参数,p1存储产品最低价格,ph存储产品最高价格,pa存储产品平均价格。每个参数必须指定类型,这里使用十进制值。关键字out指出相应的参数用来从存储过程传给一个值(返回给调用者)。mysql支持in(传递给存储过程)、out(从存储过程中传出、如这里所用)和inout(对存储过程传入和传出)类型的参数。存储过程的代码位于begin和end语句内,如前所见,它们是一些列select语句,用来检索值,然后保存到相应的变量(通过into关键字)
调用修改过的存储过程必须指定3个变量名:
call productpricing(@pricelow ,@pricehigh , @priceaverage);
这条call语句给出3个参数,它们是存储过程将保存结果的3个变量的名字
变量名 所有的mysql变量都必须以@开始
使用变量
select@priceaverage ;
select @pricelow ,@pricehigh , @priceaverage ; //获得3给变量的值
下面是另一个例子,这次使用in和out参数。ordertotal接受订单号,并返回该订单的合计
create procedure ordertotal(
in onumber int,
out ototaldecimal(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(2005 ,@total); //这样查询其他的订单总计可直接改变订单号即可
select @total;
建立智能的存储过程
上面的存储过程基本都是封装mysql简单的select语句,但存储过程的威力在它包含业务逻辑和智能处理时才显示出来
例如:你需要和以前一样的订单合计,但需要对合计增加营业税,不活只针对某些顾客(或许是你所在区的顾客)。那么需要做下面的事情:
1 获得合计(与以前一样)
2 吧营业税有条件地添加到合计
3 返回合计(带或不带税)
存储过程的完整工作如下:
-- name: ordertotal
-- parameters: onumber=订单号
-- taxable = 1为有营业税0为没有
-- ototal =合计
create procedure ordertotal(
in onumber int,
in taxable boolean,
out ototaldecimal(8,2)
-- comment()中的内容将在show procedure statusordertotal()中显示,其备注作用
) comment 'obtain ordertotal , optionally adding tax'
begin
--定义total局部变量
declare total decimal(8,2)
declare taxrate intdefault 6;
--获得订单的合计,并将结果存储到局部变量total中
select sum(item_price*quantity)
from orderitems
where order_num =onumber
into total;
--判断是否需要增加营业税,如为真,这增加6%的营业税
if taxable then
selecttotal+(total/100*taxrate) into total;
end if;
--把局部变量total中才合计传给ototal中
select total into ototal;
end;
此存储过程有很大的变动,首先,增加了注释(前面放置--)。在存储过程复杂性增加时,这样很重要。在存储体中,用declare语句定义了两个局部变量。declare要求制定变量名和数据类型,它也支持可选的默认值(这个例子中taxrate的默认设置为6%),select 语句已经改变,因此其结果存储到total局部变量中而不是ototal。if语句检查taxable是否为真,如果为真,则用另一select语句增加营业税到局部变量total,最后用另一select语句将total(增加了或没有增加的)保存到ototal中。
comment关键字 本列中的存储过程在create procedure 语句中包含了一个comment值,他不是必需的,但如果给出,将在show procedurestatus的结果中显示
if语句 这个例子中给出了mysql的if语句的基本用法。if语句还支持elseif和else子句(前者还使用then子句,后者不使用)
检查存储过程
为显示用来创建一个存储过程的create语句,使用show createprocedure语句
show create procedure ordertotal;
为了获得包括何时、有谁创建等详细信息的存储过程列表。使用show procedure status.限制过程状态结果,为了限制其输出,可以使用like指定一个过滤模式,例如:show procedurestatus like ''ordertotal;
第二十四章 使用游标
mysql5添加了对游标的支持
只能用于存储过程
由前几章可知,mysql检索操作返回一组称为结果集的行。都与mysql语句匹配的行(0行或多行),使用简单的select语句,没有办法得到第一行、下一行或前10行,也不存在每次行地处理所有行的简单方法(相对于成批处理他们)
有时,需要在检索出来的行中前进或后退一行或多行。这就是使用游标的原因。游标(cursor)是一个存储在mysql服务器上的数据库查询,它不是一条select语句,而是被该语句检索出来的结果集。在存储了游标之后,应用程序可以根据需要滚动或浏览其中的数据。
游标主要用于交互式应用,其中用户需要滚动屏幕上的数据,并对数据进行浏览或做出更改。
使用游标
使用游标涉及几个明确的步骤:
1 在能够使用游标前,必须声明(定义)它,这个过程实际上没有检索数据,它只是定义要使用的select语句
2 一旦声明后,必须打开游标以供使用。这个过程用钱吗定义的select语句吧数据实际检索出来
3 对于填有数据的游标,根据需要取出(检索)的各行
4 在接受游标使用时,必须关闭它如果不明确关闭游标,mysql将会在到达end语句时自动关闭它
创建游标
游标可用declare 语句创建。 declare命名游标,并定义相应的select语句。根据需要选择带有where和其他子句。如:下面第一名为ordernumbers的游标,使用了检索所有订单的select语句
create procedure processorders()
begin
declare ordernumbers cursor
for
select order_num from orders ;
end;
存储过程处理完成后,游标就消失,因为它局限于存储过程
打开和关闭游标
create procedure processorders()
begin
declareordernumbers cursor
for
select order_num from orders ;
open ordernumbers ;
close ordernumbers ; //close释放游标使用的所有内部内存和资源,因此,每个游标不需要时都应该关闭
end;
使用游标数据
在一个游标被打开后,可以使用fetch语句分别访问它的每一行。fetch指定检索什么数据(所需的要列),检索出来的数据存储在什么地方。它还向前移动游标中的内部行指针,使下一条fetch语句检索下一行,相当于php中的each()函数
循环检索数据,从第一行到最后一行
create procedure processorders()
begin
--声明局部变量
declare done boolean default 0;
declare o int;
declareordernumbers cursor
for
select order_num from orders ;
--当sqlstate为02000时设置done值为1
declare continuehandler for sqlstate '02000' set done=1;
--打开游标
open ordernumbers ;
--开始循环
repeat
--把当前行的值赋给声明的局部变量o中
fetch ordernumbers into o;
--当done为真时停止循环
until done end repeat;
--关闭游标
close ordernumbers ; //close释放游标使用的所有内部内存和资源,因此,每个游标不需要时都应该关闭
end;
语句中定义了continue handler ,它是在条件出现时被执行的代码。这里,它指出当sqlstate '02000'出现时,set done=1。sqlstate '02000'是一个未找到条件,当repeat没有更多的行供循环时,出现这个条件。
declare语句次序 用declare语句定义局部变量必须在定义任意游标或句柄之前定义,而句柄必须在游标之后定义。不遵守此规则就会出错
重复和循环 除这里使用repeat语句外,mysql还支持循环语句,它可用来重复
上一篇: C++字符串输入缓冲区机制详解