﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-叶明的javablog-随笔分类-ASP技术知识</title><link>http://www.blogjava.net/guming123416/category/7714.html</link><description>java学习天堂,个人关于JAVA的论坛bbs.javaworker.cn,欢迎大家访问</description><language>zh-cn</language><lastBuildDate>Wed, 29 Aug 2007 01:31:49 GMT</lastBuildDate><pubDate>Wed, 29 Aug 2007 01:31:49 GMT</pubDate><ttl>60</ttl><item><title>手把手教你制作Google Sitemap(详细制作教程和协议讲解)</title><link>http://www.blogjava.net/guming123416/archive/2007/08/28/140579.html</link><dc:creator>lovajava_ye</dc:creator><author>lovajava_ye</author><pubDate>Tue, 28 Aug 2007 08:36:00 GMT</pubDate><guid>http://www.blogjava.net/guming123416/archive/2007/08/28/140579.html</guid><wfw:comment>http://www.blogjava.net/guming123416/comments/140579.html</wfw:comment><comments>http://www.blogjava.net/guming123416/archive/2007/08/28/140579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guming123416/comments/commentRss/140579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guming123416/services/trackbacks/140579.html</trackback:ping><description><![CDATA[<p style="TEXT-INDENT: 2em">Google SiteMap Protocol是Google自己推出的一种站点地图协议，此协议文件基于早期的robots.txt文件协议，并有所升级。在Google官方指南中指出加入了Google SiteMap文件的网站将更有利于Google网页爬行机器人的爬行索引，这样将提高索引网站内容的效率和准确度。文件协议应用了简单的XML格式，一共用到6个标签，其中关键标签包括链接地址、更新时间、更新频率和索引优先权。</p>
Google SiteMap文件生成后格式如下： <xmp><urlset xmlns="http://www.google.com/schemas/sitemap
/0.84">
<url>
<loc>http://duduwolf.winzheng.com</loc>
<lastmod>2005-06-03T04:20-08:00</lastmod>
<changefreq>always</changefreq>
<priority>1.0</priority>
</url>
<url>
<loc>http://duduwolf.winzheng.com/post/140.html</loc>
<lastmod>2005-06-02T20:20:36Z</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
</urlset>
</xmp>XML标签
<ul>
    <li>changefreq:页面内容更新频率。
    <li>lastmod:页面最后修改时间
    <li>loc:页面永久链接地址
    <li>priority:相对于其他页面的优先权
    <li>url:相对于前4个标签的父标签
    <li>urlset:相对于前5个标签的父标签 </li>
</ul>
我将一句一句分解讲解这个xml文件的每一个标签：
<ol>
    <li>&lt;urlset xmlns="http://www.google.com/schemas/sitemap/0.84"&gt;<br>这一行定义了此xml文件的命名空间，相当于网页文件中的&lt;html&gt;标签一样的作用。
    <li><xmp><url></xmp>这是具体某一个链接的定义入口，你所希望展示在SiteMap文件中的每一个链接都要用&lt;url&gt;和&lt;/url&gt;包含在里面，这是必须的。
    <li><xmp><loc>http://duduwolf.winzheng.com</loc></xmp>用&lt;loc&gt;描述出具体的链接地址，这里需要注意的是链接地址中的一些特殊字符必须转换为XML(HTML)定义的转义字符，如下表：
    <table cellSpacing=0 cellPadding=2 border=1>
        <tbody>
            <tr>
                <th colSpan=2 rowSpan=2>字符</th>
                <th colSpan=2>转义后的字符</th>
            </tr>
            <tr>
                <th>HTML字符</th>
                <th>字符编码</th>
            </tr>
            <tr>
                <td noWrap width=125>and(和)</td>
                <td width=125>&amp;</td>
                <td width=75>&amp;amp;</td>
                <td width=75>&#38;</td>
            </tr>
            <tr>
                <td noWrap width=125>单引号</td>
                <td width=125>&amp;apos;</td>
                <td width=75>&amp;apos;</td>
                <td width=75>&#39;</td>
            </tr>
            <tr>
                <td noWrap width=125>双引号</td>
                <td width=125>"</td>
                <td width=75>&amp;quot;</td>
                <td width=75>&#34;</td>
            </tr>
            <tr>
                <td noWrap width=125>大于号</td>
                <td width=125>&gt;</td>
                <td width=75>&amp;gt;</td>
                <td width=75>&#62;</td>
            </tr>
            <tr>
                <td noWrap width=125>小于号</td>
                <td width=125>&lt;</td>
                <td width=75>&amp;lt;</td>
                <td width=75>&#60;</td>
            </tr>
        </tbody>
    </table>
    <li><xmp><lastmod>2005-06-03T04:20:32-08:00</lastmod></xmp>&lt;lastmod&gt;是用来指定该链接的最后更新时间，这个很重要。Google的机器人会在索引此链接前先和上次索引记录的最后更新时间进行比较，如果时间一样就会跳过不再索引。所以如果你的链接内容基于上次Google索引时的内容有所改变，应该更新该时间，让Google下次索引时会重新对该链接内容进行分析和提取关键字。这里必须用<a title="ISO 8601时间格式详细说明" href="http://www.w3.org/TR/NOTE-datetime"><u><font color=#0000ff>ISO 8601</font></u></a>中指定的时间格式进行描述，格式化的时间格式如下：
    <ul style="LIST-STYLE-TYPE: disc">
        <li>年：YYYY(2005)
        <li>年和月：YYYY-MM(2005-06)
        <li>年月日：YYYY-MM-DD(2005-06-04)
        <li>年月日小时分钟：YYYY-MM-DDThh:mmTZD(2005-06-04T10:37+08:00)
        <li>年月日小时分钟秒：YYYY-MM-DDThh:mmTZD(2005-06-04T10:37:30+08:00) </li>
    </ul>
    这里需注意的是TZD，TZD指定就是本地时间区域标记，像中国就是+08:00了
    <li><xmp><changefreq>always</changefreq></xmp>用这个标签告诉Google此链接可能会出现的更新频率，比如首页肯定就要用always(经常)，而对于很久前的链接或者不再更新内容的链接就可以用yearly(每年)。这里可以用来描述的单词共这几个："always", "hourly", "daily", "weekly", "monthly", "yearly"，具体含义我就不用解释了吧，光看单词的意思就明白了。
    <li><xmp>
    <priority>1.0</priority>
    </xmp>&lt;priority&gt;是用来指定此链接相对于其他链接的优先权比值，此值定于0.0 - 1.0之间
    <li>还有&lt;/url&gt;和&lt;/urlset&gt;，这两个就是来关闭xml标签的，这和HTML中的&lt;/body&gt;和&lt;/html&gt;是一个道理
    <li><strong>另外需要注意的是</strong>，这个xml文件必须是utf-8的编码格式，不管你是手动生成还是通过代码生成，建议最好检查一下xml文件是否是utf-8编码，最简单的方法就是用记事本打开xml然后另存为时选择编码(或转换器)为UTF-8。 </li>
</ol>
<img src ="http://www.blogjava.net/guming123416/aggbug/140579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guming123416/" target="_blank">lovajava_ye</a> 2007-08-28 16:36 <a href="http://www.blogjava.net/guming123416/archive/2007/08/28/140579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>破译天书！正则表达式学习心得体会</title><link>http://www.blogjava.net/guming123416/archive/2006/02/22/31919.html</link><dc:creator>lovajava_ye</dc:creator><author>lovajava_ye</author><pubDate>Wed, 22 Feb 2006 02:30:00 GMT</pubDate><guid>http://www.blogjava.net/guming123416/archive/2006/02/22/31919.html</guid><wfw:comment>http://www.blogjava.net/guming123416/comments/31919.html</wfw:comment><comments>http://www.blogjava.net/guming123416/archive/2006/02/22/31919.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guming123416/comments/commentRss/31919.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guming123416/services/trackbacks/31919.html</trackback:ping><description><![CDATA[<A>　前言<BR>　　Regular&nbsp;Expressions(正则表达式，以下用RE称呼)对小弟来说一直都是神密的地带，看到一些网络上的大大，简单用RE就决解了某些文字的问题，小弟便兴起了学一学RE的想法，但小弟天生就比较懒一些，总希望看有没有些快速学习的方式，于是小弟又请出Google大神，藉由祂的神力，小弟在网络上找到了Jim&nbsp;Hollenhorst先生的文章，经过了阅读，小弟觉得真是不错，所以就做个小心得报告，跟Move-to.Net的朋友分享，希望能为各位大大带来一丁点在学习RE时的帮助。Jim&nbsp;Hollenhorst大大文章之网址如下，有需要的大大可直接连结。<BR><BR>　　The&nbsp;30&nbsp;Minute&nbsp;Regex&nbsp;Tutorial&nbsp;By&nbsp;Jim&nbsp;Hollenhorst<BR><BR>　　</A><A href="http://www.codeproject.com/useritems/RegexTutorial.asp" target=_blank>http://www.codeproject.com/useritems/RegexTutorial.asp</A><A><BR><BR>　　什么是RE?<BR>　　想必各位大大在做文件查找的时侯都有使用过万用字符”*”，比如说想查找在Windows目录下所有的Word文件时，你可能就会用”*.doc”这样的方式来做查找，因为”*”所代表的是任意的字符。RE所做的就是类似这样的功能，但其功能更为强大。<BR><BR>　　写程序时，常需要比对字符串是否符合特定样式，RE最主要的功能就是来描述这特定的样式，因此可以将RE视为特定样式的描述式，举个例子来说，”\w+”所代表的就是任何字母与数字所组成的非空字符串(non-null&nbsp;string)。在.NET&nbsp;framework中提供了非常强大的类别库，藉此可以很轻易的使用RE来做文字的查找与取代、对复杂标头的译码及验证文字等工作。<BR><BR>　　学习RE最好的方式就是藉由例子亲自来做做看。Jim&nbsp;Hollenhorst大大也提供了一个工具程序Expresso(来杯咖啡吧)，来帮助我们学习RE，下载的网址是</A><A href="http://www.codeproject.com/useritems/RegexTutorial/ExpressoSetup2_1C.zip" target=_blank>http://www.codeproject.com/useritems/RegexTutorial/ExpressoSetup2_1C.zip</A><A>。<BR><BR>　　接下来，就让我们来体验一些例子吧。<BR><BR>　　一些简单的例子<BR>　　假设要查找文章中Elvis后接有alive的文字符串的话，使用RE可能会经过下列的过程，括号是所下RE的意思：<BR><BR>　　1.&nbsp;elvis&nbsp;(查找elvis)<BR><BR>　　上述代表所要查找的字符顺序为elvis。在.NET中可以设定乎略字符的大小写，所以”Elvis”、”ELVIS”或者是”eLvIs”都是符合1所下的RE。但因为这只管字符出现的顺序为elvis，所以pelvis也是符合1所下的RE。可以用2的RE来改进。<BR><BR>　　2.&nbsp;\belvis\b&nbsp;(将elvis视为一整体的字查找，如elvis、Elvis乎略字符大小写时)<BR>“\b”在RE中有特别的意思，在上述的例子中所指的就是字的边界，所以\belvis\b用\b把elvis的前后边界界定出来，也就是要elvis这个字。<BR><BR>　　假设要将同一行里elvis后接有alive的文字符串找出来，此时就会用到另外二个特别意义的字符”.”及”*”。”.”所代表就是除了换行字符的任意字符，而”*”所代表的是重复*之前项目直到找到符合RE的字符串。所以”.*”所指的就是除了换行字符外的任意数目的字符数。所以查找同一行里elvis后接有alive的文字符串找出来，则可下如3之RE。<BR><BR>　　3.&nbsp;\belvis\b.*\balive\b&nbsp;(查找elvis后面接有alive的文字符串，如elvis&nbsp;is&nbsp;alive)<BR><BR>　　用简单之特别字符就可以组成功能强大的RE，但也发现当使用越来越多的特别字符时，RE就会越来越难看得懂了。<BR><BR><BR>再看看另外的例子<BR>　　组成有效的电话号码<BR><BR>　　假使要从网页上收集顾客格式为xxx-xxxx的7位数字的电话号码，其中x是数字，RE可能会这样写。<BR><BR>　　4.&nbsp;\b\d\d\d-\d\d\d\d&nbsp;(查找七位数字之电话号码，如123-1234)<BR>　　每一个\d代表一个数字。”-”则是一般的连字符号，为避免太多重复的\d，RE可以改写成如5的方式。<BR><BR>　　5.&nbsp;\b\d{3}-\d{4}&nbsp;(查找七位数字电话号码较好的方法，如123-1234)<BR>　　在\d后的{3}，代表重复前一个项目三次，也就是相等于\d\d\d。<BR><BR>　　RE的学习及测试工具&nbsp;Expresso<BR><BR>　　因为RE不易阅读及使用者容易会下错RE的特性，Jim大大开发了一个工具软件Expresso，用来帮助使用者学习及测试RE，除了上面所述的网址之外，也可以上Ultrapico网站(</A><A href="http://www.ultrapico.com)/" target=_blank>http://www.Ultrapico.com)</A><A>。安装完Expresso后，在Expression&nbsp;Library中，Jim大大把文章的例子都建立在其中，可以边看文章边测试，也可以试着修改范例所下的RE，马上可以看到结果，小弟觉得非常好用。各位大大可以试试。<BR><BR>　　.NET中RE的基础概念<BR>　　特殊字符<BR><BR>　　有些字符有特别的意义，比如之前所看到的”\b”、”.”、”*”、”\d”等。”\s”所代表的是任意空格符，比如说spaces、tabs、newlines等.。”\w”代表是任意字母或数字字符。<BR><BR>　　再看一些例子吧<BR>　　6.&nbsp;\ba\w*\b&nbsp;(查找a开头的字，如able)<BR>　　这RE描述要查找一个字的开始边界(\b)，再来是字母”a”，再加任意数目的字母数字(\w*)，再接结束这个字的结束边界(\b)。<BR><BR>　　7.&nbsp;\d+&nbsp;(查找数字字符串)<BR>　　“+”和”*”非常相似，除了+至少要重复前面的项目一次。也就是说至少有一个数字。<BR><BR>　　8.&nbsp;\b\w{6}\b&nbsp;(查找六个字母数字的字，如ab123c)<BR><BR>　　下表为RE常用的特殊字符<BR><BR>　　.&nbsp;除了换行字符的任意字符<BR>　　\w&nbsp;任意字母数字字符<BR>　　\s&nbsp;任意空格符<BR>　　\d&nbsp;任意数字字符<BR>　　\b&nbsp;界定字的边界<BR>　　^&nbsp;文章的开头，如”^The''&nbsp;用以表示出现于文章开头的字符串为”The”<BR>　　$&nbsp;文章的结尾，如”End$”用以表示出现在文章的结尾为”End”<BR>　　特殊字符”^”及”$”是用来查找某些字必需是文章的开头或结尾，这在验证输入是否符合某一样式时特别用有，比如说要验证七位数字的电话号码，可能会输入如下9的RE。<BR><BR>　　9.&nbsp;^\d{3}-\d{4}$&nbsp;(验证七位数字之电话号码)<BR><BR>　　这和第5个RE相同，但其前后都无其它的字符，也就是整串字符串只有这七个数字的电话号码。在.NET中如果设定Multiline这个选项，则”^”和”$”会每行进行比较，只要某行的开头结尾符合RE即可，而不是整个文章字符串做一次比较。<BR><BR>　　转意字符(Escaped&nbsp;characters)<BR><BR>　　有时可能会需要”^”、”$”单纯的字面意义(literal&nbsp;meaning)而不要将它们当成特殊字符，此时”\”字符就是用来移除特殊字符特别意义的字符，因此”\^”、”\.”、”\\”所代表的就是”^”、”.”、”\”的字面意义。<BR><BR>　　重复前述项目<BR><BR>　　在前面看过”{3}”及”*”可以用来重复前述字符，之后我们会看到如何用同样的语法重复整个次描述(subexpressions)。下表是使用重复前述项目的一些方式。<BR><BR>　　*&nbsp;重复任意次数<BR>　　+&nbsp;重复至少一次<BR>　　?&nbsp;重复零次或一次<BR>　　{n}&nbsp;重复n次<BR>　　{n,m}&nbsp;重复至少n次，但不超过m次<BR>　　{n,}&nbsp;重复至少n次<BR><BR>　　再来试一些例子吧<BR><BR>　　10.&nbsp;\b\w{5,6}\b&nbsp;(查找五个或六个字母数字字符的字，如as25d、d58sdf等)<BR>　　11.&nbsp;\b\d{3}\s\d{3}-\d{4}&nbsp;(查找十个数字的电话号码，如800&nbsp;123-1234)<BR>　　12.&nbsp;\d{3}-\d{2}-\d{4}&nbsp;(查找社会保险号码，如&nbsp;123-45-6789)<BR>　　13.&nbsp;^\w*&nbsp;(每行或整篇文章的第一个字)<BR>　　在Espresso可试试有Multiline和没Multiline的不同。<BR><BR>　　匹配某范围的字符<BR><BR>　　有时需要查找某些特定的字符时怎么辨?这时中括号”[]”就派上了用场。因此[aeiou]所要查找的是”a”、”e”、”i”、”o”、”u”这些元音，[.?!]所要查找的是”.”、”?”、”!”这些符号，在中括号中的特殊字符的特别意义都会被移除，也就是解译成单纯的字面意义。也可以指定某些范围的字符，如”[a-z0-9]”，所指的就是任意小写字母或任意数字。<BR><BR>　　接下来再看一个比较初复杂查找电话号码的RE例子<BR><BR>　　14.&nbsp;\(?\d{3}[(&nbsp;]&nbsp;\s?\d{3}[-&nbsp;]\d{4}&nbsp;(查找十位数字之电话号码，如(080)&nbsp;333-1234&nbsp;)<BR><BR>　　这样的RE可查找出较多种格式的电话号码，如(080)&nbsp;123-4567、511&nbsp;254&nbsp;6654等。”\(?”代表一个或零个左小括号”(“，而”[(&nbsp;]”代表查找一个右小括号”)”或空格符，”\s?”指一个或零个空格符组。但这样的RE会将类似”800)&nbsp;45-3321”这样的电话找出来，也就是括号没有对称平衡的问题，之后会学到择一(alternatives)来决解这样的问题。<BR><BR>　　不包含在某特定字符组里(Negation)<BR><BR>　　有时需要查找在包含在某特定字符组里的字符，下表说明如何做类似这样的描述。<BR><BR>　　\W&nbsp;不是字母数字的任意字符<BR>　　\S&nbsp;不是空格符的任意字符<BR>　　\D&nbsp;不是数字字符的任意字符<BR>　　\B&nbsp;不在字边界的位置<BR>　　[^x]&nbsp;不是x的任意字符<BR>　　[^aeiou]&nbsp;不是a、e、i、o、u的任意字符<BR><BR>　　15.&nbsp;\S+&nbsp;(不包含空格符的字符串)<BR><BR>　　择一(Alternatives)<BR><BR>　　有时会需要查找几个特定的选择，此时”|”这个特殊字符就派上用场了，举例来说，要查找五个数字及九个数字(有”-”号)的邮政编码。<BR><BR>　　16.&nbsp;\b\d{5}-\d{4}\b|\b\d{5}\b&nbsp;(查找五个数字及九个数字(有”-”号)的邮政编码)<BR><BR>　　在使用Alternatives时需要注意的是前后的次序，因为RE在Alternatives中会优先选择符合最左边的项目，16中，如果把查找五个数字的项目放在前面，则这RE只会找到五个数字的邮政编码。了解了择一，可将14做更好的修正。<BR><BR>　　17.&nbsp;(\(\d{3}\)|\d{3})\s?\d{3}[-&nbsp;]\d{4}&nbsp;(十个数字的电话号码)<BR><BR>　　群组(Grouping)<BR><BR>　　括号可以用来介定一个次描述，经由次描述的介定，可以针对次描述做重复或及他的处理。<BR><BR>　　18.&nbsp;(\d{1,3}\.){3}\d{1,3}&nbsp;(寻找网络地址的简单RE)<BR><BR>　　此RE的意思第一个部分(\d{1,3}\.){3}，所指的是，数字最小一位最多三位，并且后面接有”.”符号，此类型的共有三个，之后再接一到三位的数字，也就是如192.72.28.1这样的数字。<BR><BR>　　但这样会有个缺点，因为网络地址数字最多只到255，但上述的RE只要是一到三位的数字都是符合的，所以这需要让比较的数字小于256才行，但只单独使用RE并无法做这样的比较。在19中使用择一来将地址的限制在所需要的范围内，也就是0到255。<BR><BR>　　19.&nbsp;((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)&nbsp;(寻找网络地址)<BR><BR>　　有没有发觉RE越来越像外星人说的话了?就以简单的寻找网络地址，直接看RE都满难理解的哩。<BR><BR>　　Expresso&nbsp;Analyzer&nbsp;View<BR><BR>　　Expresso提供了一个功能，它可以将所下的RE变成树状的说明，一组组的分开说明，提供了一个好的除错环境。其它的功能，如部分符合(Partial&nbsp;Match只查找反白RE的部分)及除外符合(Exclude&nbsp;Match只不查找反白RE的部分)就留给各位大大试试啰。<BR><BR>　　当次描述用括号群组起来时，符合次描述的文字可用在之后的程序处理或RE本身。在预设的情型下，所符合的群组是由数字命名，由1开始，由顺序是由左至右，这自动群组命名，可在Expresso中的skeleton&nbsp;view或result&nbsp;view中看到。<BR><BR>　　Backreference是用来查找群组中抓取的符合文字所相同的文字。举例来说”\1”所指符合群组1所抓取的文字。<BR><BR>　　20.&nbsp;\b(\w+)\b\s*\1\b&nbsp;(寻找重复字，此处说的重复是指同样的字，中间有空白隔开如dog&nbsp;dog这样的字)<BR>(\w+)会抓取至少一个字符的字母或数字的字，并将它命名为群组1，之后是查找任意空格符，再接和群组1相同的文字。<BR><BR>　　如果不喜欢群组自动命名的1，也可以自行命名，以上述例子为例，(\w+)改写为(?&lt;Word&gt;\w+)，这就是将所抓取的群组命名为Word，Backreference就要改写成为\k&lt;Word&gt;<BR>21.&nbsp;\b(?&lt;Word&gt;\w+)\b\s*\k&lt;Word&gt;\b&nbsp;(使用自行命名群组抓取重复字)<BR><BR>　　使用括号还有许多特别的语法元素，比较通用的列表如下：<BR><BR>　　抓取(Captures)&nbsp;<BR>　　(exp)&nbsp;符合exp并抓取它进自动命名的群组<BR>　　(?&lt;name&gt;exp)&nbsp;符合exp并抓取它进命名的群组name<BR>　　(?:exp)&nbsp;符合exp，不抓取它<BR>　　Lookarounds&nbsp;<BR>　　(?=exp)&nbsp;符合字尾为exp的文字<BR>　　(?&lt;=exp)&nbsp;符合前缀为exp的文字<BR>　　(?!exp)&nbsp;符合后面没接exp字尾的文字<BR>　　(?&lt;!exp)&nbsp;符合前面没接exp前缀的文字<BR>　　批注Comment&nbsp;<BR>　　(?#comment)&nbsp;批注<BR><BR>　　Positive&nbsp;Lookaround<BR><BR>　　接下来要谈的是lookahead及lookbehind&nbsp;assertions。它们所查找的是目前符合之前或之后的文字，并不包含目前符合本身。这些就如同”^”及”\b”特殊字符，本身并不会对应任何文字(用来界定位置)，也因此称做是zero-width&nbsp;assertions，看些例子也许会清楚些。<BR><BR>　　(?=exp)是一个”zero-width&nbsp;positive&nbsp;lookahead&nbsp;assertion”。它指的就是符合字尾为exp的文字，但不包含exp本身。<BR><BR>　　22.&nbsp;\b\w+(?=ing\b)&nbsp;(字尾为ing的字，比如说filling所符合的就是fill)<BR>(?&lt;=exp)是一个”zero-width&nbsp;positive&nbsp;lookbehind&nbsp;assertion”。它指的就是符合前缀为exp的文字，但不包含exp本身。<BR><BR>　　23.&nbsp;(?&lt;=\bre)\w+\b&nbsp;(前缀为re的字，比如说repeated所符合的就是peated)<BR>　　24.&nbsp;(?&lt;=\d)\d{3}\b&nbsp;(在字尾的三位数字，且之前接一位数字)<BR>　　25.&nbsp;(?&lt;=\s)\w+(?=\s)&nbsp;(由空格符分隔开的字母数字字符串)<BR><BR>　　Negative&nbsp;Lookaround<BR><BR>　　之前有提到，如何查找一个非特定或非在特定群组的字符。但如果只是要验证某字符不存在而不要对应这些字符进来呢?举个例子来说，假设要查找一个字，它的字母里有q但接下来的字母不是u，可以用下列的RE来做。<BR><BR>　　26.&nbsp;\b\w*q[^u]\w*\b&nbsp;(一个字，其字母里有q但接下来的字母不是u)<BR><BR>　　这样的RE会有一个问题，因为[^u]要对应一个字符，所以若q是字的最后一个字母，[^u]这样的下法就会将空格符对应下去，结果就有可能会符合二个字，比如说”Iraq&nbsp;haha”这样的文字。使用Negative&nbsp;Lookaround就能解决这样的问题。<BR><BR>　　27.&nbsp;\b\w*q(?!u)\w*\b&nbsp;(一个字，其字母里有q但接下来的字母不是u)<BR>　　这是”zero-width&nbsp;negative&nbsp;lookahead&nbsp;assertion”。<BR><BR>　　28.&nbsp;\d{3}(?!\d)&nbsp;(三个位的数字，其后不接一个位数字)<BR><BR>　　同样的，可以使用(?&lt;!exp)，”zero-width&nbsp;negative&nbsp;lookbehind&nbsp;assertion”，来符合前面没接exp前缀的文字符串。<BR><BR>　　29.&nbsp;(?&lt;![a-z&nbsp;])\w{7}&nbsp;(七个字母数字的字符串，其前面没接字母或空格)<BR><BR>　　30.&nbsp;(?&lt;=&lt;(\w+)&gt;).*(?=&lt;\/\1&gt;)&nbsp;(HTML卷标间的文字)<BR>　　这使用lookahead及lookbehind&nbsp;assertion来取出HTML间的文字，不包括HTML卷标。<BR><BR>　　请批注(Comments&nbsp;Please)<BR>　　括号还有个特殊的用途就是用来包住批注，语法为”(?#comment)”，若设定”Ignore&nbsp;Pattern&nbsp;Whitespace”选项，则RE中的空格符当RE使用时会乎略。此选项设定时，”#”之后的文字会乎略。<BR><BR>　　31.&nbsp;HTML卷标间的文字，加上批注<BR><BR>　　(?&lt;=&nbsp;&nbsp;　#查找前缀，但不包含它<BR>　　&lt;(\w+)&gt;&nbsp;#HTML标签<BR>　　)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#结束查找前缀<BR>　　.*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#符合任何文字<BR>　　(?=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#查找字尾，但不包含它<BR>　　&lt;\/\1&gt;&nbsp;&nbsp;#符合所抓取群组1之字符串，也就是前面小括号的HTML标签<BR>　　)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#结束查找字尾<BR><BR>　　寻找最多字符的字及最少字符的字(Greedy&nbsp;and&nbsp;Lazy)<BR>　　当RE下要查找一个范围的重复时(如”.*”)，它通常会寻找最多字符的符合字，也就是Greedy&nbsp;matching。举例来说。<BR><BR>　　32.&nbsp;a.*b&nbsp;&nbsp;(开始为a结束为b的最多字符的符合字)<BR><BR>　　若有一字符串是”aabab”，使用上述RE所得到的符合字符串就是”aabab”，因为这是寻找最多字符的字。有时希望是符合最少字符的字也就是lazy&nbsp;matching。只要将重复前述项目的表加上问号(?)就可以把它们全部变成lazy&nbsp;matching。因此”*?”代表的就是重复任意次数，但是使用最少重复的次数来符合。举个例子来说：<BR><BR>　　33.&nbsp;a.*?b&nbsp;(开始为a结束为b的最少字符的符合字)<BR><BR>　　若有一字符串是”aabab”，使用上述RE第一个所得到的符合字符串就是”aab”再来是”ab”，因为这是寻找最少字符的字。<BR><BR>　　*?&nbsp;重复任意次数，最少重复次数为原则<BR>　　+?&nbsp;重复至少一次，最少重复次数为原则<BR>　　??&nbsp;重复零次或一次，最少重复次数为原则<BR>　　{n,m}?&nbsp;重复至少n次，但不超过m次，最少重复次数为原则<BR>　　{n,}?&nbsp;重复至少n次，最少重复次数为原则<BR><BR>还有什么没提到呢?<BR><BR>　　到目前为止，已经提到了许多建立RE的元素，当然还有许多元素没有提到，下表整理了一些没提到的元素，在最左边的字段的数字是说明在Expresso中的例子。<BR><BR>　　#&nbsp;语法&nbsp;说明<BR><BR>　　\a&nbsp;Bell&nbsp;字符<BR>　　\b&nbsp;通常是指字的边界，在字符组里所代表的就是backspace<BR>　　\t&nbsp;Tab<BR><BR>　　34&nbsp;\r&nbsp;Carriage&nbsp;return<BR><BR>　　\v&nbsp;Vertical&nbsp;Tab<BR>　　\f&nbsp;From&nbsp;feed<BR><BR>　　35&nbsp;\n&nbsp;New&nbsp;line<BR>&nbsp;　　\e&nbsp;Escape<BR><BR>　　36&nbsp;\nnn&nbsp;ASCII八位码为nnn的字符<BR><BR>　　37&nbsp;\xnn&nbsp;十六位码为nn的字符<BR><BR>　　38&nbsp;\unnnn&nbsp;Unicode为nnnn的字符<BR><BR>　　39&nbsp;\cN&nbsp;Control&nbsp;N字符，举例来说Ctrl-M是\cM<BR><BR>　　40&nbsp;\A&nbsp;字符串的开始(和^相似，但不需籍由multiline选项)<BR><BR>　　41&nbsp;\Z&nbsp;字符串的结尾<BR>　　\z&nbsp;字符串的结尾<BR><BR>　　42&nbsp;\G&nbsp;目前查找的开始<BR><BR>　　43&nbsp;\p{name}&nbsp;Unicode&nbsp;字符组名称为name的字符，比如说\p{Lowercase_Letter}&nbsp;所指的就是小写字<BR>　　(?&gt;exp)&nbsp;Greedy次描述，又称之为non-backtracking次描述。这只符合一次且不采backtracking。<BR><BR>　　44&nbsp;(?&lt;x&gt;-&lt;y&gt;exp)<BR><BR>　　or&nbsp;(?-&lt;y&gt;exp)&nbsp;平衡群组。虽复杂但好用。它让已命名的抓取群组可以在堆栈中操作使用。(小弟对这个也是不太懂哩)<BR><BR>　　45&nbsp;(?im-nsx:exp)&nbsp;为次描述exp更改RE选项，比如(?-i:Elvis)就是把Elvis大乎略大小写的选项关掉<BR><BR>　　46&nbsp;(?im-nsx)&nbsp;为之后的群组更改RE选项。<BR>　　(?(exp)yes|no)&nbsp;次描述exp视为zero-width&nbsp;positive&nbsp;lookahead。若此时有符合，则yes次描述为下一个符合标的，若否，则no&nbsp;次描述为下一个符合标的。<BR>　　(?(exp)yes)&nbsp;和上述相同但无no次描述<BR>　　(?(name)yes|no)&nbsp;若name群组为有效群组名称，则yes次描述为下一个符合标的，若否，则no&nbsp;次描述为下一个符合标的。<BR><BR>　　47&nbsp;(?(name)yes)&nbsp;和上述相同但无no次描述<BR><BR>　　结论<BR>　　经过了一连串的例子，及Expresso的帮忙，相信各位大大对RE有个基本的了解，网络上当然有许多有关于RE的文章，如果各位大大有兴趣</A><A href="http://www.codeproject.com&nbsp;/" target=_blank>http://www.codeproject.com&nbsp;</A><A>还有许多关于RE的相关文章。若大大对书有兴趣的话，Jeffrey&nbsp;Friedl的Mastering&nbsp;Regular&nbsp;Expressions很多大大都有推(小弟还没拜读)。希望籍由这样的心得报告，能让对RE有兴趣的大大能缩短学习曲线，当然这是小弟第一次接触RE，若文章中有什么错误或说明的不好的地方，可要请各位大大体谅，并请各位大大将需要修正的地方mail给小弟，小弟会非常感谢各位大大。<BR></A><img src ="http://www.blogjava.net/guming123416/aggbug/31919.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guming123416/" target="_blank">lovajava_ye</a> 2006-02-22 10:30 <a href="http://www.blogjava.net/guming123416/archive/2006/02/22/31919.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Request 对象 错误 'ASP 0104 : 80004005' 不许操作</title><link>http://www.blogjava.net/guming123416/archive/2006/02/22/31917.html</link><dc:creator>lovajava_ye</dc:creator><author>lovajava_ye</author><pubDate>Wed, 22 Feb 2006 02:27:00 GMT</pubDate><guid>http://www.blogjava.net/guming123416/archive/2006/02/22/31917.html</guid><wfw:comment>http://www.blogjava.net/guming123416/comments/31917.html</wfw:comment><comments>http://www.blogjava.net/guming123416/archive/2006/02/22/31917.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guming123416/comments/commentRss/31917.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guming123416/services/trackbacks/31917.html</trackback:ping><description><![CDATA[<P>症状:<BR>上传文件到 Windows 2003 server + IIS 6.0 服务器的时候遇到下列错误:<BR>请求对象错误 'ASP 0104 : 80004005' <BR>操作被禁止<BR>/Upload.asp, line 40</P>
<P>原因:<BR>IIS6.0 禁止上传超过 200kB 的文件. 因此你需要修改 IIS 的默认设置.</P>
<P>技术背景<BR>在 IIS 6.0 中, AspMaxRequestEntityAllowed 属性指定了一个 ASP 请求(Request)可以使用的最大字节数. 如果 Content-Length 头信息中包含的请求长度超过了 AspMaxRequestEntityAllowed 的值, IIS 将返回一个 403 错误信息. <BR>这个属性值与 MaxRequestEntityAllowed 相似, 但是是针对 ASP 请求的. 假如你知道自己的 ASP 应用只需要处理很少的请求数据, 你可以在 World Wide Web Publishing Service (WWW 发布服务)层级设定全局的 MaxRequestEntityAllowed 属性为 1MB, 并单独设定 AspMaxRequestEntityAllowed 为一个较小的值.</P>
<P>解决方法<BR>打开位于 C:\Windows\System32\Inetsrv 中的 metabase.XML, 并修改 AspMaxRequestEntityAllowed 为你需要的值(例如 1073741824, 1GB).</P><img src ="http://www.blogjava.net/guming123416/aggbug/31917.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guming123416/" target="_blank">lovajava_ye</a> 2006-02-22 10:27 <a href="http://www.blogjava.net/guming123416/archive/2006/02/22/31917.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ASP与存储过程</title><link>http://www.blogjava.net/guming123416/archive/2006/02/22/31916.html</link><dc:creator>lovajava_ye</dc:creator><author>lovajava_ye</author><pubDate>Wed, 22 Feb 2006 02:26:00 GMT</pubDate><guid>http://www.blogjava.net/guming123416/archive/2006/02/22/31916.html</guid><wfw:comment>http://www.blogjava.net/guming123416/comments/31916.html</wfw:comment><comments>http://www.blogjava.net/guming123416/archive/2006/02/22/31916.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guming123416/comments/commentRss/31916.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guming123416/services/trackbacks/31916.html</trackback:ping><description><![CDATA[ASP与存储过程(Stored Procedures)的文章不少，但是我怀疑作者们是否真正实践过。我在初学时查阅过大量相关资料，发现其中提供的很多方法实际操作起来并不是那么回事。对于简单的应用，这些资料也许是有帮助的，但仅限于此，因为它们根本就是千篇一律，互相抄袭，稍微复杂点的应用，就全都语焉不详了。<BR>&nbsp;&nbsp;&nbsp; 现在，我基本上通过调用存储过程访问SQL Server，以下的文字虽不敢保证绝对正确，但都是实践的总结，希望对大家能有帮助。 
<P>&nbsp;&nbsp;&nbsp; 存储过程就是作为可执行对象存放在数据库中的一个或多个SQL命令。<BR>&nbsp;&nbsp;&nbsp; 定义总是很抽象。存储过程其实就是能完成一定操作的一组SQL语句，只不过这组语句是放在数据库中的(这里我们只谈SQL Server)。如果我们通过创建存储过程以及在ASP中调用存储过程，就可以避免将SQL语句同ASP代码混杂在一起。这样做的好处至少有三个：<BR>&nbsp;&nbsp;&nbsp; 第一、大大提高效率。存储过程本身的执行速度非常快，而且，调用存储过程可以大大减少同数据库的交互次数。<BR>&nbsp;&nbsp;&nbsp; 第二、提高安全性。假如将SQL语句混合在ASP代码中，一旦代码失密，同时也就意味着库结构失密。<BR>&nbsp;&nbsp;&nbsp; 第三、有利于SQL语句的重用。<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 在ASP中，一般通过command对象调用存储过程，根据不同情况，本文也介绍其它调用方法。为了方便说明，根据存储过程的输入输出，作以下简单分类：<BR>&nbsp;&nbsp;&nbsp; <STRONG>1. 只返回单一记录集的存储过程</STRONG><BR>&nbsp;&nbsp;&nbsp; 假设有以下存储过程(本文的目的不在于讲述T-SQL语法，所以存储过程只给出代码，不作说明)：</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> /*SP1*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.getUserList<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from dbo.[userinfo]<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 以上存储过程取得userinfo表中的所有记录，返回一个记录集。通过command对象调用该存储过程的ASP代码如下:<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**通过Command对象调用存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm,MyRst<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; MyComm.ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserList"&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp; Set MyRst = MyComm.Execute<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; 存储过程取得的记录集赋给MyRst，接下来，可以对MyRst进行操作。<BR>&nbsp;&nbsp;&nbsp; 在以上代码中，CommandType属性表明请求的类型，取值及说明如下：<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1&nbsp;&nbsp; 表明CommandText参数的类型无法确定<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 表明CommandText是一般的命令类型<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 表明CommandText参数是一个存在的表名称<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp; 表明CommandText参数是一个存储过程的名称<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 还可以通过Connection对象或Recordset对象调用存储过程，方法分别如下：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**通过Connection对象调用存储过程**<BR></FONT>&nbsp;&nbsp;&nbsp; DIM MyConn,MyRst<BR>&nbsp;&nbsp;&nbsp; Set MyConn = Server.CreateObject("ADODB.Connection")<BR>&nbsp;&nbsp;&nbsp; MyConn.open MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串<BR></FONT>&nbsp;&nbsp;&nbsp; Set MyRst&nbsp; = MyConn.Execute("getUserList",0,4)&nbsp;<FONT color=#008000> '最后一个参断含义同CommandType</FONT><BR>&nbsp;&nbsp;&nbsp; Set MyConn = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**通过Recordset对象调用存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyRst<BR>&nbsp;&nbsp;&nbsp; Set MyRst = Server.CreateObject("ADODB.Recordset")<BR>&nbsp;&nbsp;&nbsp; MyRst.open "getUserList",MyConStr,0,1,4<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串,最后一个参断含义与CommandType相同</FONT></P>
<P>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; <STRONG>2. 没有输入输出的存储过程<BR></STRONG>&nbsp;&nbsp;&nbsp; 请看以下存储过程：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>/*SP2*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.delUserAll<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete from dbo.[userinfo]<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 该存储过程删去userinfo表中的所有记录，没有任何输入及输出，调用方法与上面讲过的基本相同，只是不用取得记录集：</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '**通过Command对象调用存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; MyComm.ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "delUserAll"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '表明这是一个存储过程<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.Execute&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'此处不必再取得记录集<BR></FONT>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing&nbsp; </P>
<P>&nbsp;&nbsp;&nbsp; 当然也可通过Connection对象或Recordset对象调用此类存储过程，不过建立Recordset对象是为了取得记录集，在没有返回记录集的情况下，还是利用Command对象吧。</P>
<P><BR>&nbsp;&nbsp;&nbsp; <STRONG>3. 有返回值的存储过程</STRONG><BR>&nbsp;&nbsp;&nbsp; 在进行类似SP2的操作时，应充分利用SQL Server强大的事务处理功能，以维护数据的一致性。并且，我们可能需要存储过程返回执行情况，为此，将SP2修改如下：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>/*SP3*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.delUserAll<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BEGIN TRANSACTION<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delete from dbo.[userinfo]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF @@error=0 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; COMMIT TRANSACTION<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ROLLBACK TRANSACTION<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 以上存储过程，在delete顺利执行时，返回1，否则返回0，并进行回滚操作。为了在ASP中取得返回值，需要利用Parameters集合来声明参数：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**调用带有返回值的存储过程并取得返回值**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm,MyPara<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; MyComm.ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> 'MyConStr是数据库连接字串<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "delUserAll"&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译<BR></FONT>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '声明返回值<BR></FONT>&nbsp;&nbsp;&nbsp; Set Mypara = MyComm.CreateParameter("RETURN",2,4)<BR>&nbsp;&nbsp;&nbsp; MyComm.Parameters.Append MyPara<BR>&nbsp;&nbsp;&nbsp; MyComm.Execute<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'取得返回值<BR></FONT>&nbsp;&nbsp;&nbsp; DIM retValue<BR>&nbsp;&nbsp;&nbsp; retValue = MyComm(0)&nbsp;&nbsp;&nbsp; <FONT color=#008000>'或retValue = MyComm.Parameters(0)</FONT><BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 在MyComm.CreateParameter("RETURN",2,4)中，各参数的含义如下：<BR>&nbsp;&nbsp;&nbsp; 第一个参数("RETURE")为参数名。参数名可以任意设定，但一般应与存储过程中声明的参数名相同。此处是返回值，我习惯上设为"RETURE"；<BR>&nbsp;&nbsp;&nbsp; 第二个参数(2)，表明该参数的数据类型，具体的类型代码请参阅ADO参考，以下给出常用的类型代码：<BR>&nbsp;&nbsp;&nbsp; adBigInt: 20 ;<BR>&nbsp;&nbsp;&nbsp; adBinary : 128 ; <BR>&nbsp;&nbsp;&nbsp; adBoolean: 11 ;<BR>&nbsp;&nbsp;&nbsp; adChar: 129 ;<BR>&nbsp;&nbsp;&nbsp; adDBTimeStamp: 135 ;<BR>&nbsp;&nbsp;&nbsp; adEmpty: 0 ;<BR>&nbsp;&nbsp;&nbsp; adInteger: 3 ;<BR>&nbsp;&nbsp;&nbsp; adSmallInt: 2 ; <BR>&nbsp;&nbsp;&nbsp; adTinyInt: 16 ;<BR>&nbsp;&nbsp;&nbsp; adVarChar: 200 ;<BR>&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>对于返回值，只能取整形，且-1到-99为保留值；</FONT><BR>&nbsp;&nbsp;&nbsp; 第三个参数(4)，表明参数的性质，此处4表明这是一个返回值。此参数取值的说明如下：<BR>&nbsp;&nbsp;&nbsp; 0 : 类型无法确定； 1: 输入参数；2: 输入参数；3：输入或输出参数；4: 返回值<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 以上给出的ASP代码，应该说是完整的代码，也即最复杂的代码，其实</P>
<P>&nbsp;&nbsp;&nbsp; Set Mypara = MyComm.CreateParameter("RETURN",2,4)<BR>&nbsp;&nbsp;&nbsp; MyComm.Parameters.Append MyPara<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 可以简化为</P>
<P>&nbsp;&nbsp;&nbsp; MyComm.Parameters.Append MyComm.CreateParameter("RETURN",2,4)</P>
<P>&nbsp;&nbsp;&nbsp; 甚至还可以继续简化，稍后会做说明。<BR>&nbsp;&nbsp;&nbsp; 对于带参数的存储过程，只能使用Command对象调用(也有资料说可通过Connection对象或Recordset对象调用，但我没有试成过)。</P>
<P><BR>&nbsp;&nbsp;&nbsp; <STRONG>4. 有输入参数和输出参数的存储过程</STRONG><BR>&nbsp;&nbsp;&nbsp; 返回值其实是一种特殊的输出参数。在大多数情况下，我们用到的是同时有输入及输出参数的存储过程，比如我们想取得用户信息表中，某ID用户的用户名，这时候，有一个输入参数----用户ID，和一个输出参数----用户名。实现这一功能的存储过程如下：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>/*SP4*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.getUserName<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @UserID int,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @UserName varchar(40) output<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if @UserID is null return<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select @UserName=username <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dbo.[userinfo] <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where userid=@UserID<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 调用该存储过程的ASP代码如下：</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '**调用带有输入输出参数的存储过程**<BR></FONT>&nbsp;&nbsp;&nbsp; DIM MyComm,UserID,UserName<BR>&nbsp;&nbsp;&nbsp; UserID = 1<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; MyComm.ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserName"&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp; MyComm.Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '要求将SQL命令先行编译<BR></FONT>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'声明参数<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.Parameters.append MyComm.CreateParameter("@UserID",3,1,4,UserID)<BR>&nbsp;&nbsp;&nbsp; MyComm.Parameters.append MyComm.CreateParameter("@UserName",200,2,40)<BR>&nbsp;&nbsp;&nbsp; MyComm.Execute<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'取得出参</FONT><BR>&nbsp;&nbsp;&nbsp; UserName = MyComm(1)<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; 在以上代码中，可以看到，与声明返回值不同，声明输入参数时需要5个参数，声明输出参数时需要4个参数。声明输入参数时5个参数分别为：<FONT color=#0000ff>参数名、参数数据类型、参数类型、数据长度、参数值</FONT>。声明输出参数时，没有最后一个参数：参数值。<BR>&nbsp;&nbsp;&nbsp; 需要特别注意的是：<FONT color=#0000ff>在声明参数时，顺序一定要与存储过程中定义的顺序相同，而且各参数的数据类型、长度也要与存储过程中定义的相同</FONT>。<BR>&nbsp;&nbsp;&nbsp; 如果存储过程有多个参数，ASP代码会显得繁琐，可以使用with命令简化代码：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**调用带有输入输出参数的存储过程(简化代码)**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm,UserID,UserName<BR>&nbsp;&nbsp;&nbsp; UserID = 1<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; with MyComm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> 'MyConStr是数据库连接字串</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserName"&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserID",3,1,4,UserID)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserName",200,2,40)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Execute<BR>&nbsp;&nbsp;&nbsp; end with<BR>&nbsp;&nbsp;&nbsp; UserName = MyComm(1)<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing<BR>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp; 假如我们要取得ID为1到10，10位用户的用户名，是不是要创建10次Command对象呢？不是的。如果需要多次调用同一存储过程，只需改变输入参数，就会得到不同的输出：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**多次调用同一存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm,UserID,UserName<BR>&nbsp;&nbsp;&nbsp; UserName = ""<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; for UserID = 1 to 10<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; with MyComm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserName"&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if UserID = 1 then<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserID",3,1,4,UserID)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserName",200,2,40)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Execute<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'重新给入参赋值(此时参数值不发生变化的入参以及出参不必重新声明)<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters("@UserID") = UserID<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Execute<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end if<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; end with<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UserName = UserName + MyComm(1) + ","&nbsp;&nbsp;&nbsp;<FONT color=#008000> '也许你喜欢用数组存储<BR></FONT>&nbsp;&nbsp;&nbsp; next<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; 通过以上代码可以看出：<FONT color=#0000ff>重复调用同一存储过程时，只需为值发生改变的输入参数重新赋值即可</FONT>，这一方法在有多个输入输出参数，且每次调用时只有一个输入参数的值发生变化时，可以大大减少代码量。</P>
<P><BR>&nbsp;&nbsp;&nbsp; <STRONG>5. 同时具有返回值、输入参数、输出参数的存储过程<BR></STRONG>&nbsp;&nbsp;&nbsp; 前面说过，在调用存储过程时，声明参数的顺序要与存储过程中定义的顺序相同。还有一点要特别注意：<FONT color=#0000ff>如果存储过程同时具有返回值以及输入、输出参数，返回值要最先声明</FONT>。<BR>&nbsp;&nbsp;&nbsp; 为了演示这种情况下的调用方法，我们改善一下上面的例子。还是取得ID为1的用户的用户名，但是有可能该用户不存在(该用户已删除，而userid是自增长的字段)。存储过程根据用户存在与否，返回不同的值。此时，存储过程和ASP代码如下：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>/*SP5*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.getUserName<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--为了加深对"顺序"的印象，将以下两参数的定义顺序颠倒一下<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @UserName varchar(40) output,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @UserID int<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if @UserID is null return<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select @UserName=username <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dbo.[userinfo] <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where userid=@UserID<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if @@rowcount&gt;0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '**调用同时具有返回值、输入参数、输出参数的存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM MyComm,UserID,UserName<BR>&nbsp;&nbsp;&nbsp; UserID = 1<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; with MyComm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'MyConStr是数据库连接字串<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserName"&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '指定存储过程名</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'返回值要最先被声明<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.Append .CreateParameter("RETURN",2,4)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'以下两参数的声明顺序也做相应颠倒<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserName",200,2,40)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@UserID",3,1,4,UserID)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Execute<BR>&nbsp;&nbsp;&nbsp; end with<BR>&nbsp;&nbsp;&nbsp; if MyComm(0) = 1 then<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UserName = MyComm(1)<BR>&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UserName = "该用户不存在"<BR>&nbsp;&nbsp;&nbsp; end if<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P><BR>&nbsp;&nbsp;&nbsp; <STRONG>6. 同时返回参数和记录集的存储过程</STRONG><BR>&nbsp;&nbsp;&nbsp; 有时候，我们需要存储过程同时返回参数和记录集，比如在利用存储过程分页时，要同时返回记录集以及数据总量等参数。以下给出一个进行分页处理的存储过程：</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> /*SP6*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.getUserList<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @iPageCount int OUTPUT,&nbsp;&nbsp; <FONT color=#008000>--总页数<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @iPage int,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--当前页号</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @iPageSize int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--每页记录数<BR></FONT>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--创建临时表</FONT> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; create table #t (ID int IDENTITY,&nbsp;&nbsp;<FONT color=#008000> --自增字段<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; userid int,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; username varchar(40))<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--向临时表中写入数据<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; insert into #t <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select userid,username from dbo.[UserInfo]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; order by userid<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--取得记录总数</FONT> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; declare @iRecordCount int<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set @iRecordCount = @@rowcount</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--确定总页数</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF @iRecordCount%@iPageSize=0<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SET @iPageCount=CEILING(@iRecordCount/@iPageSize)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ELSE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SET @iPageCount=CEILING(@iRecordCount/@iPageSize)+1<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--若请求的页号大于总页数，则显示最后一页</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IF @iPage &gt; @iPageCount<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT @iPage = @iPageCount</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--确定当前页的始末记录<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE @iStart int&nbsp;&nbsp;&nbsp; --start record<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DECLARE @iEnd int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; --end record<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT @iStart = (@iPage - 1) * @iPageSize<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SELECT @iEnd = @iStart + @iPageSize + 1</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> --取当前页记录</FONT>&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select * from #t where ID&gt;@iStart and ID&lt;@iEnd</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--删除临时表</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DROP TABLE #t</P>
<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--返回记录总数</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return @iRecordCount<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 在上面的存储过程中，输入当前页号及每页记录数，返回当前页的记录集，总页数及记录总数。为了更具典型性，将记录总数以返回值的形式返回。以下是调用该存储过程的ASP代码(具体的分页操作略去):</P>
<P>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '**调用分页存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM pagenow,pagesize,pagecount,recordcount<BR>&nbsp;&nbsp;&nbsp; DIM MyComm,MyRst<BR>&nbsp;&nbsp;&nbsp; pagenow = Request("pn")<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'自定义函数用于验证自然数</FONT><BR>&nbsp;&nbsp;&nbsp; if CheckNar(pagenow) = false then pagenow = 1<BR>&nbsp;&nbsp;&nbsp; pagesize = 20<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; with MyComm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> 'MyConStr是数据库连接字串</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserList"&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '指定存储过程名</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'返回值(记录总量)</FONT> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.Append .CreateParameter("RETURN",2,4)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> '出参(总页数)<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.Append .CreateParameter("@iPageCount",3,2)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'入参(当前页号)<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@iPage",3,1,4,pagenow)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'入参(每页记录数)<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@iPageSize",3,1,4,pagesize)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set MyRst = .Execute<BR>&nbsp;&nbsp;&nbsp; end with<BR>&nbsp;&nbsp;&nbsp; if MyRst.state = 0 then&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'未取到数据，MyRst关闭<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recordcount = -1<BR>&nbsp;&nbsp;&nbsp; else<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyRst.close&nbsp;&nbsp;&nbsp; <FONT color=#008000>'注意：若要取得参数值，需先关闭记录集对象</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; recordcount = MyComm(0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pagecount&nbsp;&nbsp; = MyComm(1)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if cint(pagenow)&gt;=cint(pagecount) then pagenow=pagecount<BR>&nbsp;&nbsp;&nbsp; end if<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'以下显示记录<BR></FONT>&nbsp;&nbsp;&nbsp; if recordcount = 0 then<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Response.Write "无记录"<BR>&nbsp;&nbsp;&nbsp; elseif recordcount &gt; 0 then<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MyRst.open<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do until MyRst.EOF<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; loop<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'以下显示分页信息</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp; else&nbsp; <FONT color=#008000>'recordcount=-1</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Response.Write "参数错误"<BR>&nbsp;&nbsp;&nbsp; end if</P>
<P>&nbsp;&nbsp;&nbsp; 对于以上代码，只有一点需要说明：<FONT color=#0000ff>同时返回记录集和参数时，若要取得参数，需先将记录集关闭，使用记录集时再将其打开</FONT>。</P>
<P><BR>&nbsp;&nbsp;&nbsp; <STRONG>7. 返回多个记录集的存储过程<BR></STRONG>&nbsp;&nbsp;&nbsp; 本文最先介绍的是返回记录集的存储过程。有时候，需要一个存储过程返回多个记录集，在ASP中，如何同时取得这些记录集呢？为了说明这一问题，在userinfo表中增加两个字段：usertel及usermail，并设定只有登录用户可以查看这两项内容。</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>/*SP7*/<BR></FONT>&nbsp;&nbsp;&nbsp; CREATE PROCEDURE dbo.getUserInfo<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @userid int,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @checklogin bit<BR>&nbsp;&nbsp;&nbsp; as<BR>&nbsp;&nbsp;&nbsp; set nocount on<BR>&nbsp;&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if @userid is null or @checklogin is null return<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select username<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dbo.[usrinfo]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where userid=@userid<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>--若为登录用户，取usertel及usermail</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if @checklogin=1<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select usertel,usermail<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from dbo.[userinfo]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where userid=@userid<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return<BR>&nbsp;&nbsp;&nbsp; end<BR>&nbsp;&nbsp;&nbsp; go</P>
<P>&nbsp;&nbsp;&nbsp; 以下是ASP代码：</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'**调用返回多个记录集的存储过程**</FONT><BR>&nbsp;&nbsp;&nbsp; DIM checklg,UserID,UserName,UserTel,UserMail<BR>&nbsp;&nbsp;&nbsp; DIM MyComm,MyRst<BR>&nbsp;&nbsp;&nbsp; UserID = 1<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'checklogin()为自定义函数，判断访问者是否登录<BR></FONT>&nbsp;&nbsp;&nbsp; checklg = checklogin()<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; with MyComm<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .ActiveConnection = MyConStr&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<FONT color=#008000> 'MyConStr是数据库连接字串</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandText&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = "getUserInfo"&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'指定存储过程名<BR></FONT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .CommandType&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'表明这是一个存储过程</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Prepared&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; = true&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#008000>'要求将SQL命令先行编译</FONT><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@userid",3,1,4,UserID)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .Parameters.append .CreateParameter("@checklogin",11,1,1,checklg)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set MyRst = .Execute<BR>&nbsp;&nbsp;&nbsp; end with<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'从第一个记录集中取值</FONT><BR>&nbsp;&nbsp;&nbsp; UserName = MyRst(0)<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'从第二个记录集中取值</FONT><BR>&nbsp;&nbsp;&nbsp; if not MyRst is Nothing then<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set MyRst = MyRst.NextRecordset()<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UserTel&nbsp; = MyRst(0)<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UserMail = MyRst(1)<BR>&nbsp;&nbsp;&nbsp; end if<BR>&nbsp;&nbsp;&nbsp; Set MyRst = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; 以上代码中，<FONT color=#0000ff>利用Recordset对象的NextRecordset方法，取得了存储过程返回的多个记录集</FONT>。</P>
<P><BR>&nbsp;&nbsp;&nbsp; 至此，针对ASP调用存储过程的各种情况，本文已做了较为全面的说明。最后说一下在一个ASP程序中，调用多个存储过程的不同方法。<BR>&nbsp;&nbsp;&nbsp; 在一个ASP程序中，调用多个存储过程至少有以下三种方法是可行的：<BR>&nbsp;&nbsp;&nbsp; <STRONG>1. 创建多个Command对象</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp; DIM MyComm<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'调用存储过程一<BR></FONT>&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '调用存储过程二</FONT><BR>&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing<BR>&nbsp;&nbsp;&nbsp; ......</P>
<P>&nbsp;&nbsp;&nbsp;<STRONG> 2. 只创建一个Command对象，结束一次调用时，清除其参数</STRONG></P>
<P>&nbsp;&nbsp;&nbsp; DIM MyComm<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '调用存储过程一<BR></FONT>&nbsp;&nbsp;&nbsp; .....<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'清除参数(假设有三个参数)<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.Parameters.delete 2<BR>&nbsp;&nbsp;&nbsp; MyComm.Parameters.delete 1<BR>&nbsp;&nbsp;&nbsp; MyComm.Parameters.delete 0<BR>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '调用存储过程二并清除参数<BR></FONT>&nbsp;&nbsp;&nbsp; ......<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing</P>
<P>&nbsp;&nbsp;&nbsp; 此时要注意：清除参数的顺序与参数声明的顺序相反，原因嘛，我也不知道。</P>
<P>&nbsp;&nbsp;&nbsp; <STRONG>3. 利用Parameters数据集合的Refresh方法重置Parameter对象</STRONG></P>
<P>&nbsp;&nbsp;&nbsp; DIM MyComm<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Server.CreateObject("ADODB.Command")<BR>&nbsp;&nbsp;&nbsp; <FONT color=#008000>'调用存储过程一</FONT><BR>&nbsp;&nbsp;&nbsp; .....<BR>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '重置Parameters数据集合中包含的所有Parameter对象<BR></FONT>&nbsp;&nbsp;&nbsp; MyComm.Parameters.Refresh<BR>&nbsp;&nbsp;&nbsp;<FONT color=#008000> '调用存储过程二</FONT><BR>&nbsp;&nbsp;&nbsp; .....<BR>&nbsp;&nbsp;&nbsp; Set MyComm = Nothing<BR>&nbsp; <BR>&nbsp;&nbsp;&nbsp; 一般认为，重复创建对象是效率较低的一种方法，但是经测试(测试工具为Microsoft Application Center Test)，结果出人意料：<BR>&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>方法2 &gt;= 方法1 &gt;&gt; 方法3<BR></FONT>&nbsp;&nbsp;&nbsp; 方法2的运行速度大于等于方法1(最多可高4%左右)，这两种方法的运行速度远大于方法3(最多竟高达130%)，所以建议在参数多时，采用方法1，在参数较少时，采用方法2。</P>
<P>&nbsp;&nbsp;&nbsp; 花了一天的时间，终于把我对于在ASP中调用存储过程的一些粗浅的经验形成了文字。这其中，有些是我只知其果而不明其因的，有些可能是错误的，但是，这些都是经过我亲身实践的。各位看官批判地接受吧。有不同意见，希望一定向我指明，先谢了。</P><img src ="http://www.blogjava.net/guming123416/aggbug/31916.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guming123416/" target="_blank">lovajava_ye</a> 2006-02-22 10:26 <a href="http://www.blogjava.net/guming123416/archive/2006/02/22/31916.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ASP]GetRows的用法详解！</title><link>http://www.blogjava.net/guming123416/archive/2006/02/22/31915.html</link><dc:creator>lovajava_ye</dc:creator><author>lovajava_ye</author><pubDate>Wed, 22 Feb 2006 02:25:00 GMT</pubDate><guid>http://www.blogjava.net/guming123416/archive/2006/02/22/31915.html</guid><wfw:comment>http://www.blogjava.net/guming123416/comments/31915.html</wfw:comment><comments>http://www.blogjava.net/guming123416/archive/2006/02/22/31915.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/guming123416/comments/commentRss/31915.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/guming123416/services/trackbacks/31915.html</trackback:ping><description><![CDATA[<P>大家应该都知道&nbsp;Recordset&nbsp;有个&nbsp;GetRows&nbsp;属性，但是真正使用的不多，我也是最近才用的！汗……</P>
<P>其实这个属性很简单，就是把数据集输出到一个数组中。但是实用性可不小，在这里我举一个例子说明一下GetRows的使用方法，大家举一反三能想到更多的用法！</P>
<P>比如一个分类的表&nbsp;T_Cate，结构和数据如下：</P>
<P>ID&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;Title&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;Intro<BR>-----------------------------------------<BR>1&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;新闻&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;这里是新闻<BR>2&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;教程&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;这里是教程<BR>3&nbsp;&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;下载&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;这里是下载</P>
<P>好了，表建立好了，数据也有了，下面我们就要用到GetRows咯！ </P>
<P>
<P><SPAN class=code style="WIDTH: 502px; HEIGHT: 124px"></P>
<P>
<P>Dim&nbsp;Rs_Cate<BR>Dim&nbsp;Arr_Cate<BR>Set&nbsp;Rs_Cate=Conn.ExeCute("SELECT&nbsp;ID,Title,Intro&nbsp;FROM&nbsp;T_Cate&nbsp;ORDER&nbsp;BY&nbsp;ID&nbsp;ASC")<BR>Arr_Cate=Rs_Cate.GetRows<BR>Set&nbsp;Rs_Cate=Nothing</P></SPAN>
<P></P>
<P>好了表数据已经导出到数组了！下面我们将遍历这个数组</P>
<P><SPAN class=code style="WIDTH: 512px; HEIGHT: 138px"></P>
<P>Dim&nbsp;Arr_CateNumS,Arr_CateNumI<BR>Arr_CateNumS=Ubound(Arr_Cate,2)&nbsp;&nbsp;'得到数组中数据的下标<BR>For&nbsp;Arr_CateNumI=0&nbsp;To&nbsp;Arr_CateNumS<BR>&nbsp;&nbsp;&nbsp;&nbsp;Response.Write("ID："&amp;Arr_Cate(0,Arr_CateNumI)&amp;"&nbsp;|&nbsp;标题："&amp;Arr_Cate(1,Arr_CateNumI)&amp;"&nbsp;|&nbsp;介绍："&amp;Arr_Cate(2,Arr_CateNumI)&amp;"&lt;br&gt;")<BR>Next</P></SPAN>
<P></P>
<P>呵呵，好了，输出的数据为：<BR>ID：1&nbsp;|&nbsp;标题：新闻&nbsp;|&nbsp;介绍：这里是新闻<BR>ID：2&nbsp;|&nbsp;标题：教程&nbsp;|&nbsp;介绍：这里是教程<BR>ID：3&nbsp;|&nbsp;标题：下载&nbsp;|&nbsp;介绍：这里是下载</P>
<P>好了，具体就写这么多吧！文采不行，如果大家有什么不明白的，多用用就可以了，呵呵</P><img src ="http://www.blogjava.net/guming123416/aggbug/31915.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/guming123416/" target="_blank">lovajava_ye</a> 2006-02-22 10:25 <a href="http://www.blogjava.net/guming123416/archive/2006/02/22/31915.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>