|
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 数据表(一个或多个) jj9Ens where 满足的条件 i4J?0F&M _
XvD#LZ select语句有几个子句,他们的各种搭配能帮你查出最感兴趣的信息,这些子句可以很简单,也可以很复杂,看看作者是如何详细讲解的 {
N%GTD }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 来进行判断,举例如下: fiQ&4D
select last_name,first_name,birth,state from president cF 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 Pja|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^E W,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'uq`O 查找某个日期或日期范围 lAaJeMQh 提取日期中的年,元,日各个部分 8?=4CDG 计算两个日期的间隔 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=A 3/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 日期值的减法运算还能帮我们计算出现在距离某个特定日期还有多长的时间,这正是我们用来找到需要在近期内缴纳会费的会员的办法: TV uU`vw^
select last_name,first_name,expiration from member UM
2W@ where (to_days(expiration)-to_days(curdate())<60; //有些人60天内需要花钱了! 7,模式匹配 %@ %DS)>P =i5QSdZey 有些情况下,模糊查询是很必要的,我们使用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开头的人 MJMTjS Ok 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{i E&kd 在开始统计自前,不必知道被统计的数据列里面有多少种不同的取值 0UuAgmfLv 因为只用了一个查询命令,我们可以对输出做排序的处理 (e]) g\e select state,count(*) as count from president r_rhcy;vb group by state order by count desc limt4; //看看出生总统最多的前四个州是哪几个? ,wj[+7v} 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:查询某一天内的学生们的考试成绩,用姓名列出。 qkor<1 select student.name event.name,score.score,event.type -nCv/Jg9 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 %(mNXQa 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^
;|2FI )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-K EjZS < |