日志文章

2006-07-02

mysql笔记(转)

select 的使用 i\cMog  
1#lr1JIMm  
    现在,数据表都已经创建起来了,假设我们已经插入了许多的数据,我们就可以用自己喜欢的方式对数据表里面的信息进行检索和显示了,比如说:可以象下面这样把整个数据表内的内容都显示出来 ]*;%{DX  
M?] ~q}LT  
    select * from president; GY(4b+d  
AX 4m?19  
也可以只选取某一个数据行里的某一个数据列 dwCea_q@i\  
+ Lr"!;  
    select birth from president where last_name=’Eisenhower’; r*K$U8Xd9  
*Zo)}>CC  
select语句的通用形式如下: cD]6eh;  
5_BcwUk<T  
    select 你要的信息 tNR@C)gS:  
    from 数据表(一个或多个) jj9 Ens  
    where 满足的条件 i4J?0F&M  
_ XvD#LZ  
select语句有几个子句,他们的各种搭配能帮你查出最感兴趣的信息,这些子句可以很简单,也可以很复杂,看看作者是如何详细讲解的 { N%G TD  
}6UE[hw  
1,用各种操作符来设定检索条件 zFG[OKa U  
e%^u!;wR;  
要想让select语句只把满足特定条件的记录检索出来,就必须给它加上where字句来设置数据行的检索条件。只有这样,才能有选择地把数据列的取值满足特定要求的那些数据行挑选出来。可以针对任何类型的值进行查找,比如说,对数值进行搜索 eKy.TPu  
select * from score where score>95; //显示所有分数在95分以上的信息 Z L)  
也可以针对字符串值进行查找 >t;N(kY?0  
select last_name,first_name from president where last_name=’Tom’; //找出所有姓tom的总统 fw"7` /m  
还可以对不同类型的值进行组合查找 Y&h3MJ@L  
select last_name,first_name,birth,state from president XrGGO-1i  
where birth<’1950-1-1’ and (state=’VA’ or state=’BA’); TKe.o[S  
//找出1950年前出生于VA州或BA州的总统 W*c&v>jp  
可见 where子句中可以使用的是算术操作符(+-*/%),比较操作符(<>=)以及逻辑运算符,我们应该熟练理解这些操作符的含义(都很简单) i.kqi{.  
& 2^O^8&  
2,NULL 值的特别处理 / Agj5  
-pQK\Hb  
这是一种不属于任何类型的值。它通常用来表示“没有数据”“数据未知”“数据缺失”“数据超出取值范围”“与本数据列无关”“与本数据列的其它值不同”等多种含义。在许多情况下,NULL 值是非常有用的。 f#j<>yHP.=  
我们的各种操作符是不能对NULL 值进行处理的,如果相对NULL 值进行查找,用的是 is null 或 is not null 来进行判断,举例如下: fi Q&4D  
select last_name,first_name,birth,state from president c F yaq7r  
where death is null; //找出所有没死的总统 !7/`!vGF  
在某些情况下,NULL 值是很有用的类型,大家慢慢就会理解的。 |U.||nB  
bWyl5U  
3,查询结果进行排序 lb2Spni@  
9ixs.h}{>  
一般说来,如果创建了一个数据表并向里面插入了一些记录,当发出一条select * from name命令的时候,数据记录在查询结果中的先后顺序通常与它们被插入时的先后顺序一样.这当然符合我们的思维习惯.但这只是一种"想当然"的假设而已,事实上,但记录被删除时,数据库中会产生一些空的区域,MYSQL会用新的记录来填补这些区域,也就是说,这个时候本假设就不正确了.因此我们必须记住一点,从服务器返回的记录行的先后顺序是没有任何保证的!如果想要按照一定的顺序,就必须使用order by 子句来设置这个顺序. q3OJ]v=`  
select last_name,first_name,birth,state from president Pj a|LaF/  
order by last_name; //让总统们的名字按字母顺序排列 o@cPIP<U  
还可以设置排列的升序降序 eLy"7(2c9  
select last_name,first_name from president `V;X!$  
order by state DESC,last_name ASC;  =eu))  
//先按照出生地的降序排列,同出生地的按照姓氏的升序排列 @+/4d v  
注意:如果结果中含有NULL 值,默认情况下他们总是出现在查询结果的开头。 @S_PB  
[<"b}[VHh,  
4,限制查询结果中数据行个数 [~Zx6`}5  
;+V, 6-  
这个简单,只要用limit 子句就可以了,看两个例子: =r}9O  
select last_name,first_name,birth,state from president cxiPQ*n^3  
order by birth limit 5;  //只想看前5个 Z~b#|kc   
order by birth limit 10,5; //返回从第11个记录开始的5个记录(跳过了10个) S$RXx]_  
小技巧:从president表中随机找出一个总统来玩: O)p0bSs0  
select last_name,first_name,birth,state from president d5ZcuX G#  
order by rand() limit 1; //这是用了表达式求值的方法,在哪里都管用 {\\il]@o\  
1 !2*O  
5,对输出列进行求值和命名 *3!@2)DZz  
Xg/{,6}  
为了提高效率,MYSQL还可以把表达式的计算结果当作输出列的值。表达式可以很简单,也可以很复杂。例如:下面这个查询有两个输出列,前一个输出列对应一个非常简单的表达式(一个常数),而后一个输出列则对应着一个使用了多个算术运算符和两个函数调用的复杂表达式。 O3Jl#*7  
Select 17,format(sqrt(3*3+4*4),0)) d~I .P)t  
输出:17 5 B|?Q3!D*_  
再看这个命令:把两个输出列合并成一个 e"EQ]wJ_  
select concat(first_namem,’ ‘,last_name),concat(city,’,’,state) from president; O^EW,u8  
如果合并之后输出列的标题过长,则可以给其一个别名,如: _]X^/t.~8=  
select concat(first_namem,’ ‘,last_name) as name, Ow%f\"tbk9  
concat(city,’,’,state) as birth place 9f?A.r]  
from president;这样就比较美观了。 'mW%O>AG$  
\9r'4 r  
6,和日期有关的问题 ^<2WTG$i  
-z>SXO ?`  
首先记住:在MYSQL中,年份是放到最前面的!我们通常对日期进行下列操作: L4 :/xs  
按日期进行排序 5my'u q`O  
查找某个日期或日期范围 lAaJeMQh  
提取日期中的年,元,日各个部分 8?=4 CDG  
计算两个日期的间隔 sj?&&U;}b  
用一个日期求出另外一个日期 Vp^"Qc  
看例子: >:L&D   
select * from event where date=’2002-10-01’ //看看这天有何考试信息? +'r7;|X6L;  
select last_name,first_name,birth,state from president S-\3[|7  
where death>’1900-01-01’ and death<’2000-01-01’; //看看上个世纪死了几个? 0r=A3/M/  
三个函数year,month,dayofmonth可以分别分离出日期中的年月日来。 u'0!4P  
select last_name,first_name,birth from president Jr [D1vg  
where month(birth)=3; //谁生在3月 ? r;xzrH  
where month(birth)=7 and dayofmonth(birth) =6; //谁生在7月6日?(汤姆克鲁斯?) }2pyU>o~  
函数to_days可以把日期转换为天数。 AUB3AD }wG  
select last_name,first_name,birth to_days(death)-to_days(birth) as age from president 0sT3 zGZ  
可以看看这帮家伙都活了多少天!你自己把它改为年吧。 L_f (iDY  
日期值的减法运算还能帮我们计算出现在距离某个特定日期还有多长的时间,这正是我们用来找到需要在近期内缴纳会费的会员的办法: TVuU`vw^  
select last_name,first_name,expiration from member UM 2W@  
where (to_days(expiration)-to_days(curdate())<60; //有些人60天内需要花钱了!

7,模式匹配 %@%DS)>P  
=i5 QSdZey  
有些情况下,模糊查询是很必要的,我们使用like和not like加上一个带通配符的字符串就可以了。共有两个通配符”_”(单个字符)和”&”(多个字符) YG h;v  
select concat(first_namem,’ ‘,last_name) as name, 'x*,  
where last_name like ‘W%’; //找到以W或w开头的人 qg5.g#C  
where last_name like ‘%W%’; //找到名字里面W或w开头的人 MJMTjSOk  
v7|pA 5  
8,设置和使用SQL变量 W\=,7 f  
zj0STX+4  
MYSQL 3.23.6以上的版本可以使用查询结果来设置变量,我们就能够方面的把一些结果保存起来以供他用。变量的命名规格是:@name, 赋值语法是 @name:=value ( pascal?) 使用起来也简单: WC],m  
select @birth:=birth from president a }U4bn  
where last_name =’adsltiger’;  //执行完成后我们就就会有一个@birth变量可用 /+ |UQv(  
用一下试试: "b^&8Q=*  
select concat(first_namem,’ ‘,last_name) as name from president 3V+% 8  
where birth<@birth order by birth; //看看那些人比我大! XA`y3I  
%qGC{L  
*9,生成统计信息 Lcu>x>Gj  
.z;>EH4  
单纯依靠手工来生成统计信息是一项既艰苦又耗时还容易出错的工作,如果我们能熟练掌握用数据库来生成各种统计信息的技巧,他就会成为很有威力的信息处理工具。作者在这里用了许多篇幅讲这个主题,为了便于大家理解,我分解开来论述: 4SH~yf\9&  
cDjV0LC  
9.1 找出一组数据中到底有多少种不同的值是一项比较常见的统计工作,而关键字distinct就可以把查询结果中的重复数据清除掉。如 q|>H.7?  
select distinct state from president  //看看美国总统们都来自那些州?(重复的不计) <W&GG}N'7  
3gvGf O  
9.2用count()函数来统计相关记录的个数,注意其使用方法:count(*)计算所有的,NULL也要;count(数据列名称) NULL值不计算在内。 }h|udBWO#  
select count(*) from president; *|0k0(C  
/t/9?  
9.3如果我们想知道班级内的男女生数目?该如何查询呢?最简单的方法是 v<sQz4M!>  
select count(*) from student where sex=’f’; 9vo)GMw[x`  
select count(*) from student where sex=’m w,^~9ZZ  
但是如果使用count函数结合group by关键字,一行命令就搞定了 a.@!@~  
select sex,count(*) f rom student group by sex; =;A''{\B  
[sceR5j|  
我们可以看到,与反复使用彼此类似的查询来分别统计某数据列不同取值出现次数的做法相比, 把count(*)和group by字句相结合使用有许多优点,主要表现在: S{iE&kd  
在开始统计自前,不必知道被统计的数据列里面有多少种不同的取值 0UuAgmfLv  
因为只用了一个查询命令,我们可以对输出做排序的处理 (e]) g\e  
select state,count(*) as count from president r_rhcy;vb  
group by state order by count desc limt4; //看看出生总统最多的前四个州是哪几个? ,wj[+7 v}  
G/9x#&  
9.4除了count(),我们还用其他一些统计函数,如求出最小值的min(),求最大值的max(),求和的sum(),求平均值的avg(),在实际工作中,这些函数时经常用到的! s<-W<Ebd  
t,Df\,eC  
*10,从多个表提取信息 5PZ4&0M  
N{bl-4*#  
我们目前的例子都是从一个表里面提取信息,但数据库的真正威力还在于用“关系”来综合多个数据表里面的记录,这种操作称之为“关联”或“结合”我们可以看到,select需要给出多个数据表里面的信息(不可重复);from需要知道从哪几个表里面做事;where则对几个表之间的关联信息作出详细的描述。 oXm3y  
首先我们要学习最可靠的数据列引用方式:数据表名.数据列名。这样在查询中就一定不会混淆这个数据列到底在哪一个表里。 ;*R2{R&i>  
W|&i*HSyl  
例子1:查询某一天内的学生们的考试成绩,用学号列出。 W6[ b  
select scroe.student_id,event_date,score.score.event.type D]djoS+f  
from event,score C'xhiOZK  
where event.date=’2003-09-12’ I=$sEk]G  
and event.event_id=score.event_id ,<"9'Tus  
首先,利用event数据表把日期映射到一个考试事件编号,在利用这个编号把score表内相匹配的考试分数找出来。关联两个表,一个查询搞定。 y 5 :Ih]  
n\D)h0W  
例子2:查询某一天内的学生们的考试成绩,用姓名列出。 qko r<1  
select student.name event.name,score.score,event.type -nCv/J g9  
form event,score,student p-'4,Cj  
where event.date=’2003-09-12’ {N tYVJ=  
and event.event_id= score.event_id 81pl$~  
and scroe.student_id=student.student_id; {sjAS`s F  
关联三个表,一个查询搞定。 @6i7[  
YoDFDQD>U  
例子3:查询一下缺席学生的名字,学号,缺席次数 I(k9L/jLa  
select student.student_id,student_name %(mN XQa  
count(absence.date) as absences p^.m5wW@  
from student,absence 'm])"9  
where student.student_id=absence.student_id  //关联条件 ~<r:9  
group by student.student_id; ELhQ>F:'  
m6<lJA  
简单的关联操作就介绍到这里。事实上,对于关联的知识我们需要学的很多很多,比如说,我们怀疑某一个数据表内不存在和我们相关的数据,把么在关联查询的时候如何处理这个表呢?这就涉及到内联接,外联接,左联接,右联接的许多新概念了。不知道大家还有没有信心向下看我的笔记?在本书第四章里面,对关联进行了十分详细的论述,看来“在SQL里面,干粗活的是select”的说法再对不过了。 4Nz6e  
 ! ~JM  
我们了解了select命令的如此之多的用法,感到了它的灵活性,许多字句的组合能够形成一个非常“精妙”的SQL语句,在基础没有打好之前,我等初学者目前还没有必要去钻研那些技巧性很高的东西,“一定程度的创造性是必要的,但太专业或充满技巧的代码则是各种 bug的发源地,同时也是若干个不眠之夜的前奏” pQ&(y^v,  
8#uia[{r>  
第一章  总结 ZR~H)7wB  
A-ojbsp  
78页的知识量还是比较大的,我们学会了MYSQL中最最基础的知识:创建数据库和数据表;对数据表里面的记录进行插入,检索,修改,删除等操作,并且对select语句的用法作了一些相对复杂的讲解,不知道各位好学的朋友有何感想。
Ox1}jx5b  
MYSQL数据库里面的数据 u/@}Bhc:9  
-jb[_kih  
    用想用好MYSQL,就必须透彻理解MYSQL是如何看待和处理数据的。本章主要讨论了两个问题:一是SQL所能处理的数据值的类型;二是这些数据类型在实际应用中需要注意的问题。 umz'^;27t  
$_RzG2 P_  
    首先我们看看mysql能够支持的数据类型,和其它的数据库一样,我们可以处理各种数值(整型,浮点),字符串型,日期/时间型,NULL值等等。大家在使用的需要注意不同类型的数值的格式是不一样的。在这里,对字符串的处理有一个比较特殊的地方大家需要理解。因为字符串两端是需要用引号(单引号,双引号)括起来的,但是如果字符串本身里面也包括了引号(单引号,双引号),我们应该怎么办呢。这时就必须用以下三种方法之一来标识这个特殊的字符串。 . rrY7u  
.LG g r]  
    1, 如果字符串内部的引号字符与字符串两端的引号字符相同,则双写该引号 1}y,fZEh  
!4tw+4>  
‘I can’’t’ /~]3shal<  
“He said,””I told you so, “”’ Y Xw+#i  
)dexW;~  
    2, 用与字符串内部的引号字符不同的引号把该字符串引起来,此时,就不用双写字符串内部的引号了 o$-NGRt  
p_@A{z  
“I can’t” >p}mj?  
‘He said,”I told you so,”’ #$kYbswC  
A&=+A!4e  
    3, 用反斜杠对字符串内部的引号字符进行转义,此时与字符串两端的引号无关 =3;x wJ+R  
Wz o# 8   
‘I can’t’ 7hS]gOKc  
“He said,”I told you so,”” [k$o#  
T w<JE$j-  
    下面我们看数据列类型,真的很奇怪,数据列里面放数据,两者类型不相同。事实上,把数据列类型叫做列类型也许更合适一些,数据类型只是一种含义广泛的分类方法,比如:数值,字符串等等。而列类型是对一个给定的数据列里面的值有哪些具体特点的准确描述。比如smallint或varchar(10)等。也就是说,数据列类型决定了mysql如何对待这些数据,你不能把abc放到一个数值列里面!如果你给你的数据找到一个合适的位置,下列问题时必须考虑的: ^j2p_J14pp  
V6vjyy;  
    需要把哪些种类的数值保存到数据表里面? >=8G} >%  
    这种类型的值要占用多少存储空间? TuxLK}  
    这种类型的值长度是否固定不变? I-.%&j#W:<  
    这种类型的值如何进行比较和排序? Ar&1gxo,  
    这种类型的值可以用null值吗? zD(j@#l6G  
    如何对这种类型的值进行索引呢?
5@ACC Z;  
 p%du&  
    当你对这些问题都能心中有数的时候,就可以选择具体的列类型了,当然,每一种列类型都有相应的特征表格大家可以查询。需要注意的是这几点: ,,7>1Z S%%  
n!)om\tpi  
    1,显示宽度 Uw? L '  
{gfm| FCLr  
    整数列的显示宽度与mysql需要用多少个字符来显示该列数值,与该整数需要的存储空间的大小都没有关系,比如,不管设定了显示宽度是多少个字符,bigint都要占用8个字节。 69 q[>d[  
Z45$Y  
    2,截短处理 &Ceo'W3=  
Cx&jju  
    数值类型列的取值范围是由它的具体类型决定的。如果想把一个超出列取值范围的值插入到各个列中,mysql会截短这个值,会先把这个值替换为该数据列取值范围的上限或下限,然后插入,这种截短仅与这个列的取值范围有关,与该列的显示宽度无关。比如说:把99999插入到一个类型为smallint(3)的数据列里面,就会被截短为32767 __ Ouy} H[  
;GVe'X  
    3,前导0的问题 ZK\%|`O.n  
;g3QLG;s  
    如果想让某列里面的值都能全部整齐的按所定义的显示宽度显示出来,就需要使用zerofill属性,就可以在数值前面加入不定数目的0来显示数值,这个功能有些情况下很有用。但有一点需要注意,如果一个数值长度大于定义的显示宽度,这个数值也会正常显示,此时不受显示宽度的限制。 ](X>yfB  
`kvU>rf   
    4,enum和set i^ ;|2 FI  
)M$5" _]6  
    需要记住,这两种数据列的列定义里面都要有一个列表,列表里面的元素就是该列的合法取值。如果你试图把一个不在这个列表里面数据放入本列,它就会被转换为空字符串! +lJmA\fi%=  
E)[q))Kr  
    5,日期和时间 (B2}}  
T%Lpz0$065  
    在许多情况下,希望能够在数据列里面创建一条记录的时候可以记录当时的日期和时间。还希望这个时间值不会因为以后的操作而改变,但令人遗憾的是,目前仍然没有一种mysql列类型能够直接满足这个需要,现在我们一般用两个办法来解决这个问题:  </id,&3  
DRoPbI't1  
    1,使用一个timestamp数据列,在需要创建一条新纪录的时候,把这个timestamp数据列设置为null.也就是把它初始化为当前的日期和实践. @BViY#Nr  
    Insert into table_name (ts_col,…) values (null,…); 0il;.&dH  
    在以后对这条纪录进行修改的时候,要用这个列里面的现有数据对它进行赋值.这种明确赋值的做法将抑制住mysql 的时间戳机制,让timestamp数据列里面的值不会自动改变. D\WluI`?7  
    Update table_name set ts_col=ts_col where … ?n_N%5`  
sA#N)_  
    2,使用一个datetime数据列,在需要创建一条新纪录的时候,用now() 函数来初始化这个数据列: V5sNn3f  
    insert into table_name (dt_col,…) values (now(),…); "Ye)`d#  
    以后对这条纪录进行修改的时候,不要碰这个数据列. [ ovz)]G  
    Update table_name set … anything but dt_col where … 8sn-KEjZS  
<vj]!q  
    6,关于年份的转换问题 v<dlL*7+$  
d9B{i9  
    如果你把一个两位数的年份值插入到一个year数据列里面, mysql 会自动地按照一下规则来进行转换: *? :82  
    年份值 00-69 转换为 2000-2069 %/T[ x'H  
    年份值 70-99 转换为 1970-1999 MX}7r(#q  
    需要注意的是00这个年份,如果你执行: oTFYU*,op  
    insert into table_name values (00)  其结果就会变成 0000 {P?y}- PB  
    因此,如果想使用一个没有世纪部分的值,结果得到2000年,就必须是用字符串格式 ’00’ 如果想让mysql 把一个向year 数据列插入的值看作字符串而不是数值,就应该用 concat()函数把这个值转化为字符串,无论输出参数是一个字符串还是一个数值, concat() 都会返回一个字符串. sKN&<K ?  
8 7>#lo3  
    7,序列和编号 8bE,hyv  
'lzUSJ|  
    作者之所以把序列和编号的问题单独拿出来讲解,是因为许多应用程序都需要一个独一无二的编号来把一条记录和其他的分别开来. N\) gOiI"  
s()w2 Vo  
    在mysql 里面,这种独一无二的编号是通过数据列的auto_increment 属性而自动生成一组序列编号的办法来实现的.需要我们首先知道的是, mysql目前支持多种数据表类型.不同的数据表类型对于auto_increment 属性的处理机制是不一样的!所以我们不仅需要掌握有关auto_increment 属性的基本知识,还需要熟悉这种机制在各种的数据表类型中的差异. m2[eE J  
&Pkng=t  
    Mysql 3.23以前的版本仅仅支持比较基础的ISAM 数据表类型,在后来的版本中,其他几种数据表类型也逐步加了进来.包括 MyISAM 和 HEAP 类型等等.现在我们使用mysql的时候默认建立的数据表都是比较先进的MyISAM类型.我们先看比较基础的IASM表类型是如何看待数据列的auto_increment 属性.? *^GuJl"Ie  
do%=5M9l  
    A 如果试图把一个null 值插入到一个auto_increment 数据列里面,Mysql会自动生成一个序列编号并插入, %klb8$w=&  
一般从1开始,依次递增 )= C#me=  
    B 不要把0插入auto_increment 数据列里面,我们不推荐这这样做. ;kA-%4}  
    C 如果在需要创建一条新纪录的时候,对auto_increment 数据列明确制定了一个数,会有两种情况存在:1,某个纪录已经使用了这个数,此时Mysql 会报告错误.2,如果没有纪录使用这个数,那么纪录正常插入,以后再插入的新纪录就会以这个编号+1开始!也就是说,我们可以人为地”跳过”一些编号,举例来说,如果插入一个”假”纪录,编号为999 那么以后的纪录就会从1000开始.然后我们就可以删除”假”纪录了.这是个简单的技巧. sw>fkOm\  
    D 如果删除了编号最大的纪录.再插入新纪录的时候仍然会使用这个编号!这是ISAM表本身的特点,也就是说,如果把数据表里面的纪录全部干掉的话,新纪录编号将从1开始 hQs'#L_l)  
    E last_insert_id() 函数能够返回编号序列中最后一个生成的编号.在某些情况下,我们可以利用这个函数取得当前数据表中最后一个生成的编号. ra._^>V3Qs  
=3 Gu#m  
    下面要说的是Mysql 里面的,目前大部分用户使用的 MyISAM表类型对auto_increment 数据属性的处理方法,可以看到,这种新的表类型有更大的灵活性,消除了原始的IASM标在处理序列和编号方面的许多缺陷!下面我们看: DN;" FQ  
    A 在MyIASM表里面,一个自动生成的序列编号将严格地依次递增,即使被删掉也不会被再次使用! s W=F^(8  
    B 可以在建立数据表的时候,使用 auto_increment=n 选项为序列编号明确地设定一个初始值 fmX lgpK  
    C 可以用alter table 随时改变MyISAM表中auto_increment的开始值,比如,下面这条命令会让序列编号从2000开始 GnK&'cD-  
1HCr=7bm  
    其他注意事项 rzNrn<:p  
=cZC/n7  
    1,Mysql 提供auto_increment的主要目的是生成一个正整数数据列,所以我们可以把该列声明为unsigned ,这样能够使用的编号范围就多了一倍 6z/%Wdsb  
    2, auto_increment 属性仍然受到具体的数据列的取值范围的限制,比如一个tinyint数据列,编号最大值也只能是127 `5ox)3S3l  
    3,清除一个表的全部内容会让序列从1开始重新生成. &z?R6f^y  
We)>} JQ  
    最后的问题 24+B#A~  
WkcQ| hR  
    当我们打算创建一个数据表的时候,面对这么多的数据列属性,如果做出正确的选择? :RpXw,G~  
;OUsz/O>E  
    A这个数据列将用来存放哪一种数据? &h0T  G  
YFLnem4:  
    这是我们第一个需要考虑的问题,一般说来,这个问题的答案似乎很直观:把数值放到数据列里面;把字符串放到字符串列里面;如果是整数就用整数列,如果有小数就用浮点类型。但是,事情往往不是这么简单,只有洞察有关数据的本质,才能明智地选择出最佳类型,有时候的结论往往是这样:最不适合人类阅读和理解的方案往往是最适合数据库的!这是不是很有趣,总之,对数据的全面把握才是选择数据列的关键所在。大家在学习过程中慢慢的体会这一点吧! m>W$C  
hj / JI  
    B数据值是否都在某个具体的范围内? Xp^Z 'FQY  
j/[]FP$h:  
    在第一章,我们为考试积分项目创建了一个名为score 的数据表,其中有一个用来记录考试和测验成绩的score 数据列,当时我们使用了int 类型,现在我们考虑到了对于考试来说,成绩一般都在0-100之间,因此我们用 tinyint unsigned 是不是更合适呢?但是如果有一种特殊情况,那就是校方会用-1来表示某个学生因病没有来考试,这时unsigned 就不行了 <!)WD$eg  
Ezk a3WRZo  
    C有没有性能和效率方面的问题? (VxbnBGnE  
I^ 6\x:  
    一般来说: 9QFAb  
    数值操作比字符串快 ; ]8Lg<:$f  
    近可能地使用enum类型,因为这种类型在MySQL内部是用数值表示的,速度较快! v9Yrd)d^  
    小类型的处理速度比大类型快 DaXob$k  
hAn'.v/}  
    D打算如何对有关数据进行比较? {W(mX*{  
    E是否要在某个数据列商建立索引?
pza\02WbP  
jKv$y  
    这两个问题往往看似简单,但对于比较特殊的应用来说值得相当关注! \r5[`8Q  
ejwM{  
    有关数据类型转换的问题 *#z` jt_HS  
Q1 *bW*=  
    这个问题是很重要的!尤其对于那些用来删改数据记录的delete和update语句,必须确保这些语句只能施加在想对之进行操作的那些记录上!举例来说,假设某个数据表中有这么一个char数据列 a3\SdIZCJ-  
‘abc’ F?6+:o-  
‘def’ S!D-jRcA  
‘00’ ?kyK7 Q0$A  
‘jk0’ E~`zb^}  
    看这个命令 delete from table_name where char=00 D_')0L>P  
    我们的本意可能是想把包含有00那条记录删掉,可实际上本命令执行之后会把所有的记录全部赶掉!原因就在于MySQL把00当作了一个数值(字符串和数值比较时,比较操作将把他的两个操作数都当作数值来看待,这种情况下,所有的字符串都不可避免的变成了0) X}qLNrEgz  
&5}F;LY  
    所以我们在执行delete语句之前一定要先用select 检查一下 where 带来的结论。 ;/%s ($jJ{  
k&>=Hzav:  
+kg+x  
    下面是最常见的类型转换功能,大家好好学学 '(;Od$0t  
    1) 把数据加上一个0或0.0 能把它强制转换为数值型 weHGB"  
    2) floor函数会把浮点数强制转换为整数 upr#}AmrT  
    3) 给一个整数加上一个0.0会强制转换为浮点数 aP#lN}t_  
    4) concat函数能把任何类型强制转换为字符串 L1C%j2k  
    5) hex函数能把字符串强制转换为十六进制数 2oyfP'ACH  
    6) ascii函数能把字符转换为ascii码 ?RNZb~(xq  
    7) data_add函数能够把字符串或者数值转换为日期和时间值 w)]Hi0T4T%  
    8) 给日期和时间值加上一个0,可以强制转换为数值
VWo7b# (  
第三章,MySQL的语法及其使用 4~[w^n"<  
G0L)pB(]5  
先看看MySQL支持的SQL语句的分类  Pz(Fe  
1, 数据库的选取,创建,丢弃和变更 )%!YYnd  
use })R"ztvA:  
create database dS"s@2M  
drap database [O.95!G  
alter database i ,+,psO  
2, 数据表和索引的创建,变更和丢弃 .`w:PS5  
create table L HTi\s-w  
drop table /cH!6gnZ!'  
create index 1ONr=7P  
drop index _d1^p}C7%  
alter index 9-aF+s-#l  
3, 从数据表检索信息 !^I T9  
select g%&1 LelC  
union "(>eWWisA  
4, 事务处理 xxv/A'Rw  
begin m@ f{/\O  
commit Pl0BW)mF  
rollback N;:mkWgX  
set autocommit v%RU&=,_=  
5, 对数据表里面的信息进行修改 V0s\  
delete lz=\]@M  
insert bZI-Xx$0)  
load data O: ]$tj  
replace a 7A~Bm  
update 4]#>Hj5;  
6, 管理型命令 `7q3_%;r  
flush q`^KDBz)  
grant .4:!bQcfk  
revoke OK>[6$7  
a!U?3W   
一,命名规则 u B;8(9>  
IVdw<^ t8=  
1MySQL允许用在名字中的系统字符. +iPri6f{  
任何字母数字加上”_” 或 “$” 3]}o'23  
2名字的长度. udE?0oN\  
数据库,数据表,数据列,索引等名字最多64个字母 /#NGmP.*"  
256别名最多256个字母 $aZ yMZ"6  
3名字的限定符 hzn[ #\  
依据不同的上下文,有时需要给某些名字加上某个限制:如数据列的全限定,部分限定,以及无限制.这一点比较容易理解 tK9?  
select * from db_name.tbl_name… _ Z<!WX  
I2)tOUZW)  
二,MySQL中的大小写问题 zuW##7X>@  
YF;n#+M  
关键字和函数名:不区别 zy`io0l  
数据库名数据表名:根据服务器主机系统而定 zKLFG'du +  
数据列名索引名:不区别 g'Xk{m0Is  
别名:区别大小写 7rzY%/a^V  
一般来说,不管系统是否区分数据库名和数据表名中的字母大小写情况,我们都应该在同一个查询语句里面以前后一致的字母大小写形式来写出这些名字,这是一个非常好的编程习惯。 F~f?([j}  
iL,^"H9FCC  
三,MySQL支持的名种数据表类型详解 k5h#yH*   
n&1kT,x.hB  
1,ISAM数据表 Mi^XoE/  
这是3.23版本之前的MySQL支特的唯一一种表类型,目前己经过时,MyIASM处理程库逐步取代了ISAM处理程序,这种老式的表类型己经没有人在用了 'Q[2b?:~u  
.th89#"m  
2,MyIASM数据表 vJgRDfmDOx  
•        这是目前中MySQL默认使用的数据表类型。其优点是 .TUeB\ O21  
•        如果主机操作系统支持大尺寸文件,数据表长度就能够很大,就能客纳更多的数据. \3&6/"`  
•        数据表内容独立于硬件也就是说可以把数据表在机器之间随意拷贝 '_GbXaK\  
•        提高了索引方面的功能 Ng8* zzv'F  
•        提供了更好的索引键压缩效果 Q ?!xBg%Y  
•        auto_incremnet能力加强 -(4C 9N8/  
•        改进了对数据表的完整性检查机制 4/w$<u/  
•        支持进行fulltext全文本搜索 9btZns^E a  
x-|`0Dmx  
3,Merge数据表 cr|MV!<[  
这是一种把相同结构的MyIASM数据表组织为一个逻辑单元的方法 aL>vLV!0  
4,HEAP数据表 e9w)_.*U  
这是一种使用内存的数据表,而且各个数据行的长度固定,这两个特性使得这种类型数据表的检索速度非常快,作为一种临时性的数据表,HEAP在某些特定情况下很有用。 qD~!9-%!  
5,BDB数据表 `cH,ON w;  
这种数据表支持事务处理机制 m[* Gg]w}  
具有良好的并发性能 0k`*;JfJ:  
6,InnoBDB数据表 5T7W+"8L  
这是最近加入MySQL的数据表类型,有许多新的特性 a*"qecm+A:  
支持事务处理机制 Z:deQR;  
崩溃后能够立刻恢复 ;e!$xi .m  
支持外键功能,包括级联删除 RV7~q")g  
具有并发功能 C_heA3'  
7这种数据表在硬盘上的文件存储方式 6i0hB|JW;  
IASM        Frm isd ism ]Tzcn 4WC  
MyISAM        Frm myd myi KgfO q_  
Merge        Frm mrg ri6' i.L  
Heap        Frm nwOg_w\  
BDB        Frm db oi$ !b0,;  
InnoBDB        frm =NU;9 /)  
8数据表的可移植性 2V:k#K7  
通用方法:吧数据表的内容导出到一个文本文件中,然后拷贝到目的地硬盘上,在用脚本加载到数据库里面,这是首先我们应该掌握的方法。但就文件层次的操作来说,某些数据表是可以单独拷贝的。看表了 T NV(__U  
ISAM        No TE_=&-m @  
MyIASM        Yes Vwl4Y J1  
BDB        No t< ]L8O*W<  
InnoBDB        Yes `@$d7Nm%  
XPtNtF(P!  
四,索引的初步知识 XNmG1"jZ  
1,索引是加快数据表内容访问性能的基本手段,其基本特性: c3Z*h  
为可以索引单独的数据列也可以构造包含多个数据列的复合索引 _okvhLwCd  
索引可以包含重复键值 [e1hj659W  
可以为一个数据表建立多个索引 Sh>b0pAoI  
2,不同的数据表有着不同的索引特性使用的时候需要区别对待 ,|T{?q~WP  
3,如何创建索引 !oe 2d{O  
①用alter table命令创建索引 u !UL  
②用create index 命令创建索引 Qr b#F6  
③在create table 时创建索引 |n\.k3Vm|  
'?Gh$4<y  
五,变更数据表的结构 8V7 eeSe?  
当发现某个数据表的结构己经不能满足我们的使用要求时,就要对其结构进行变更.可能需要这个数据表存放比以前更多的信息;也可能是这个数据表里面的某些信息己经没用;了或许是现有的某个数据列宽度太窄…在这些情况下都要用到alter 语匀 Aa=vIIV  
1,重新命名数据表 C ;nd 0B  
alter table A rename to B  //数据表A改名为B obl(cA  
rename table A to B                //数据表A改名为B ]jD{2e)  
rename A toC,B to A,C to A    //数据表A和数据表B互换名字 VcTc Z Zx  
alter table S.A rename to T.A                //数据库S里面的表A移动到数据库B里面 /yYG/DD  
rename table S.A to T.A   //数据库S里面的表A移动到数据库B里面 M8Oo@y]  
2,改变数据列的类型 Bjb @0,87  
我们现在要把数据表A里面的一个smallint unsigned类型的数据列I再次改动为 mediumint unsigned 类型 BD4ztcT5  
alter table A motify I mediumint unsigned P[mOYo  
alter table A change I I mediumint unsigned 3#x(ylY8  
注意change子句的特点:不仅能够改变数据列的类型,还能改变数据列的名字。这是modify子句所不能完成的。下面就把这个数据列改名了。 i12oXs] Ke  
alter table A change I J mediumint unsigned +;27|\  
3,将数据表由可变长度数据行转变成固定长度数据行 &tOXX &j  
有的时候为了提高性能,需要做这样的转变,但有一点需要注意:必须用同一条alter命令来一次改变所有的数据列,不能仅仅改变一个数据列!举例如下: Shh zt5  
create table A(name varchar(40),address varchar(80)) NTRAI5  
我们开始修改命令就应该是: ":$4#!Sie  
alter table A modify name char(40),modify address char(80); 443ja |  
4,将数据表由固定长度数据行转变成可变长度数据行 "X_R q+Er  
如果觉得空间利用率不高,那就需要再转变回来,这个就很简单了,没有特别要求 ~nGT+Kp-  
alter table A modify name varchar(40) VY93q6L  
5,转换数据表类型 a?(UrrZ  
我们知道,MySQL数据库存在多种数据表类型,但每一种类型的特性并不相同。 {t43?Enh4  
如果你想让你的数据表支持事务处理机制。那就必须把它搞成BDB或innoBDB格式 tDP sRDaJ  
alter table A type= BDB _"b`@O1,-  
alter table A type= InnoBDB

MySQL里面的子选择 c'RsNbp  
一,子选择基本用法 +:S~Q=f  
1,子选择的定义 .~,fMVD  
子迭择允许把一个查询嵌套在另一个查询当中。比如说:一个考试记分项目把考试事件分为考试(T)和测验(Q)两种情形。下面这个查询就能只找出学生们的考试成绩 ^l&~y+~2  
select * from score where event_id in (select event_id from event where type=’T’); 1HL<-  
2,子选择的用法(3种) !(E\Z0d4  
        用子选择来生成一个参考值 0Dw}5<+n'  
在这种情况下,用内层的查询语句来检索出一个数据值,然后把这个数据值用在外层查询语句的比较操作中。比如说,如果要查询表中学生们在某一天的测验成绩,就应该使用一个内层查询先找到这一天的测验的事件号,然后在外层查询语句中用这个事件号在成绩表里面找到学生们的分数记录。具体语句为: :nfyf_n  
select * from score where $2U2j%,xu@  
id=(select event_id from event where date=’2002-03-21’ and type=’Q’); G{=h% Y5v1  
需要注意的是:在应用这种内层查询的结果主要是用来进行比较操作的分法时,内层查询应该只有一个输出结果才对。看例子,如果想知道哪个美国总统的生日最小,构造下列查询 X*.R[  
select * from president where birth=min(birth) IU79e*Htk  
这个查询是错的!因为MySQL不允许在子句里面使用统计函数!min()函数应该有一个确定的参数才能工作!所以我们改用子选择: Ny%;01P2a0  
select * from president where birht=(select min(birth) from presidnet); \u#JSA=RB  
        exists 和 not exists 子选择 WhnQ7Rh>B  
上一种用法是把查间结果由内层传向外层、本类用法则相反,把外层查询的结果传递给内层。看外部查询的结果是否满足内部查间的匹配径件。这种“由外到内”的子迭择用法非常适合用来检索某个数据表在另外一个数据表里面有设有匹配的记录 5PD:j@8  
E im44t l  
数据表t1                                        数据表t2 3'"p= :ls  
I1        C1                I2        C2 mGG'8  
1 p(T:>H  
2 FyC|7&NT  
3        A ]4g|0jL   
B N7'fyOr+  
C                2 fi M7m_I'V  
3 .8FlZP AJ  
4        C Tx ,9  
B bncGjh^q  
A j3| q~Oa{  
先找两个表内都存在的数据 qh3#G<  
select i1 from t1 where exists(select * from t2 where t1.i1=t2.i2); Q]5mEo|y?=  
再找t1表内存在,t2表内不存在的数据 p)Cx)  
select i1 form t1 where not exists(select * from t2 where t1.i1=t2.i2); &70iN<-)k  
=b gk~VW  
需要注意:在这两种形式的子选择里,内层查询中的星号代表的是外层查询的输出结果。内层查询没有必要列出有关数据列的名字,田为内层查询关心的是外层查询的结果有多少行。希望大家能够理解这一点 NOca lrW  
        in 和not in 子选择 Yg%bYY_  
在这种子选择里面,内层查询语句应该仅仅返回一个数据列,这个数据列里的值将由外层查询语句中的比较操作来进行求值。还是以上题为例 |fOW>  
先找两个表内都存在的数据 E05xd!p  
select i1 from t1 where i1 in (select i2 from t2); ItAJ\_}@  
再找t1表内存在,t2表内不存在的数据 17O4w*7  
select i1 form t1 where i1 not in (select i2 from t2); w[)eIqd3  
好象这种语句更容易让人理解,再来个例子 2_; tn]c  
比如你想找到所有居住在A和B的学生。 4,"{08T  
select * from student where state in(‘A’,’B’) fD7`N @y  
二,        把子选择查询改写为关联查询的方法。 {0;R 9lgxE  
1,匹配型子选择查询的改写 x$+&IhI.&  
下例从score数据表里面把学生们在考试事件(T)中的成绩(不包括测验成绩!)查询出来。  wq*yOm}  
Select * from score where event_id in (select event_id from event where type=’T’); q M$I Y  
可见,内层查询找出所有的考试事件,外层查询再利用这些考试事件搞到学生们的成绩。 ]++Q=3  
这个子查询可以被改写为一个简单的关联查询: G#w!BR  
Select score.* from score, event where score.event_id=event.event_id and event.event_id=’T’; b$GZU)V0^.  
下例可以用来找出所有女学生的成绩。 c WF])"~FW  
Select * from score where student_id in (select student_id form student where sex = ‘f’); -69%C,  
可以把它转换成一个如下所示的关联查询: KgQSE  
Select * from score ?&.AyK4l  
Where student _id =student.student_id and student.sex =’f’;  NM x#  
把匹配型子选择查询改写为一个关联查询是有规律可循的。下面这种形式的子选择查询: [:3[[elZ  
Select * from tablel iee7zv[z  
Where column1 in (select column2a from table2 where column2b = value); FNe,&j  
可以转换为一个如下所示的关联查询: x4:UG30#!  
Select tablel. * from tablel,table2 &eS\{]sn1  
Where table.column1 = table2.column2a and table2.column2b = value; "= 1` b  
(2)非匹配(即缺失)型子选择查询的改写 lAKF FD/}  
子选择查询的另一种常见用途是查找在某个数据表里有、但在另一个数据表里却没有的东西。正如前面看到的那样,这种“在某个数据表里有、在另一个数据表里没有”的说法通常都暗示着可以用一个left join 来解决这个问题。请看下面这个子选择查询,它可以把没有出现在absence数据表里的学生(也就是那些从未缺过勤的学生)给查出来: f-dx  
Select * from student uF4r9b  
Where student_id not in (select student_id from absence); fq5pg,!  
这个子选择查询可以改写如下所示的left join 查询: ?L zl z(  
Select student. * Aq,u#r %"8  
From student left join absence on student.student_id =absence.student_id G]\)X{J=o  
Where absence.student_id is null; Au8>n#}\  
把非匹配型子选择查询改写为关联查询是有规律可循的。下面这种形式的子选择查询: =^lE2W -  
Select * from tablel /0jo1I\g  
Where column1 not in (select column2 from table2); 5@8P_v 5  
可以转换为一个如下所示的关联查询: k1`7fP3K  
Select tablel . * |<jSz'  
From tablel left join table2 on tablel.column1=table2.column2 t +nVX y<  
Where table2.column2 is null; r=}[Ua\j  
注意:这种改写要求数据列table2.column2声明为not null。
0\o;*Vdg-  


类别: 无分类 |  评论(4) |  浏览(4192) |  收藏
一共有 4 条评论
2007-08-20 11:43 Says:
除湿器家用除湿机工业除湿机去湿机除湿机抽湿机智力抢答器竞赛抢答器 氧气机制氧机网络摄像机无线网络摄像机擦鞋机自动擦鞋机鞋套机自动鞋套机抢答器 表决器 滚动光栅 独轮车 杂技独轮车 鞋套 一次性鞋套喊话器 扩音器 扩音机皮鞋美容机 修鞋机 计数器 手握计数器计时牌 累时器 电子计时牌 倒计时器 定时器 驱鼠器电子驱鼠器超声波驱鼠器灭鼠器电子灭鼠器电子猫抢答器除湿机抽湿机磁铁
发表评论
看不清楚,换一张