统计在线人数...

SQL进阶

[ 来源:ASP教程 | 作者:Admin | 时间:2003-7-8 9:33:41 | 浏览:统计中... ]


在我们完成我们的Internet笑话数据库网站的例子的过程中,我们已经研究了许多结构化查询语言(SQL)的大部分问题。从一个CREATE TABLE查询的基本格式,到INSERT查询的两种语法,你现在也许还知道很多这样的命令。
在这一周中,我们将会学习一些新的我们以前没看到过的SQL的技巧,有些是因为的确很先进,也有些仅仅是因为“以前没接触过”。作为其中的典型情况,绝大部分是对我们已经了解的知识的扩充。让我们先从最复杂也是最容易让人搞糊涂的SQL命令:SELECT查询开始。
对SELECT的结果集进行排序
一个信息的长的列表如果能按一定的顺序排列,肯定能给我们带来方便。例如,如果在我们的数据库中有很多注册的作者,要从我们的Authors表的清单中找到某一个作者肯定是一件比较困难的事。虽然它首先会按数据库中插入的顺序排列(最老的记录在最前面,最新的记录在最后面),但是你很快会注意到如果有记录被删除将会打乱这种顺序。
这意味着从最初的SELECT查询得到的结果集的排列顺序并不是让人信赖的。幸运的是,对于SELECT查询有一个可选项可以让我们根据指定的列对我们的结果集进行排序。以打印出我们的Authors表中的记录的清单为例。我们可以回忆一下,这个表共有三个列:ID、Name和eMail。因为ID列没有什么实际意义(它仅仅提供了与Jokes表中的作者的一个关联),我们通常只需要列出剩下的两个列。下面是作者数据表的一个清单:
mysql> SELECT Name, eMail FROM Authors;


正如你看到的,这些记录并没有按什么顺序排列。对于一个短的清单这也许没什么关系,但是如果我们是从一个很长的作者清单(也许是几百个)中寻找一个指定的作者(例如是Amy Mathieson)的email地址,能够让作者的姓名按字母顺序排列肯定会对我们有帮助。你可以这样做:
mysql> SELECT Name, eMail FROM Authors ORDER BY Name;


现在记录是按作者姓名的字母顺序排列的。就象我们可以在SELECT语句中增加一个WHERE子句以过滤结果集一样,我们也可以增加一个ORDER BY子句使得结果集按指定列排序。
在排序的列后面增加DESC关键字,你可以以降序排列这些记录:
mysql> SELECT Name, eMail FROM Authors ORDER BY Name DESC;


你还可以在ORDER BY子句中使用以逗号分隔的一组列名,以使得记录首先按第一个列排序,对于一个列相同的再按第二个列排序。在ORDER BY子句中列出的任意列都可以使用DESC关键字来颠倒排列顺序。
设置LIMIT
我们经常是工作在一个很大的数据表中,但是往往我们只对其中的几条记录感兴趣。假如你是想要统计你的站点中的不同的笑话的受欢迎程序。你可以向你的Jokes表中增加一个名为TimesViewed的列。对于一个新笑话,它的初始值设为零,而这个笑话每被显示一次,就将这个值加一,这样你就可以对你的数据库中的每一个笑话被阅读的次数进行记数。
对于指定ID的笑话的TimesViewed列加一的PHP脚本如下:
$sql = "UPDATE Jokes SET TimesViewed=TimesViewed+1 ".
"WHERE ID=$id";
if (!mysql_query($sql)) {
echo("<P>Error adding to times viewed ".
"for this joke!</P> ");
}

利用这个"笑话显示计数",你可以在你的站点的首页设置"最受欢迎的10个笑话"。使用ORDER BY TimesViewed DESC可以将笑话按TimesViewed从高到低排列,我们仅仅需要取出其中的前十名就行了。但是如果在我们的数据库中有数千个笑话,得到全部的列表可能是相当浪费处理时间的以及服务器的系统资源(例如内存和CPU的负载)的,因为实际上我们只需要其中的十个。
使用一个LIMIT子句,我们可以指定返回的结果的数目。在我们的这个例子中,我们只需要最先的十个:
$sql = "SELECT * FROM Jokes ORDER BY TimesViewed DESC LIMIT 10";
你也可以不用DESC从而得到最不受欢迎的十个笑话。
通常,你如果想要让用户查看一个很长的记录清单(也就是一个搜索的结果集),你一次只想为他显示其中的几个。想想你上次使用搜索引擎寻找网站时,你就可以发现这种做法。你可以使用一个LIMIT子句指定清单显示的开始位置及最大数目来达到这种目的,例如,下面的查询会显示数据库中第21到25个最受欢迎的笑话:
$sql = "SELECT * FROM Jokes ORDER BY TimesViewed DESC LIMIT 20, 5";
记住,结果集中第一个记录的记录号是0。这样,第21个记录的记录号就是20。
对表进行锁定
现在请注意,在上面的UPDATE查询中,我们将TimesViewed的值加一以代替原来的值。
$sql = "UPDATE Jokes SET TimesViewed=TimesViewed+1 WHERE ID=$id";
如果你不知道可以这样做,你可能会先做一个SELECT来获取当前的值,将其加一,然后用一个UPDATE将计算出来的值取代原来的值。除了这样做会用到两次查询,从而耗费两倍的时间以外,这种方法还带来了一个危险。如果在你对这个新的值进行计算时,另一个人又查看了同一个笑话,你想想会发生什么情况?PHP脚本会为新的请求运行第二次。当它执行SELECT获取TimesViewed的"当前值"时,它会获得与第一次执行时一样的值,因为这个值还没有被更改。于是虽然程序被执行了两次,但是这个值只会被加一。看看发生了什么?两个用户查看了这个笑话,但是TimesViewed只是被加了一次!
在有些情况下,这种获取-计算-更改的过程是不可避免的,我们必须处理对于同时发生的两个请求可能会造成的冲突(就象我们前面所看到那样)。另外一种情况是我们有时必须针对同一项事务同时更改几个表(例如,在一个电子商务的网站,我们必须针对一项销售同时更改存货和销售表)。许多高级的数据库服务(例如Oracle、MS SQL Server等等)支持一种叫做"事务"的特征,这样我们可以将复杂的操作定义为必须同时执行,中间不会被中断。而目前MySQL还不支持事务,但是它有另一种解决方案!
在执行一个多重查询的操作时,通过对一个表或几个表进行"锁定",你就可以获得唯一的访问以避免在操作过程中其它同时发生的操作可能造成的破坏。锁定一个表的语法相当简单:
LOCK TABLES tblName {

[1] [2] [3]  下一页

共有0人参与评价,平均得分:0分
评论内容只代表网友观点,与本站立场无关! 查看完整内容
   

广告位

当前在线人数
QQ:748838 MSN:allen_xia#msn.com E-mail:allenxia666#126.com QQ群:站长联盟北方区-北京(28200145) 站长联盟南方区-上海(67713522)