﻿<?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-辰o(^o^)o的专栏[除非注释原创，其它文章基本来源于网络]-文章分类-数据库相关</title><link>http://www.blogjava.net/jackybu/category/543.html</link><description>&lt;a href="http://www.fastonlineusers.com"&gt;&lt;b&gt;&lt;font color=red&gt;共有&lt;script src=http://fastonlineusers.com/online.php?d=jackybu.blogjava.net&gt;&lt;/script&gt;人在同时阅读此Blog&lt;/font&gt;&lt;/b&gt;&lt;/a&gt;</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 07:45:07 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 07:45:07 GMT</pubDate><ttl>60</ttl><item><title>丢掉ODBC java与Access连接</title><link>http://www.blogjava.net/jackybu/articles/6160.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Wed, 15 Jun 2005 06:07:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/6160.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/6160.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/6160.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/6160.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/6160.html</trackback:ping><description><![CDATA[不用配置ODBC也可以连接Access。做法非常简单，只要将Url改为如下写法即可：
<DIV>String url = &nbsp;"jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=E:\\MS\\DB.mdb";</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/6160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-06-15 14:07 <a href="http://www.blogjava.net/jackybu/articles/6160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mysql导入导出数据库</title><link>http://www.blogjava.net/jackybu/articles/5808.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Thu, 09 Jun 2005 04:41:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/5808.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/5808.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/5808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/5808.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/5808.html</trackback:ping><description><![CDATA[用mysqldump <BR>把一个库导出到一个SQL文件 <BR>mysqldump db_name &gt; /path/name.sql -uroot -p <BR>如果数据库太大，压缩导出 <BR>mysqldump db_name | gzip &gt; /path/name.sql -u root -p <BR>
<P>备份全部的库 <BR>mysqldump --all-databases &gt; /path/name.sql -u root -p <BR>mysqldump --all-databases | gzip &gt; /path/name.gz -uroot -p <BR>备份一个单独或者几个表 <BR>mysqldump db_name tab_name &gt; /path/sqlname.sql -u root -p <BR>恢复数据 导入数据 <BR>mysql db_name &lt; backup-file.sql -u root -p <BR>有一种用mysql db_name &lt; backup-file.sql -u root -p <BR>第二种方法： <BR>mysql -u root -p <BR>use db_name <BR>. /path/dbname.sql <BR>这种方法保险点，因为有时我用 db_name &lt; dbname.sql有问题 <BR>用第二种方法可以的 <BR>………………………………………………………… <BR>添加mysql用户mysqlname 密码为password ，赋予dbname数据库所有权限 <BR>mysql&gt; grant all on dbname.* to mysqlname@localhost identified by 'password'; <BR>mysql &gt; grant select,insert,update,delete,create,drop on 数据库名.* to 用户(新建)@localhost identified by '密码'; <BR>或者直接修改mysql表 <BR>mysql &gt; insert into user(host,user,password) values('%','user_name',password("you password")); <BR>mysql &gt; set password for user_name=password("you_password") <BR>以上两种必须进行重载授权表(./scripts/mysql_install_db) <BR>或者在shell环境下 <BR>mysqladmin -u root password "you password" </P><img src ="http://www.blogjava.net/jackybu/aggbug/5808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-06-09 12:41 <a href="http://www.blogjava.net/jackybu/articles/5808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>取一表前N筆記錄的各种數据庫的寫法</title><link>http://www.blogjava.net/jackybu/articles/5412.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Wed, 01 Jun 2005 06:39:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/5412.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/5412.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/5412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/5412.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/5412.html</trackback:ping><description><![CDATA[<FONT face=Verdana>介紹取一表前N筆記錄的各种數据庫的寫法... <BR>1. ORACLE <BR>SELECT * FROM TABLE1 WHERE ROWNUM&lt;=N <BR>2. INFORMIX <BR>SELECT FIRST N * FROM TABLE1 <BR>3. DB2 <BR>SELECT * ROW_NUMBER() OVER(ORDER BY COL1 DESC) AS ROWNUM WHERE ROWNUM&lt;=N <BR>DB2 <BR>SELECT COLUMN FROM TABLE FETCH FIRST N ROWS ONLY <BR>4. SQL SERVER <BR>SELECT TOP N * FROM TABLE1 <BR>5. SYBASE <BR>SELECT TOP N * FROM TABLE1</FONT><img src ="http://www.blogjava.net/jackybu/aggbug/5412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-06-01 14:39 <a href="http://www.blogjava.net/jackybu/articles/5412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【讨论】JDBC中，如果ResultSet 和 Statement 不关闭的话，会有什么影响 </title><link>http://www.blogjava.net/jackybu/articles/1756.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Sat, 05 Mar 2005 15:10:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1756.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1756.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1756.html</trackback:ping><description><![CDATA[<SPAN class=postbody>感觉上好象是只要把connection给关闭了，系统就能正常运行了。 <BR>那在查询或是其实操作中，如果只关闭Connection，不作ResultSet 和 Statement 的关闭的话，对系统性能是否会有影响呢。或者是其实方面的不良影响。<BR><BR><SPAN class=postbody>如果你不使用连接池，那么就没有什么问题，一旦Connection关闭，数据库物理连接就被释放，所有相关Java资源也可以被GC回收了。 <BR>但是如果你使用连接池，那么请注意，Connection关闭并不是物理关闭，只是归还连接池，所以PreparedStatement和ResultSet都被持有，并且实际占用相关的数据库的游标资源，在这种情况下，只要长期运行，往往就会报“游标超出数据库允许的最大值”的错误，导致程序无法正常访问数据库。<BR><BR><SPAN class=postbody>补充：其实这个要看你用的是什么数据库，然后决定了你的JDBC，然后呢，决定了实现这个JDBC的方法，然后呢就决定了问题。 <BR>建议关闭。<BR><BR>不使用连接池的情况下,如果你直接关闭连接话,对应的Statement,ResultSet对象都应该由Driver Vendor来帮你关闭,即由他来进行资源的释放.这个是由JDBC3.0规范中提到的.因为有些数据库资源可能属于GC不能释放的范围. <BR>对于连接池的实现而言,有时间我看看Oracle和Postgres的实现再下定论吧.但是我认为出现上面的情况应该理解成为连接池vendor的一种没有按规范来实现的问题.如果用数据库自己实现的连接池应该不会有这样的情况出现.<BR><BR>使用连接池时也应该会关闭PreparedStatement和ResultSet，看过Apache的DBCP，它是会关的，不知道其他连接池是怎么样的。实际上，使用不使用连接池应该对开发者透明，都应该遵循Jdbc规范，从这个角度，连接池如果没有实现关闭功能应该是有问题的。</SPAN></SPAN></SPAN><img src ="http://www.blogjava.net/jackybu/aggbug/1756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-03-05 23:10 <a href="http://www.blogjava.net/jackybu/articles/1756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>数据库设计过程中一些命名规范 </title><link>http://www.blogjava.net/jackybu/articles/1579.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:43:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1579.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1579.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1579.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1579.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1579.html</trackback:ping><description><![CDATA[<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 27pt; mso-char-indent-count: 2.57"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数据库设计过程中命名规范很是重要，命名规范合理的设计能够省去开发人员很多时间去区别数据库实体。<BR><BR>数据库物理设计包括：表设计，视图设计，存储过程设计，用户自定义函数设计等等。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt; TEXT-INDENT: -18pt; mso-list: l0 level3 lfo1; tab-stops: list 77.95pt"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">1、<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">表设计命名规范：表使用</SPAN><SPAN lang=EN-US>t</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开头最好能将表根据属性分类并作好编号。</SPAN><SPAN lang=EN-US><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如：编码表可写为</SPAN><SPAN lang=EN-US>tBM001Something<SPAN style="mso-spacerun: yes">&nbsp; </SPAN>t</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为表开头，</SPAN><SPAN lang=EN-US>BM</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为业务类型，</SPAN><SPAN lang=EN-US>001</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为该类别中的第几个表</SPAN><SPAN lang=EN-US>something</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">是表的名称注释。</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt; TEXT-INDENT: -18pt; mso-list: l0 level3 lfo1; tab-stops: list 77.95pt"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">2、<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp;</SPAN></SPAN></SPAN><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">视图设计命名规范：视图设计过程中使用</SPAN><SPAN lang=EN-US>v</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开头，视图命名以制作视图的主表为准或是以视图的实现功能为准。</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如：上述</SPAN><SPAN lang=EN-US>tBM001Something </SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">为主表制作的视图</SPAN> </B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">可取名</SPAN><SPAN lang=EN-US>vBM001Something<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">或者</SPAN><SPAN lang=EN-US>vGetSomeThingInfo</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">等。</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt; TEXT-INDENT: -18pt; mso-list: l0 level3 lfo1; tab-stops: list 77.95pt"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">3、</SPAN></SPAN><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">存储过程命名规范：用户自定义存储过程使用</SPAN><SPAN lang=EN-US>p</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开头以其实现功能命名</SPAN><SPAN lang=EN-US>,<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如：</SPAN><SPAN lang=EN-US>pGetSomethingInfo<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt; TEXT-INDENT: -18pt; mso-list: l0 level3 lfo1; tab-stops: list 77.95pt"><SPAN lang=EN-US style="mso-fareast-font-family: 'Times New Roman'"><SPAN style="mso-list: Ignore">4、<SPAN style="FONT: 7pt 'Times New Roman'">&nbsp; </SPAN></SPAN></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">存储过程命名规范：用户自定义存储过程使用</SPAN><SPAN lang=EN-US>f</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开头以其实现功能命名</SPAN><SPAN lang=EN-US>,<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt 77.95pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">如：</SPAN><SPAN lang=EN-US>fGetSomethingInfo<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN></SPAN><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">此外在制作视图存储过程用户自定义函数过程中，注意写好注释。</SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><SPAN lang=EN-US><o:p>&nbsp;</o:p></SPAN></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">注释内容包括：名称，作用，调用，使用表，更新记录，设计思路，入口参数</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>/*========================================================<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;</SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">存储过程名称：</SPAN><SPAN lang=EN-US>pro_tXT005TraceLeaderSearch<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt; TEXT-INDENT: 10.55pt; mso-char-indent-count: 1.0"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">作</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">用：生成日志中资源更新情况统计分析</SPAN><SPAN lang=EN-US> <o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;</SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">调用存储过程：</SPAN><SPAN lang=EN-US>pro_tXT005TraceLeaderSearch<o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">使用表：</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>t BM001Something</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">。。。。。。</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;</SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">更新记录：</SPAN><SPAN lang=EN-US>1</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</SPAN><SPAN lang=EN-US><SPAN style="mso-tab-count: 1">&nbsp; </SPAN>cc<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="15" Month="7" Year="2004">2004-7-15</st1:chsdate><SPAN style="mso-spacerun: yes">&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">构建存储过程</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </SPAN>2</SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">、</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN>cc<SPAN style="mso-spacerun: yes">&nbsp; </SPAN><st1:chsdate w:st="on" IsROCDate="False" IsLunarDate="False" Day="6" Month="2" Year="2005">2005-2-6</st1:chsdate><SPAN style="mso-spacerun: yes">&nbsp;&nbsp;&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">修改存储过程，处理</SPAN><SPAN lang=EN-US>bug<SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">增加新的内容</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">设计思路：算法描述</SPAN><SPAN lang=EN-US><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;</SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">入</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">口</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp;&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">参</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&nbsp; </SPAN></SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">数：</SPAN><SPAN lang=EN-US> @startDate </SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">开始日期，</SPAN><SPAN lang=EN-US>@endDate </SPAN></B><B style="mso-bidi-font-weight: normal"><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">结束时间</SPAN><SPAN lang=EN-US><SPAN style="mso-spacerun: yes">&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; </SPAN><o:p></o:p></SPAN></B></P>
<P class=MsoNormal style="MARGIN: 0cm 0cm 0pt"><B style="mso-bidi-font-weight: normal"><SPAN lang=EN-US>--=========================================================*/<o:p></o:p></SPAN></B></P><img src ="http://www.blogjava.net/jackybu/aggbug/1579.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:43 <a href="http://www.blogjava.net/jackybu/articles/1579.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL Server 2000 XML之七种兵器 </title><link>http://www.blogjava.net/jackybu/articles/1576.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:34:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1576.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1576.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1576.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1576.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1576.html</trackback:ping><description><![CDATA[XML，已成为近来最热门的Web技术，它是SQL Server 2000中的重要部分。本文将综合七条SQL Server 2000中最重要的XML综合特性组成XML之七种兵器。 
<P>　　<B>兵器之一：FOR XML</B></P>
<P>　　在SQL Server 2000中，标准的T-SQL SELECT语句包括FOR XML子句，它以XML文档形式返回一个查询结果。新的FOR XML子句有三种模式——RAW，AUTO，和EXPLICIT，每个都能对XML文档格式提供附加标准的控制。</P>
<P>　　下面首先介绍“FOR XML”的使用方法。</P>
<P>　　为了从SQL Server提取XML格式的数据，T-SQL中加入了一个FOR XML命令。在查询命令中使用FOR XML命令使得查询结果以XML格式出现。FOR XML命令有三种模式：RAW，AUTO和EXPLICIT。图1所显示的SQL命令访问SQL Server提供的Pubs示例数据库。有关Pubs数据库的更多信息，请参见MSDN说明。如果我们依次指定该SQL命令的模式为三种允许的模式之一，就可以得到各种模式所支持的不同XML输出。 </P>
<P>【图1 】</P>
<P></P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>SELECT store.stor_id as Id, stor_name as Name, </P>
<P>sale.ord_num as OrderNo,sale.qty as Qty</P>
<P>FROM stores store inner join </P>
<P>sales sale on store.stor_id = sale.stor_id</P>
<P>ORDER BY stor_name</P>
<P>FOR XML ＜模式＞ </P></TD></TR></TBODY></TABLE>
<P>　　该查询命令所生成的结果包含所有销售记录及其对应的商店，结果以商店名称的字母升序排列。查询的最后加上了FOR XML命令以及具体的模式，比如FOR XML RAW。 </P>
<P>　　理想情况下，SQL命令所生成的XML文档应具有如下结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>＜Stores＞</P>
<P>＜Store Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞</P>
<P>＜/Sale OrderNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞</P>
<P>＜/Store＞</P>
<P>＜/Stores＞</P></TD></TR></TBODY></TABLE>
<P>　　下面我们来看看具体的处理方法。 </P>
<P>　　<B>RAW模式</B> </P>
<P>　　下面是指定RAW模式时结果XML文档的一个片断。</P>
<P align=center><IMG height=137 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_1.gif" width=500></P>
<P></P>
<P>　　查询结果集中每一个记录包含唯一的元素＜row＞。由于我们无法控制元素名字和文档结构，因此这种模式不是很有用。RAW模式所生成的文档结构与我们所希望的不符，而且它的用途也非常有限。 </P>
<P>　　<B>AUTO模式</B> </P>
<P>　　下面是指定AUTO模式时结果文档的一个片断： </P>
<P align=center><IMG height=255 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_2.gif" width=500></P>
<P>　　可以看到，＜Stroe＞和＜Sale＞两个元素是父-子关系，形成了我们所希望的层次结构。这种节点关系由查询中表的声明次序决定，后声明的表成为前声明表的孩子。 </P>
<P>　　再参考图1，我们可以看出查询命令所指定的别名决定了XML文档中的名字。根据这一点，我们可以控制XML文档元素、属性的名字，使得这些名字符合我们所要求的命名惯例。 </P>
<P>　　可见AUTO模式能够创建出我们所需要的XML文档。不过它存在以下缺点： </P>
<P>　　虽然可以得到层次结构，但这种层次结构是线性的，即每个父节点只能有一个子节点，反之亦然。 </P>
<P>　　通过别名指定元素名字不太方便，而且有时候会影响查询命令本身的可读性。 </P>
<P>　　无法在文档中同时生成元素和属性。要么全部是元素（通过ELEMENTS关键词指定），要么全部是属性（默认）。 EXPLICIT模式解决了上述不足。 </P>
<P><BR>　<B>EXPLICIT模式 </B></P>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE></P>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE></P>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE></P>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE></P>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE></P>　<B>EXPLICIT模式 </B>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE>　<B>EXPLICIT模式 </B>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE>　<B>EXPLICIT模式 </B>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE>　<B>EXPLICIT模式 </B>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE><BR>　<B>EXPLICIT模式 </B>
<P></P>
<P>　　EXPLICIT模式比较复杂，我们将用另外一种方法来表达图1所显示的查询。这种方法使得我们能够完全地控制查询所生成的XML文档。首先我们将介绍如何改用EXPLICIT模式编写图1所显示的查询，然后看看这种方法如何赋予我们远远超过AUTO模式的能力。 </P>
<P>　　下面是图1查询用EXPLICIT模式表达的代码： </P>
<P>【图2 】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>--商店数据<BR>SELECT 1 as Tag,<BR>NULL as Parent,<BR>s.stor_id as [store!1!Id],<BR>s.stor_name as [store!1!Name],<BR>NULL as[sale!2!OrderNo],<BR>NULL as [sale!2!Qty]<BR>FROM stores s<BR>UNION ALL<BR>-- 销售数据<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>ORDER BY [store!1!name]<BR>FOR XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　这个查询初看起来有点复杂，其实它只是把不同的数据集（即这里的Store和Sale）分解到了独立的SELECT语句里，然后再用UNION ALL操作符连结成一个查询。 </P>
<P>　　我们之所以要把查询写成上面的形式，是为了让查询结果不仅包含XML文档所描述的数据，而且还包含描述XML文档结构的元数据。上述查询所生成的表称为Universal表，sqlxml.dll生成XML文档时需要这种格式。Universal表对于编写代码的人来说是透明的，但了解这个表还是很有意义的，它将有助于代码的开发和调试。下面是Universal表的一个例子： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty<BR>1 NULL 7066 Barnum&amp;single;s NULL NULL<BR>2 1 7066 Barnum&amp;single;s A297650 50<BR>2 1 7066 Barnum&amp;single;s QA7442 375<BR>1 NULL 8042 Bookbeat NULL NULL<BR>2 1 8042 Bookbeat 423LL9 2215</TD></TR></TBODY></TABLE>
<P>　　Universal表和EXPLICIT模式查询的元数据部分都以红色表示，黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我们来仔细地分析一下它们描述的是什么。 </P>
<P>　　Tag和Parent列是XML文档层次结构方面的信息，我们可以认为图2中的每个SELECT语句代表了一个XML节点，而Tag和Parent列让我们指定节点在文档层次结构中的位置。如果在第二个SELECT语句中指定Tag为2、指定Parent为1，就表示为这些数据加上了一个值为2的标签，而这些数据的父亲是那些标签为1的数据（即第一个SELECT语句）。这就使得我们能够构造出＜Store＞和＜Sale＞之间的父-子关系，而且正如你可能猜想到的，它使得我们可以生成任意合法的XML文档结构。注意第一个SELECT命令的parent列设置成了NULL，这表示＜Store＞元素处于最顶层的位置。 </P>
<P>　　以黑色表示的数据将成为节点的属性或元素，例如，Store_ID就通过列名提供了这方面的信息。列名字中的“!”是分隔符，总共可分成四项（四个参数），其中第四个参数是可选的。这些参数描述的是： </P>
<P>　　第一个参数描述该列所属元素的名字，在这里是＜Store＞元素。 </P>
<P>　　第二个是标签编号，它指定了该列信息在XML树形结构中所处位置。 </P>
<P>　　第三个参数指定XML文档内的属性或元素名字。在这里名字指定为id。 </P>
<P>　　数据列默认被创建为参数2所指定节点的属性，即id将成为＜Store＞节点的属性。如果要指定id是＜Store＞的一个子元素，我们可以使用第四个可选的参数，这个参数的一个作用就是让我们把该项指定为元素，例如store!1!id!element。 <BR><BR>　　由于使用了UNION ALL操作符来连结SELECT语句，为了保证SQL查询的合法性，所有SELECT语句的选择结果必须具有相同数量的列。我们使用NULL关键词来补足SELECT语句，从而避免了重复数据。 </P>
<P>　　通过EXPLICIT模式查询所生成的XML文档和通过AUTO模式生成的完全相同，那么为什么要创建EXPLICIT模式查询呢？ </P>
<P>　　假设现在有人要求在XML文档中包含商店的打折信息。查看Pubs数据库，我们得知每个商店都可以有0到n范围内的折扣率。因此，一种合理的方法是在＜Store＞元素下面加上子元素＜Discount＞，这样我们就得到如下XML文档结构： </P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>＜STORES＞<BR>＜STORE Id=&amp;single;&amp;single; Name=&amp;single;&amp;single;＞<BR>＜DISCOUNT Type=&amp;single;&amp;single; LowQty=&amp;single;&amp;single; HighQty=&amp;single;&amp;single;＞<BR>＜AMOUNT＞＜/AMOUNT＞<BR>＜/DISCOUNT＞<BR>＜SALE OrdNo=&amp;single;&amp;single; Qty=&amp;single;&amp;single;＞<BR>＜/SALE＞<BR>＜/STORE＞<BR>＜/STORES＞ </TD></TR></TBODY></TABLE>
<P>　　这里的改动包括： </P>
<P>　　要在＜Sale＞元素所在的层次增加一个XML元素＜Discount＞，即＜Discount＞是＜Stroe＞的子元素。 </P>
<P>　　Amount嵌套在＜Discount＞里面，但不应该是＜Discount＞元素的属性。 <BR><BR>　　在AUTO模式中是不可能实现这些改动的。 </P>
<P>　　下面是创建这个新XML文档的EXPLICIT模式查询： </P>
<P>【图 2A】</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>SELECT 1 as Tag, NULL as Parent,<BR>s.stor_id as [Store!1!id],<BR>s.stor_name as [Store!1!name],<BR>NULL as [Sale!2!orderno],<BR>NULL as [Sale!2!1ty],<BR>NULL as [Discount!3!type],<BR>NULL as [Discount!3!lowqty],<BR>NULL as [Discount!3!highqty],<BR>NULL as [Discount!3!amount!element]<BR>FROM stores s<BR>UNION ALL<BR>SELECT 2, 1,<BR>s.stor_id,<BR>s.stor_name,<BR>sa.ord_num,<BR>sa.qty,<BR>NULL,<BR>NULL,<BR>NULL,<BR>NULL<BR>FROM stores s, sales sa<BR>WHERE s.stor_id = sa.stor_id<BR>UNION ALL<BR>SELECT 3, 1,<BR>NULL,<BR>s.stor_name,<BR>NULL,<BR>NULL,<BR>d.discounttype,<BR>d.lowqty,<BR>d.highqty,<BR>d.discount<BR>FROM stores s, discounts d<BR>WHERE s.stor_id = d.stor_id<BR>ORDER BY [store!1!name]<BR>For XML EXPLICIT </TD></TR></TBODY></TABLE>
<P>　　为了创建图2A所显示的EXPLICIT模式查询，我们对图2的查询进行了如下修改： </P>
<P>　　增加了第三个子查询提取折扣数据，通过Tag列声明这些数据的标签值为3。 </P>
<P>　　通过指定Parent列为1将折扣数据设置成＜Store＞元素的子元素。 </P>
<P>　　注意在第三个SELECT子查询中我们只包含了那些必需的列，并用NULL补足空列。这个子查询包含store_name列，虽然Discount元素并不要用到这个列，但如果把这个列也设置为NULL，则结果Universal表将不会按照解析器所要求的那样以节点升序排序（不妨自己试一下看看）。Universal表的排序列也可以用Tag列替代。 </P>
<P>　　为维持结果Universal表的完整性，第一、二两个SELECT语句也用NULL补足以反映为折扣数据增加的列。 </P>
<P>　　为指定新折扣列的元数据修改了第一个SELECT语句。 </P>
<P>　　通过在第四个参数中声明element指定Amount列为Discount的一个元素（element是可在第四个参数中声明的多个指令之一）。 <BR><BR>　　下面这个XML文档只能用EXPLICIT模式生成： </P>
<P align=center><IMG height=288 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_3.gif" width=500></P>
<P></P>
<P>　　结果XML文档中不会显示出NULL数据，如折扣lowqty和highqty。</P>
<P>　　看来上面的介绍，大家可能已经对FOR XML的语法有所了解。通过FOR XML 我们在能够在Query Analyzer 中直接返回一个XML格式的数据或者通过其他多样化表现方式将XML格式的数据显示出来，比如可以将数据显示在浏览器上。下面这个例子就使用FOR XML和ADO将数据输出到浏览器的例子。</P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>
<P>Dim adoConn<BR>Set adoConn = Server.CreateObject("ADODB.Connection")</P>
<P>Dim sConn<BR>sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"<BR>adoConn.ConnectionString = sConn<BR>adoConn.CursorLocation = adUseClient<BR>adoConn.Open</P>
<P>Dim adoCmd<BR>Set adoCmd = Server.CreateObject("ADODB.Command")<BR>Set adoCmd.ActiveConnection = adoConn</P>
<P>Dim sQuery<BR>‘定义 FOR XML的查询。具体的语法在以后的章节中将详细介绍。<BR>sQuery = "＜ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'＞＜sql:query＞SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO＜/sql:query＞＜/ROOT＞"</P>
<P>‘建立ADODB Stream 对象，ADODB Stream 对象需要ADO2.5以上版本支持，它可以将记录集转换为数据流。<BR>Dim adoStreamQuery<BR>Set adoStreamQuery = Server.CreateObject("ADODB.Stream")<BR>adoStreamQuery.Open<BR>adoStreamQuery.WriteText sQuery, adWriteChar<BR>adoStreamQuery.Position = 0<BR>adoCmd.CommandStream = adoStreamQuery<BR>adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"</P>
<P>Response.write "Pushing XML to client for processing " &amp; "＜BR/＞"</P>
<P>adoCmd.Properties("Output Stream") = Response<BR>‘输出XML格式的文本<BR>Response.write "＜XML ID=MyDataIsle＞"<BR>adoCmd.Execute , , adExecuteStream<BR>Response.write "＜/XML＞"</P>
<P>‘通过IE的XML解析器，使用DOM方法将XML的文本转换为HTML<BR>＜SCRIPT language="VBScript" For="window" Event="onload"＞</P>
<P>Dim xmlDoc<BR>Set xmlDoc = MyDataIsle.XMLDocument<BR>xmlDoc.resolveExternals=false<BR>xmlDoc.async=false</P>
<P>Dim root, child<BR>Set root = xmlDoc.documentElement</P>
<P>For each child in root.childNodes<BR>dim OutputXML<BR>OutputXML = document.all("log").innerHTML<BR>document.all("log").innerHTML = OutputXML &amp; "＜LI＞" &amp; child.getAttribute("ProductName") &amp; "＜/LI＞"<BR>Next</P>
<P>＜/SCRIPT＞ </SPAN><BR></P></TD></TR></TBODY></TABLE><STRONG>兵器之二：XPath </STRONG>
<P>　　W3C 于 1999 年 10 月 8 日提出的 XPath 语言规范，它是一种基于XML的查询语言，它能在XML文挡中处理数据。SQL Server 2000 中实现的是该规范的子集。它把table和views作为XML的组件，并把columns作为XML属性。SQL Server 2000的XML支持IIS使用URL或者模板的方式提交到SQL Server处理Xpath查询，并返回XML的结果。 </P>
<P><B>　　支持的功能 </B></P>
<P>　　下表显示 SQL Server 2000 中实现的 XPath 语言的功能。</P>
<TABLE cellSpacing=0 cols=3 cellPadding=0 rules=all width=600 bgColor=#ffffff border=0 frame=box>
<TBODY>
<TR vAlign=top>
<TH class=label width="33%">功能</TH>
<TH class=label width="33%">项目</TH></TR>
<TR vAlign=top>
<TD width="33%">轴</TD>
<TD width="33%"><B>attribute</B>、<B>child</B>、<B>parent</B> 和 <B>self</B> 轴</TD></TR>
<TR vAlign=top>
<TD width="33%">包括连续谓词和嵌套谓词在内的布尔值谓词</TD>
<TD width="33%">&nbsp;</TD></TR>
<TR vAlign=top>
<TD width="33%">所有关系运算符</TD>
<TD width="33%">=, !=, ＜, ＜=, ＞, ＞=</TD></TR>
<TR vAlign=top>
<TD width="33%">算术运算符</TD>
<TD width="33%">+, -, *, div</TD></TR>
<TR vAlign=top>
<TD width="33%">显式转换函数</TD>
<TD width="33%"><B>number()</B>、<B>string()</B>、<B>Boolean()</B></TD></TR>
<TR vAlign=top>
<TD width="33%">布尔运算符</TD>
<TD width="33%">AND, OR</TD></TR>
<TR vAlign=top>
<TD width="33%">布尔函数</TD>
<TD width="33%"><B>true()</B>、<B>false()</B>、<B>not()</B></TD></TR>
<TR vAlign=top>
<TD width="33%">XPath 变量</TD>
<TD width="33%">&nbsp;</TD></TR></TBODY></TABLE><BR><B>　　不支持的功能</B> 
<P>　　下表显示 SQL Server 2000 中没有实现的 XPath 语言的功能。</P>
<TABLE cellSpacing=0 cols=2 cellPadding=0 rules=all width=600 bgColor=#ffffff border=0 frame=box>
<TBODY>
<TR>
<TH class=label vAlign=top width="41%">功能</TH>
<TH class=label vAlign=top width="59%">项目</TH></TR>
<TR>
<TD vAlign=top width="41%">轴</TD>
<TD vAlign=top width="59%"><B>ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-sibling</B></TD></TR>
<TR>
<TD width="41%" height=25>数值谓词</TD>
<TD vAlign=top width="59%">&nbsp;</TD></TR>
<TR>
<TD width="41%" height=25>算术运算符</TD>
<TD vAlign=top width="59%">mod</TD></TR>
<TR>
<TD vAlign=top width="41%">节点函数</TD>
<TD vAlign=top width="59%"><B>ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-sibling</B></TD></TR>
<TR>
<TD vAlign=top width="41%">字符串函数</TD>
<TD vAlign=top width="59%"><B>string()、concat()、starts-with()、contains()、substring-before()、substring-after()、substring()、string-length()、normalize()、translate()</B></TD></TR>
<TR>
<TD width="41%" height=25>布尔函数</TD>
<TD width="59%"><B>lang()</B></TD></TR>
<TR>
<TD width="41%" height=25>数字函数</TD>
<TD width="59%"><B>sum()、floor()、ceiling()、round()</B></TD></TR>
<TR>
<TD width="41%" height=25>Union 运算符</TD>
<TD width="59%">|</TD></TR></TBODY></TABLE>
<P><B>　　</B>XPath 查询是以表达式的形式指定的。位置路径是一种比较常用表达式，用以选择相对于上下文节点的节点集。位置路径表达式的求值结果是节点集。 <BR></P>
<TABLE cellSpacing=0 cellPadding=0 width=600 bgColor=#ffffff border=0>
<TBODY>
<TR>
<TD>XML 文档<BR>＜root＞<BR>&nbsp;&nbsp;＜order productid="Prod-28" unitprice="45.6" quantity="15"＞<BR>&nbsp;&nbsp;＜discount＞0.25＜/discount＞<BR>&nbsp;&nbsp;＜/order＞ <BR>&nbsp;&nbsp;＜order productid="Prod-39" unitprice="18" quantity="21"＞<BR>&nbsp;&nbsp;＜discount＞0.25＜/discount＞ <BR>&nbsp;&nbsp;＜/order＞<BR>&nbsp;&nbsp;＜order productid="Prod-46" unitprice="12" quantity="2"＞ <BR>&nbsp;&nbsp;＜discount＞0.25＜/discount＞<BR>&nbsp;&nbsp;＜/order＞ <BR>＜/root＞ </TD></TR></TBODY></TABLE>
<P>　　下面是查询该XML 文档的XPath位置路径表达式，它的含义是返回根节点下所有＜ROOT＞子元素下的ProductID属性的属性值为 "prod-39"的 ＜order＞ 元素。</P>
<P align=center><IMG height=283 src="http://soft.yesky.com/SoftChannel/72342371928965120/20020722/fangz20722_4.gif" width=425></P>
<P><B>　　位置路径的类型</B> <BR><BR>　　可以分为绝对位置路径和相对位置路径。 <BR><BR>　　绝对位置路径以文档的根节点开始，由斜杠 (/) 组成，后面可以是相对位置路径。斜杠 (/) 选定文档的根节点。 <BR><BR>　　相对位置路径以文档的上下文节点（Context）开始，由斜杠 (/) 所分开的一个或多个位置步骤序列组成。每个步骤都选定相对于上下文节点的节点集。初始步骤序列选定相对于上下文节点的节点集。节点集中的每个节点都用作后续步骤的上下文节点。由后续步骤标识的节点集联接在一起。例如，child::Order/child::OrderDetail 选定上下文节点的＜order＞ 子元素的 ＜orderdetail＞ 子元素。 </P>
<P>　　位置步骤 （绝对或相对）位置路径由包含下面三部分的位置步骤组成： </P>
<P><B>　　轴 </B></P>
<P>　　轴指定位置步骤选定的节点与上下文节点之间的树关系。SQL Server 2000 支持 parent、child、attribute 及 self 轴。 </P>
<P>　　如果在位置路径中指定 child 轴，查询选定的所有节点都将是上下文节点的子节点。<BR>比如说要查询从当前的上下文节点中选定所有 ＜Order＞节点的子节点,可以使用 child:: Order </P>
<P>　　如果指定 parent 轴，选定的节点将是上下文节点的父节点。 <BR>比如说要查询从当前的上下文节点中选定所有 ＜Order＞节点的父节点,可以使用 parent:: Order </P>
<P>　　如果指定 attribute 轴，选定的节点是上下文节点的属性。<BR>比如说要查询从当前的上下文节点中选定所有 ＜Order＞节点的属性,可以使用 attribute:: Order </P>
<P><B>　　节点测试 </B></P>
<P>　　节点测试指定位置步骤选定的节点类型。每个轴（child、parent、attribute 和 self）都具有主要节点类型。对于 attribute 轴，主要节点类型是 ＜attribute＞。对于 parent、child 和 self 轴，主要节点类型是 ＜element＞。</P>
<P>　　例如，如果位置路径指定 child::Order，则将选定上下文节点的 ＜Order＞ 子元素。因为 child 轴以 ＜element＞ 为其主要节点类型，而且如果Order是 ＜element＞ 节点，则节点测试Order为 TRUE。</P>
<P><B>　　选择谓词（零个或多个）</B></P>
<P>　　谓词围绕着轴筛选节点集。在 XPath 表达式中指定选择谓词与在 SELECT 语句中指定 WHERE 子句相似。谓词在括号中指定。应用在选择谓词中指定的测试将对节点测试返回的节点进行筛选。对于要筛选的节点集中的每个节点，在对谓词表达式取值时将此节点作为上下文节点，将节点集中的节点数作为上下文大小。如果谓词表达式对此节点取值为 TRUE，则此节点将包括在最后所得到的节点集中。</P>
<P>　　例如： <BR>　　1. Child::Order [attribute::ProductID="Prod-39"] 表示从当前的上下文节点中选定ProductID属性值为Prod-39的所有 ＜order＞子节点。</P>
<P>　　2. Child::Order [child:: Discount] 表示从当前的上下文节点中选定包含一个或多个 ＜Discount＞ 子节点的所有 ＜Order＞ 子节点。</P>
<P>　　3. Child::Order [not(child:: Discount)] 表示从当前的上下文节点中选定不包含 ＜Discount＞ 子节点的所有 ＜Order＞ 子节点。</P>
<P><B>　　位置步骤的语法</B><BR><BR>　　是用两个冒号 (::) 分开的轴名和节点测试，后面是分别放在方括号中的零个或多个表达式。</P>
<P>　　例如，在 XPath 表达式（位置路径）child::Order[attribute::ProductID="prod-39"]中，选定上下文节点的所有 ＜order＞ 子元素。然后将谓词中的测试应用于节点集，将只返回 ProductID属性的属性值为 "prod-39"的 ＜order＞ 元素节点。 </P>
<P><B>　　缩略语法 </B></P>
<P>　　Sqlservr2000支持下面的位置路径缩略语法: <BR>　　attribute::可以缩略为 @。 <BR>　　比如：[attribute::ProductID="Prod-39"] 可以缩写成 [@ProductID =" Prod-39"] </P>
<P>　　child::可以在位置步骤中省略。<BR>　　比如：位置路径child::ROOT/child::Orde可以缩写成 ROOT /Order </P>
<P>　　self::node() 可缩略为一个句点 (.)，而 parent::node() 可缩略两个句点 (..)。</P>
<P>　　所以 /child::ROOT/child::Order[attribute::ProductID="prod-39"]也可以缩写成 /ROOT/Order[@ProductID="prod-39"] </P></SPAN><img src ="http://www.blogjava.net/jackybu/aggbug/1576.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:34 <a href="http://www.blogjava.net/jackybu/articles/1576.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一问一答：存储过程经典问题 </title><link>http://www.blogjava.net/jackybu/articles/1575.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:30:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1575.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1575.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1575.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1575.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1575.html</trackback:ping><description><![CDATA[<P>只涉及到一个表：xkb_treeNode</P>
<P>表结构是这样：<BR>node_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //节点id<BR>parentNode_id&nbsp;&nbsp;&nbsp; int&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //父节点id<BR>node_text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; varchar&nbsp; //节点内容<BR>isModule&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bit&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //是否叶子节点</P>
<P>现在保存的数据有：</P>
<P>node_id&nbsp; parentNode_id&nbsp; node_text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; isModule<BR>&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语言与文学&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<BR>&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1&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; 0<BR>&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; -1&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; 0<BR>&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&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; 0<BR>&nbsp;&nbsp; 5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&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; 0<BR>&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5&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; 0<BR>&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 初中英语&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0<BR>&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 特斯塔&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测定是2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1</P>
<P><BR>现在问题是：<BR>能否通过做一个存储过程，<BR>根据表中的isModule字段的取值（取值为1的表示最终叶子结点），<BR>比如“特斯塔”为叶子节点，层层向上递进找到”特斯塔“的祖先节点：<BR>特斯塔-〉初中英语-〉英语-〉外语-〉语言与文学<BR>即通过”特斯塔“找到”语言与文学“来</P>
<P>最终返回的形态为：<BR>叶子节点id&nbsp; 父节点id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 节点名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 祖先节点名称&nbsp; 祖先节点id<BR>&nbsp;&nbsp; 8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 特斯塔&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语言与文学&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测定是2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 语言与文学&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1<BR>&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 测试3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 数学&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2</P>
<P>&nbsp;</P>
<P>/////////////////////////////////////////////////////////////////////////<BR>正确答案：</P>
<P>&nbsp;--生成测试数据<BR>create table xkb_treeNode(<BR>node_id&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int,<BR>parentNode_id&nbsp;&nbsp; int,<BR>node_textvarchar(10),<BR>isModulebit)</P>
<P><BR>insert into xkb_treeNode select 1&nbsp; ,-1,'语言与文学',0<BR>insert into xkb_treeNode select 2&nbsp; ,-1,'数学',0<BR>insert into xkb_treeNode select 3&nbsp; ,-1,'技术',0<BR>insert into xkb_treeNode select 4&nbsp; , 1,'语文',0<BR>insert into xkb_treeNode select 5&nbsp; , 1,'外语',0<BR>insert into xkb_treeNode select 6&nbsp; , 5,'英语',0<BR>insert into xkb_treeNode select 7&nbsp; , 6,'初中英语',0<BR>insert into xkb_treeNode select 8&nbsp; , 7,'特斯塔'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ,1<BR>insert into xkb_treeNode select 9&nbsp; , 4,'测定是2',1<BR>insert into xkb_treeNode select 10 , 2,'测试3',1</P>
<P><BR>--创建存储过程<BR>create procedure sp_test<BR>as<BR>begin<BR>&nbsp;&nbsp; select <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.node_id,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.parentNode_id,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.node_text,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.node_id&nbsp;&nbsp; as ancestor_id&nbsp; ,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b.node_text as ancestor_text&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <BR>&nbsp;&nbsp; into <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #t<BR>&nbsp;&nbsp; from <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xkb_treeNode a,xkb_treeNode b<BR>&nbsp;&nbsp; where<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.parentNode_id = b.node_id and a.isModule = 1&nbsp; <BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; while(exists(select 1 from xkb_treeNode a,#t b where a.node_id=ancestor_id and a.parentNode_id != -1))<BR>&nbsp;&nbsp; begin<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; update #t<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ancestor_id&nbsp;&nbsp; = b.p_id,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ancestor_text = b.p_text<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #t a,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (select <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.node_id,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.node_id as p_id,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; d.node_text as p_text <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xkb_treeNode c,xkb_treeNode d <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c.parentNode_id = d.node_id) b<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; a.ancestor_id = b.node_id<BR>&nbsp;&nbsp; end<BR>&nbsp;&nbsp; <BR>&nbsp;&nbsp; select * from #t order by node_id<BR>end</P>
<P><BR>--执行存储过程，结果楼主自己看<BR>exec sp_test<BR></P><img src ="http://www.blogjava.net/jackybu/aggbug/1575.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:30 <a href="http://www.blogjava.net/jackybu/articles/1575.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL Server联机丛书：存储过程及其创建 </title><link>http://www.blogjava.net/jackybu/articles/1574.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:28:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1574.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1574.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1574.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1574.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1574.html</trackback:ping><description><![CDATA[存储过程可以使得对数据库的管理、以及显示关于数据库及其用户信息的工作容易得多。存储过程是 SQL 语句和可选控制流语句的预编译集合，以一个名称存储并作为一个单元处理。存储过程存储在数据库内，可由应用程序通过一个调用执行，而且允许用户声明变量、有条件执行以及其它强大的编程功能。 
<P>存储过程可包含程序流、逻辑以及对数据库的查询。它们可以接受参数、输出参数、返回单个或多个结果集以及返回值。 </P>
<P>可以出于任何使用 SQL 语句的目的来使用存储过程，它具有以下优点： 
<UL type=disc>
<LI>可以在单个存储过程中执行一系列 SQL 语句。<BR>
<LI>可以从自己的存储过程内引用其它存储过程，这可以简化一系列复杂语句。<BR>
<LI>存储过程在创建时即在服务器上进行编译，所以执行起来比单个 SQL 语句快。 </LI></UL>
<P>存储过程的功能取决于数据库所提供的功能。</P>
<H1>创建存储过程</H1>
<P>可使用 Transact-SQL 语句 CREATE PROCEDURE 创建存储过程。创建存储过程前，请考虑下列事项： 
<UL type=disc>
<LI>不能将 CREATE PROCEDURE 语句与其它 SQL 语句组合到单个批处理中。<BR>
<LI>创建存储过程的权限默认属于数据库所有者，该所有者可将此权限授予其他用户。<BR>
<LI>存储过程是数据库对象，其名称必须遵守标识符规则。<BR>
<LI>只能在当前数据库中创建存储过程。 </LI></UL>
<P>创建存储过程时，应指定： 
<UL type=disc>
<LI>所有输入参数和向调用过程或批处理返回的输出参数。<BR>
<LI>执行数据库操作（包括调用其它过程）的编程语句。<BR>
<LI>返回至调用过程或批处理以表明成功或失败（以及失败原因）的状态值。 </LI></UL>
<H5>系统存储过程</H5>
<P>Microsoft® SQL Server™ 2000 中的许多管理活动是通过一种称为<!--GLOSSARY--><NOBR><U><FONT color=#800080>系统存储过程</FONT></U></NOBR><!--/GLOSSARY-->的特殊过程执行的。系统存储过程在 <B>master</B> 数据库中创建并存储，带有 <B>sp_</B> 前缀。可从任何数据库中执行系统存储过程，而无需使用 <B>master </B>数据库名称来完全限定该存储过程的名称。</P>
<P>强烈建议您不要创建以 <B>sp_ </B>为前缀的存储过程。SQL Server 始终按照下列顺序查找以 <B>sp_ </B>开头的存储过程： 
<OL>
<LI>在 <B>master</B> 数据库中查找存储过程。<BR>
<LI>根据所提供的任何限定符（数据库名称或所有者）查找该存储过程。<BR>
<LI>如果未指定所有者，则使用 <B>dbo</B> 作为所有者查找该存储过程。 </LI></OL>
<P>因此，虽然当前数据库中可能存在带 <B>sp_</B> 前缀的用户创建的存储过程，但总会先检查 <B>master</B> 数据库（即使该存储过程已用数据库名称限定）。</P>
<P class=indent><!--IMPORTANT--></P>
<P>&nbsp;<B class=notes>重要</B>&nbsp;&nbsp;如果用户创建的存储过程与系统存储过程同名，则永远不执行用户创建的存储过程。</P><!--/IMPORTANT-->
<P></P>
<H5>分组</H5>
<P>如果将一个不同的标识号赋予某过程，则可以用与现有某存储过程相同的名称创建该过程，这样可允许将这些过程进行逻辑分组。同名的分组过程可以同时删除。在同一应用程序中使用的过程一般都以该方式分组。例如，用于 <B>my_app </B>应用程序的过程可能被命名为 <B>my_proc;1</B>、<B>my_proc;2 </B>等。删除 <B>my_proc</B> 即删除该整个组。将过程分组后，就无法删除该组内的单个过程。</P>
<H5>临时存储过程</H5>
<P>专用和全局临时存储过程与临时表类似，都可以用向该过程名称添加 # 和 ## 前缀的方法进行创建。# 表示本地临时存储过程，## 表示全局临时存储过程。SQL Server 关闭后，这些过程将不再存在。</P>
<P>临时存储过程在连接到 SQL Server 的早期版本时很有用，这些早期版本不支持再次使用 Transact-SQL 语句或批处理执行计划。连接到 SQL Server 2000 的应用程序应使用 <B>sp_executesql</B> 系统存储过程，而不使用临时存储过程。有关更多信息，请参见<FONT color=#800080>执行计划的高速缓存和重新使用</FONT>。 </P>
<P>只有创建本地临时过程的连接才能执行该过程，当该连接关闭（用户从 SQL Server 中注销）时，将自动删除该过程。</P>
<P>任何连接都可执行全局临时存储过程。只有创建该过程的用户所用的连接关闭，并且所有其它连接所用的该过程的当前执行版本运行完毕后，全局临时存储过程才不再存在。一旦用于创建该过程的连接关闭，将不再允许启动执行该全局临时存储过程。只允许那些已启动执行该存储过程的连接完成该过程的运行。</P>
<P>如果直接在 <B>tempdb</B> 数据库中创建没有 # 或 ## 前缀的存储过程，则由于每次启动 SQL Server 时 <B>tempdb</B> 都要重新创建，因此当关闭 SQL Server 时将自动删除该存储过程。直接在 <B>tempdb</B> 中创建的过程即使在创建该过程的连接终止后也会存在。与任何其它对象一样，可向其他用户授予、拒绝和废除执行该临时存储过程的权限。</P>
<H1>CREATE PROCEDURE</H1>
<P>创建存储过程，存储过程是保存起来的可以接受和返回用户提供的参数的 Transact-SQL 语句的集合。</P>
<P>可以创建一个过程供永久使用，或在一个会话中临时使用（局部临时过程），或在所有会话中临时使用（全局临时过程）。</P>
<P>也可以创建在 Microsoft® SQL Server™ 启动时自动运行的存储过程。</P>
<H5>语法</H5>
<P>CREATE PROC [ EDURE ] <I>procedure_name </I>[ <B>; </B><I>number </I>]<BR>&nbsp;&nbsp;&nbsp;&nbsp;[ { @<I>parameter data_type </I>}<I><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</I>[ VARYING ] [ <B>= </B><I>default </I>] [ OUTPUT ]<B><BR>&nbsp;&nbsp;&nbsp;&nbsp;</B>] [ <B>,</B>...<I>n </I>] <BR><BR>[ WITH<BR>&nbsp;&nbsp;&nbsp;&nbsp;{ RECOMPILE | ENCRYPTION | RECOMPILE <B>,</B> ENCRYPTION } ] <BR><BR>[ FOR REPLICATION ] <BR><BR>AS <I>sql_statement</I> [ ...<I>n </I>] <BR></P>
<H5>参数</H5>
<P><I>procedure_name</I></P>
<P class=indent>新存储过程的名称。过程名必须符合标识符规则，且对于数据库及其所有者必须唯一。有关更多信息，请参见<FONT color=#800080>使用标识符</FONT>。</P>
<P class=indent>要创建局部临时过程，可以在 <I>procedure_name</I> 前面加一个编号符 (#<I>procedure_name</I>)，要创建全局临时过程，可以在 <I>procedure_name</I> 前面加两个编号符 (##<I>procedure_name</I>)。完整的名称（包括 # 或 ##）不能超过 128 个字符。指定过程所有者的名称是可选的。</P>
<P><B>;</B><I>number</I></P>
<P class=indent>是可选的整数，用来对同名的过程分组，以便用一条 DROP PROCEDURE 语句即可将同组的过程一起除去。例如，名为 orders 的应用程序使用的过程可以命名为 <B>orderproc</B>;1、<B>orderproc</B>;2 等。DROP PROCEDURE <B>orderproc</B> 语句将除去整个组。如果名称中包含定界标识符，则数字不应包含在标识符中，只应在 <I>procedure_name</I> 前后使用适当的定界符。</P>
<P>@<I>parameter</I></P>
<P class=indent>过程中的参数。在 CREATE PROCEDURE 语句中可以声明一个或多个参数。用户必须在执行过程时提供每个所声明参数的值（除非定义了该参数的默认值）。存储过程最多可以有 2.100 个参数。</P>
<P class=indent>使用 @ 符号作为第一个字符来指定参数名称。参数名称必须符合标识符的规则。每个过程的参数仅用于该过程本身；相同的参数名称可以用在其它过程中。默认情况下，参数只能代替常量，而不能用于代替表名、列名或其它数据库对象的名称。有关更多信息，请参见 <FONT color=#800080>EXECUTE</FONT>。 </P>
<P><I>data_type</I></P>
<P class=indent>参数的数据类型。所有数据类型（包括 <B>text</B>、<B>ntext</B> 和 <B>image</B>）均可以用作存储过程的参数。不过，<B>cursor</B> 数据类型只能用于 OUTPUT 参数。如果指定的数据类型为 <B>cursor</B>，也必须同时指定 VARYING 和 OUTPUT 关键字。有关 SQL Server 提供的数据类型及其语法的更多信息，请参见<FONT color=#0000ff>数据类型</FONT>。 </P>
<P class=level2><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;对于可以是 <B>cursor</B> 数据类型的输出参数，没有最大数目的限制。</P><!--/NOTE-->
<P></P>
<P>VARYING</P>
<P class=indent>指定作为输出参数支持的结果集（由存储过程动态构造，内容可以变化）。仅适用于游标参数。</P>
<P><I>default</I></P>
<P class=indent>参数的默认值。如果定义了默认值，不必指定该参数的值即可执行过程。默认值必须是常量或 NULL。如果过程将对该参数使用 LIKE 关键字，那么默认值中可以包含通配符（%、_、[] 和 [^]）。</P>
<P>OUTPUT</P>
<P class=indent>表明参数是返回参数。该选项的值可以返回给 EXEC[UTE]。使用 OUTPUT 参数可将信息返回给调用过程。<B>Text</B>、<B>ntext</B> 和 <B>image</B> 参数可用作 OUTPUT 参数。使用 OUTPUT 关键字的输出参数可以是游标占位符。</P>
<P><I>n</I></P>
<P class=indent>表示最多可以指定 2.100 个参数的占位符。</P>
<P>{RECOMPILE | ENCRYPTION | RECOMPILE<B>, </B>ENCRYPTION}</P>
<P class=indent>RECOMPILE 表明 SQL Server 不会缓存该过程的计划，该过程将在运行时重新编译。在使用非典型值或临时值而不希望覆盖缓存在内存中的执行计划时，请使用 RECOMPILE 选项。</P>
<P class=indent>ENCRYPTION 表示 SQL Server 加密 <B>syscomments</B> 表中包含 CREATE PROCEDURE 语句文本的条目。使用 ENCRYPTION 可防止将过程作为 SQL Server 复制的一部分发布。</P>
<P class=level2><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;在升级过程中，SQL Server 利用存储在 <B>syscomments </B>中的加密注释来重新创建加密过程。</P><!--/NOTE-->
<P></P>
<P>FOR REPLICATION</P>
<P class=indent>指定不能在订阅服务器上执行为复制创建的存储过程。.使用 FOR REPLICATION 选项创建的存储过程可用作存储过程筛选，且只能在复制过程中执行。本选项不能和 WITH RECOMPILE 选项一起使用。</P>
<P>AS</P>
<P class=indent>指定过程要执行的操作。</P>
<P><I>sql_statement</I></P>
<P class=indent>过程中要包含的任意数目和类型的 Transact-SQL 语句。但有一些限制。</P>
<P><I>n</I></P>
<P class=indent>是表示此过程可以包含多条 Transact-SQL 语句的占位符。</P>
<H5>注释</H5>
<P>存储过程的最大大小为 128 MB。</P>
<P>用户定义的存储过程只能在当前数据库中创建（临时过程除外，临时过程总是在 <B>tempdb </B>中创建）。在单个批处理中，CREATE PROCEDURE 语句不能与其它 Transact-SQL 语句组合使用。 </P>
<P>默认情况下，参数可为空。如果传递 NULL 参数值并且该参数在 CREATE 或 ALTER TABLE 语句中使用，而该语句中引用的列又不允许使用 NULL，则 SQL Server 会产生一条错误信息。为了防止向不允许使用 NULL 的列传递 NULL 参数值，应向过程中添加编程逻辑或为该列使用默认值（使用 CREATE 或 ALTER TABLE 的 DEFAULT 关键字)。</P>
<P>建议在存储过程的任何 CREATE TABLE 或 ALTER TABLE 语句中都为每列显式指定 NULL 或 NOT NULL，例如在创建临时表时。ANSI_DFLT_ON 和 ANSI_DFLT_OFF 选项控制 SQL Server 为列指派 NULL 或 NOT NULL 特性的方式（如果在 CREATE TABLE 或 ALTER TABLE 语句中没有指定的话）。如果某个连接执行的存储过程对这些选项的设置与创建该过程的连接的设置不同，则为第二个连接创建的表列可能会有不同的为空性，并且表现出不同的行为方式。如果为每个列显式声明了 NULL 或 NOT NULL，那么将对所有执行该存储过程的连接使用相同的为空性创建临时表。</P>
<P>在创建或更改存储过程时，SQL Server 将保存 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 的设置。执行存储过程时，将使用这些原始设置。因此，所有客户端会话的 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 设置在执行存储过程时都将被忽略。在存储过程中出现的 SET QUOTED_IDENTIFIER 和 SET ANSI_NULLS 语句不影响存储过程的功能。</P>
<P>其它 SET 选项（例如 SET ARITHABORT、SET ANSI_WARNINGS 或 SET ANSI_PADDINGS）在创建或更改存储过程时不保存。如果存储过程的逻辑取决于特定的设置，应在过程开头添加一条 SET 语句，以确保设置正确。从存储过程中执行 SET 语句时，该设置只在存储过程完成之前有效。之后，设置将恢复为调用存储过程时的值。这使个别的客户端可以设置所需的选项，而不会影响存储过程的逻辑。</P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;SQL Server 是将空字符串解释为单个空格还是解释为真正的空字符串，由兼容级别设置控制。如果兼容级别小于或等于 65，SQL Server 就将空字符串解释为单个空格。如果兼容级别等于 70，则 SQL Server 将空字符串解释为空字符串。有关更多信息，请参见<B> </B><FONT color=#0000ff>sp_dbcmptlevel</FONT>。 </P><!--/NOTE-->
<P></P>
<H6>获得有关存储过程的信息</H6>
<P>若要显示用来创建过程的文本，请在过程所在的数据库中执行 <B>sp_helptext</B>，并使用过程名作为参数。 </P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;使用 ENCRYPTION 选项创建的存储过程不能使用 <B>sp_helptext</B> 查看。</P><!--/NOTE-->
<P></P>
<P>若要显示有关过程引用的对象的报表，请使用 <B>sp_depends</B>。 </P>
<P>若要为过程重命名，请使用 <B>sp_rename</B>。 </P>
<H6>引用对象</H6>
<P>SQL Server 允许创建的存储过程引用尚不存在的对象。在创建时，只进行语法检查。执行时，如果高速缓存中尚无有效的计划，则编译存储过程以生成执行计划。只有在编译过程中才解析存储过程中引用的所有对象。因此，如果语法正确的存储过程引用了不存在的对象，则仍可以成功创建，但在运行时将失败，因为所引用的对象不存在。有关更多信息，请参见<FONT color=#800080>延迟名称解析和编译</FONT>。 </P>
<H6>延迟名称解析和兼容级别</H6>
<P>SQL Server 允许 Transact-SQL 存储过程在创建时引用不存在的表。这种能力称为延迟名称解析。不过，如果 Transact-SQL 存储过程引用了该存储过程中定义的表，而兼容级别设置（通过执行 <B>sp_dbcmptlevel</B> 来设置）为 65，则在创建时会发出警告信息。而如果在运行时所引用的表不存在，将返回错误信息。有关更多信息，请参见 <FONT color=#0000ff>sp_dbcmptlevel</FONT> 和<FONT color=#800080>延迟名称解析和编译</FONT>。 </P>
<H6>执行存储过程</H6>
<P>成功执行 CREATE PROCEDURE 语句后，过程名称将存储在 <B>sysobjects </B>系统表中，而 CREATE PROCEDURE 语句的文本将存储在 <B>syscomments</B> 中。第一次执行时，将编译该过程以确定检索数据的最佳访问计划。</P>
<H6>使用 cursor 数据类型的参数</H6>
<P>存储过程只能将 <B>cursor</B> 数据类型用于 OUTPUT 参数。如果为某个参数指定了 <B>cursor</B> 数据类型，也必须指定 VARYING 和 OUTPUT 参数。如果为某个参数指定了 VARYING 关键字，则数据类型必须是 <B>cursor</B>，并且必须指定 OUTPUT 关键字。</P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;<B>cursor</B> 数据类型不能通过数据库 API（例如 OLE DB、ODBC、ADO 和 DB-Library）绑定到应用程序变量上。因为必须先绑定 OUTPUT 参数，应用程序才可以执行存储过程，所以带有 <B>cursor</B> OUTPUT 参数的存储过程不能通过数据库 API 调用。只有将 <B>cursor</B> OUTPUT 变量赋值给 Transact-SQL 局部 <B>cursor</B> 变量时，才可以通过 Transact-SQL 批处理、存储过程或触发器调用这些过程。</P><!--/NOTE-->
<P></P>
<H6>Cursor 输出参数</H6>
<P>在执行过程时，以下规则适用于 <B>cursor</B> 输出参数： 
<OL type=disc>
<LI>对于只进游标，游标的结果集中返回的行只是那些存储过程执行结束时处于或超出游标位置的行，例如： 
<OL type=disc>
<LI>在过程中的名为 RS 的 100 行结果集上打开一个非滚动游标。 <BR><BR>
<LI>过程提取结果集 RS 的头 5 行。<BR><BR>
<LI>过程返回到其调用者。<BR><BR>
<LI>返回到调用者的结果集 RS 由 RS 的第 6 到 100 行组成，调用者中的游标处于 RS 的第一行之前。 </LI></OL>
<LI>对于只进游标，如果存储过程完成后，游标位于第一行的前面，则整个结果集将返回给调用批处理、存储过程或触发器。返回时，游标将位于第一行的前面。<BR><BR>
<LI>对于只进游标，如果存储过程完成后，游标的位置超出最后一行的结尾，则为调用批处理、存储过程或触发器返回空结果集。 
<P class=level2><!--NOTE--></P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> 
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;空结果集与空值不同。</P><!--/NOTE-->
<LI>对于可滚动游标，在存储过程执行结束时，结果集中的所有行均会返回给调用批处理、存储过程或触发器。返回时，游标保留在过程中最后一次执行提取时的位置。<BR><BR>
<LI>对于任意类型的游标，如果游标关闭，则将空值传递回调用批处理、存储过程或触发器。如果将游标指派给一个参数，但该游标从未打开过，也会出现这种情况。 </LI></OL>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;关闭状态只有在返回时才有影响。例如，可以在过程中关闭游标，稍后再打开游标，然后将该游标的结果集返回给调用批处理、存储过程或触发器。</P><!--/NOTE-->
<P></P>
<H6>临时存储过程</H6>
<P>SQL Server 支持两种临时过程：局部临时过程和全局临时过程。局部临时过程只能由创建该过程的连接使用。全局临时过程则可由所有连接使用。局部临时过程在当前会话结束时自动除去。全局临时过程在使用该过程的最后一个会话结束时除去。通常是在创建该过程的会话结束时。</P>
<P>临时过程用 # 和 ## 命名，可以由任何用户创建。创建过程后，局部过程的所有者是唯一可以使用该过程的用户。执行局部临时过程的权限不能授予其他用户。如果创建了全局临时过程，则所有用户均可以访问该过程，权限不能显式废除。只有在 <B>tempdb</B> 数据库中具有显式 CREATE PROCEDURE 权限的用户，才可以在该数据库中显式创建临时过程（不使用编号符命名）。可以授予或废除这些过程中的权限。 </P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;频繁使用临时存储过程会在 <B>tempdb</B> 中的系统表上产生争用，从而对性能产生负面影响。建议使用 <B>sp_executesql</B> 代替。<B>sp_executesql</B> 不在系统表中存储数据，因此可以避免这一问题。</P><!--/NOTE-->
<P></P>
<H6>自动执行存储过程</H6>
<P>SQL Server 启动时可以自动执行一个或多个存储过程。这些存储过程必须由系统管理员创建，并在 <B>sysadmin</B> 固定服务器角色下作为后台过程执行。这些过程不能有任何输入参数。 </P>
<P>对启动过程的数目没有限制，但是要注意，每个启动过程在执行时都会占用一个连接。如果必须在启动时执行多个过程，但不需要并行执行，则可以指定一个过程作为启动过程，让该过程调用其它过程。这样就只占用一个连接。</P>
<P>在启动时恢复了最后一个数据库后，即开始执行存储过程。若要跳过这些存储过程的执行，请将启动参数指定为跟踪标记 4022。如果以最低配置启动 SQL Server（使用 <B>-f</B> 标记），则启动存储过程也不会执行。有关更多信息，请参见<FONT color=#0000ff>跟踪标记</FONT>。 </P>
<P>若要创建启动存储过程，必须作为 <B>sysadmin</B> 固定服务器角色的成员登录，并在 <B>master </B>数据库中创建存储过程。</P>
<P>使用 <B>sp_procoption </B>可以： 
<OL type=disc>
<LI>将现有存储过程指定为启动过程。<BR><BR>
<LI>停止在 SQL Server 启动时执行过程。<BR><BR>
<LI>查看 SQL Server 启动时执行的所有过程的列表。 </LI></OL>
<H6>存储过程嵌套</H6>
<P>存储过程可以嵌套，即一个存储过程可以调用另一个存储过程。在被调用过程开始执行时，嵌套级将增加，在被调用过程执行结束后，嵌套级将减少。如果超出最大的嵌套级，会使整个调用过程链失败。可用 @@NESTLEVEL 函数返回当前的嵌套级。</P>
<P>若要估计编译后的存储过程大小，请使用下列性能监视计数器。 </P>
<P>
<TABLE cols=2 cellPadding=2 rules=all width=587 border=1 frame=box>
<TBODY>
<TR vAlign=top>
<TH class=label width="51%">性能监视器对象名</TH>
<TH class=label width="49%">性能监视计数器名称</TH></TR>
<TR vAlign=top>
<TD width="51%">SQLServer：缓冲区管理器</TD>
<TD width="49%">高速缓存大小（页面数）</TD></TR>
<TR vAlign=top>
<TD width="51%">SQLServer：高速缓存管理器</TD>
<TD width="49%">高速缓存命中率</TD></TR>
<TR vAlign=top>
<TD width="51%">&nbsp;</TD>
<TD width="49%">高速缓存页</TD></TR>
<TR vAlign=top>
<TD width="51%">&nbsp;</TD>
<TD width="49%">高速缓存对象计数*</TD></TR></TBODY></TABLE><BR></P>
<P>* 各种分类的高速缓存对象均可以使用这些计数器，包括特殊 sql、准备 sql、过程、触发器等。</P>
<P>有关更多信息，请参见 <FONT color=#800080>SQL Server:Buffer Manager 对象</FONT>和 <FONT color=#800080>SQL Server:Cache Manager 对象</FONT>。 </P>
<H6>sql_statement 限制</H6>
<P>除了 SET SHOWPLAN_TEXT 和 SET SHOWPLAN_ALL 之外（这两个语句必须是批处理中仅有的语句），任何 SET 语句均可以在存储过程内部指定。所选择的 SET 选项在存储过程执行过程中有效，之后恢复为原来的设置。 </P>
<P>如果其他用户要使用某个存储过程，那么在该存储过程内部，一些语句使用的对象名必须使用对象所有者的名称限定。这些语句包括： 
<OL type=disc>
<LI>ALTER TABLE<BR>
<LI>CREATE INDEX<BR>
<LI>CREATE TABLE<BR>
<LI>所有 DBCC 语句<BR>
<LI>DROP TABLE<BR>
<LI>DROP INDEX<BR>
<LI>TRUNCATE TABLE<BR>
<LI>UPDATE STATISTICS </LI></OL>
<H5>权限</H5>
<P>CREATE PROCEDURE 的权限默认授予 <B>sysadmin</B> 固定服务器角色成员和 <B>db_owner</B> 和 <B>db_ddladmin</B> 固定数据库角色成员。<B>sysadmin </B>固定服务器角色成员和 <B>db_owner </B>固定数据库角色成员可以将 CREATE PROCEDURE 权限转让给其他用户。执行存储过程的权限授予过程的所有者，该所有者可以为其它数据库用户设置执行权限。</P>
<H5>示例</H5>
<H6>A. 使用带有复杂 SELECT 语句的简单过程</H6>
<P>下面的存储过程从四个表的联接中返回所有作者（提供了姓名）、出版的书籍以及出版社。该存储过程不使用任何参数。</P><PRE>USE pubs
IF EXISTS (SELECT name FROM sysobjects 
         WHERE name = 'au_info_all' AND type = 'P')
   DROP PROCEDURE au_info_all
GO
CREATE PROCEDURE au_info_all
AS
SELECT au_lname, au_fname, title, pub_name
   FROM authors a INNER JOIN titleauthor ta
      ON a.au_id = ta.au_id INNER JOIN titles t
      ON t.title_id = ta.title_id INNER JOIN publishers p
      ON t.pub_id = p.pub_id
GO
</PRE>
<P><B>au_info_all</B> 存储过程可以通过以下方法执行：</P><PRE>EXECUTE au_info_all
-- Or
EXEC au_info_all
</PRE>
<P>如果该过程是批处理中的第一条语句，则可使用：</P><PRE>au_info_all
</PRE>
<H6>B. 使用带有参数的简单过程</H6>
<P>下面的存储过程从四个表的联接中只返回指定的作者（提供了姓名）、出版的书籍以及出版社。该存储过程接受与传递的参数精确匹配的值。</P><PRE>USE pubs
IF EXISTS (SELECT name FROM sysobjects 
         WHERE name = 'au_info' AND type = 'P')
   DROP PROCEDURE au_info
GO
USE pubs
GO
CREATE PROCEDURE au_info 
   @lastname varchar(40), 
   @firstname varchar(20) 
AS 
SELECT au_lname, au_fname, title, pub_name
   FROM authors a INNER JOIN titleauthor ta
      ON a.au_id = ta.au_id INNER JOIN titles t
      ON t.title_id = ta.title_id INNER JOIN publishers p
      ON t.pub_id = p.pub_id
   WHERE  au_fname = @firstname
      AND au_lname = @lastname
GO
</PRE>
<P><B>au_info</B> 存储过程可以通过以下方法执行：</P><PRE>EXECUTE au_info 'Dull', 'Ann'
-- Or
EXECUTE au_info @lastname = 'Dull', @firstname = 'Ann'
-- Or
EXECUTE au_info @firstname = 'Ann', @lastname = 'Dull'
-- Or
EXEC au_info 'Dull', 'Ann'
-- Or
EXEC au_info @lastname = 'Dull', @firstname = 'Ann'
-- Or
EXEC au_info @firstname = 'Ann', @lastname = 'Dull'
</PRE>
<P>如果该过程是批处理中的第一条语句，则可使用：</P><PRE>au_info 'Dull', 'Ann'
-- Or
au_info @lastname = 'Dull', @firstname = 'Ann'
-- Or
au_info @firstname = 'Ann', @lastname = 'Dull'
</PRE>
<H6>C. 使用带有通配符参数的简单过程</H6>
<P>下面的存储过程从四个表的联接中只返回指定的作者（提供了姓名）、出版的书籍以及出版社。该存储过程对传递的参数进行模式匹配，如果没有提供参数，则使用预设的默认值。</P><PRE>USE pubs
IF EXISTS (SELECT name FROM sysobjects 
      WHERE name = 'au_info2' AND type = 'P')
   DROP PROCEDURE au_info2
GO
USE pubs
GO
CREATE PROCEDURE au_info2
   @lastname varchar(30) = 'D%',
   @firstname varchar(18) = '%'
AS 
SELECT au_lname, au_fname, title, pub_name
FROM authors a INNER JOIN titleauthor ta
   ON a.au_id = ta.au_id INNER JOIN titles t
   ON t.title_id = ta.title_id INNER JOIN publishers p
   ON t.pub_id = p.pub_id
WHERE au_fname LIKE @firstname
   AND au_lname LIKE @lastname
GO
</PRE>
<P><B>au_info2</B><I> </I>存储过程可以用多种组合执行。下面只列出了部分组合：</P><PRE>EXECUTE au_info2
-- Or
EXECUTE au_info2 'Wh%'
-- Or
EXECUTE au_info2 @firstname = 'A%'
-- Or
EXECUTE au_info2 '[CK]ars[OE]n'
-- Or
EXECUTE au_info2 'Hunter', 'Sheryl'
-- Or
EXECUTE au_info2 'H%', 'S%'
</PRE>
<H6>D. 使用 OUTPUT 参数</H6>
<P>OUTPUT 参数允许外部过程、批处理或多条 Transact-SQL 语句访问在过程执行期间设置的某个值。下面的示例创建一个存储过程 (<B>titles_sum</B>)，并使用一个可选的输入参数和一个输出参数。</P>
<P>首先，创建过程：</P><PRE>USE pubs
GO
IF EXISTS(SELECT name FROM sysobjects
      WHERE name = 'titles_sum' AND type = 'P')
   DROP PROCEDURE titles_sum
GO
USE pubs
GO
CREATE PROCEDURE titles_sum @@TITLE varchar(40) = '%', @@SUM money OUTPUT
AS
SELECT 'Title Name' = title
FROM titles 
WHERE title LIKE @@TITLE 
SELECT @@SUM = SUM(price)
FROM titles
WHERE title LIKE @@TITLE
GO
</PRE>
<P>接下来，将该 OUTPUT 参数用于控制流语言。 </P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;OUTPUT 变量必须在创建表和使用该变量时都进行定义。</P><!--/NOTE-->
<P></P>
<P>参数名和变量名不一定要匹配，不过数据类型和参数位置必须匹配（除非使用 <B>@@</B>SUM <B>= </B><I>variable </I>形式）。 </P><PRE>DECLARE @@TOTALCOST money
EXECUTE titles_sum 'The%', @@TOTALCOST OUTPUT
IF @@TOTALCOST &lt; 200 
BEGIN
   PRINT ' '
   PRINT 'All of these titles can be purchased for less than $200.'
END
ELSE
   SELECT 'The total cost of these titles is $' 
         + RTRIM(CAST(@@TOTALCOST AS varchar(20)))
</PRE>
<P>下面是结果集：</P><PRE>Title Name                                                               
------------------------------------------------------------------------ 
The Busy Executive's Database Guide
The Gourmet Microwave
The Psychology of Computer Cooking

(3 row(s) affected)

Warning, null value eliminated from aggregate.
 
All of these titles can be purchased for less than $200.
</PRE>
<H6>E. 使用 OUTPUT 游标参数</H6>
<P>OUTPUT 游标参数用来将存储过程的局部游标传递回调用批处理、存储过程或触发器。</P>
<P>首先，创建以下过程，在 titles 表上声明并打开一个游标：</P><PRE>USE pubs
IF EXISTS (SELECT name FROM sysobjects 
      WHERE name = 'titles_cursor' and type = 'P')
DROP PROCEDURE titles_cursor
GO
CREATE PROCEDURE titles_cursor @titles_cursor CURSOR VARYING OUTPUT
AS
SET @titles_cursor = CURSOR
FORWARD_ONLY STATIC FOR
SELECT *
FROM titles

OPEN @titles_cursor
GO
</PRE>
<P>接下来，执行一个批处理，声明一个局部游标变量，执行上述过程以将游标赋值给局部变量，然后从该游标提取行。</P><PRE>USE pubs
GO
DECLARE @MyCursor CURSOR
EXEC titles_cursor @titles_cursor = @MyCursor OUTPUT
WHILE (@@FETCH_STATUS = 0)
BEGIN
   FETCH NEXT FROM @MyCursor
END
CLOSE @MyCursor
DEALLOCATE @MyCursor
GO
</PRE>
<H6>F. 使用 WITH RECOMPILE 选项</H6>
<P>如果为过程提供的参数不是典型的参数，并且新的执行计划不应高速缓存或存储在内存中，WITH RECOMPILE 子句会很有帮助。</P><PRE>USE pubs
IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'titles_by_author' AND type = 'P')
   DROP PROCEDURE titles_by_author
GO
CREATE PROCEDURE titles_by_author @@LNAME_PATTERN varchar(30) = '%'
WITH RECOMPILE
AS
SELECT RTRIM(au_fname) + ' ' + RTRIM(au_lname) AS 'Authors full name',
   title AS Title
FROM authors a INNER JOIN titleauthor ta 
   ON a.au_id = ta.au_id INNER JOIN titles t
   ON ta.title_id = t.title_id
WHERE au_lname LIKE @@LNAME_PATTERN
GO
</PRE>
<H6>G. 使用 WITH ENCRYPTION 选项</H6>
<P>WITH ENCRYPTION 子句对用户隐藏存储过程的文本。下例创建加密过程，使用 <B>sp_helptext</B> 系统存储过程获取关于加密过程的信息，然后尝试直接从<B> syscomments</B><I> </I>表中获取关于该过程的信息。</P><PRE>IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'encrypt_this' AND type = 'P')
   DROP PROCEDURE encrypt_this
GO
USE pubs
GO
CREATE PROCEDURE encrypt_this
WITH ENCRYPTION
AS
SELECT * 
FROM authors
GO

EXEC sp_helptext encrypt_this
</PRE>
<P>下面是结果集：</P><PRE>The object's comments have been encrypted.
</PRE>
<P>接下来，选择加密存储过程内容的标识号和文本。</P><PRE>SELECT c.id, c.text 
FROM syscomments c INNER JOIN sysobjects o
   ON c.id = o.id
WHERE o.name = 'encrypt_this'
</PRE>
<P>下面是结果集：</P>
<P class=indent><!--NOTE--></P>
<P><IMG style="MARGIN-LEFT: 0em" height=11 alt="" src="mk:@MSITStore:C:\Program%20Files\Microsoft%20SQL%20Server\80\Tools\Books\tsqlref.chm::/Basics/note.gif" width=12 border=0> </P>
<P style="MARGIN-TOP: -1.1em; MARGIN-LEFT: 1.5em"><B>说明</B>&nbsp;&nbsp;<B>text </B>列的输出显示在单独一行中。执行时，该信息将与 <B>id </B>列信息出现在同一行中。</P><!--/NOTE-->
<P></P><PRE>id         text                                                        
---------- ------------------------------------------------------------
1413580074 ?????????????????????????????????e?????????????????????????????????????????

(1 row(s) affected)
</PRE>
<H6>H. 创建用户定义的系统存储过程</H6>
<P>下面的示例创建一个过程，显示表名以 <B>emp</B> 开头的所有表及其对应的索引。如果没有指定参数，该过程将返回表名以 <B>sys</B> 开头的所有表（及索引）。</P><PRE>IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'sp_showindexes' AND type = 'P')
   DROP PROCEDURE sp_showindexes
GO
USE master
GO
CREATE PROCEDURE sp_showindexes
   @@TABLE varchar(30) = 'sys%'
AS 
SELECT o.name AS TABLE_NAME,
   i.name AS INDEX_NAME, 
   indid AS INDEX_ID
FROM sysindexes i INNER JOIN sysobjects o
   ON o.id = i.id 
WHERE o.name LIKE @@TABLE
GO         
USE pubs
EXEC sp_showindexes 'emp%'
GO
</PRE>
<P>下面是结果集：</P><PRE>TABLE_NAME       INDEX_NAME       INDEX_ID 
---------------- ---------------- ----------------
employee         employee_ind     1
employee         PK_emp_id        2

(2 row(s) affected)
</PRE>
<H6>I. 使用延迟名称解析</H6>
<P>下面的示例显示四个过程以及延迟名称解析的各种可能使用方式。尽管引用的表或列在编译时不存在，但每个存储过程都可创建。</P><PRE>IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'proc1' AND type = 'P')
   DROP PROCEDURE proc1
GO
-- Creating a procedure on a nonexistent table.
USE pubs
GO
CREATE PROCEDURE proc1
AS
   SELECT *
   FROM does_not_exist
GO  
-- Here is the statement to actually see the text of the procedure.
SELECT o.id, c.text
FROM sysobjects o INNER JOIN syscomments c 
   ON o.id = c.id
WHERE o.type = 'P' AND o.name = 'proc1'
GO
USE master
GO
IF EXISTS (SELECT name FROM sysobjects
      WHERE name = 'proc2' AND type = 'P')
   DROP PROCEDURE proc2
GO
-- Creating a procedure that attempts to retrieve information from a
-- nonexistent column in an existing table.
USE pubs
GO
CREATE PROCEDURE proc2
AS
   DECLARE @middle_init char(1)
   SET @middle_init = NULL
   SELECT au_id, middle_initial = @middle_init
   FROM authors
GO  
-- Here is the statement to actually see the text of the procedure.
SELECT o.id, c.text
FROM sysobjects o INNER JOIN syscomments c 
   ON o.id = c.id
WHERE o.type = 'P' and o.name = 'proc2'
转自: <A href="http://goaler.xicp.net/ShowLog.asp?ID=515">http://goaler.xicp.net/ShowLog.asp?ID=515</A><BR></PRE><img src ="http://www.blogjava.net/jackybu/aggbug/1574.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:28 <a href="http://www.blogjava.net/jackybu/articles/1574.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Sql Server基本函数 </title><link>http://www.blogjava.net/jackybu/articles/1573.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:25:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1573.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1573.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1573.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1573.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1573.html</trackback:ping><description><![CDATA[1.字符串函数&nbsp;<BR>长度与分析用&nbsp;<BR><BR>datalength(Char_expr)&nbsp;返回字符串包含字符数,但不包含后面的空格&nbsp;<BR><BR>substring(expression,start,length)&nbsp;不多说了,取子串&nbsp;<BR><BR>right(char_expr,int_expr)&nbsp;返回字符串右边int_expr个字符&nbsp;<BR><BR>字符操作类&nbsp;<BR><BR>upper(char_expr)&nbsp;转为大写&nbsp;<BR><BR>lower(char_expr)&nbsp;转为小写&nbsp;<BR><BR>space(int_expr)&nbsp;生成int_expr个空格&nbsp;<BR><BR>replicate(char_expr,int_expr)复制字符串int_expr次&nbsp;<BR><BR>reverse(char_expr)&nbsp;反转字符串&nbsp;<BR><BR>stuff(char_expr1,start,length,char_expr2)&nbsp;将字符串char_expr1中的从&nbsp;<BR><BR>start开始的length个字符用char_expr2代替&nbsp;<BR><BR>ltrim(char_expr)&nbsp;rtrim(char_expr)&nbsp;取掉空格&nbsp;<BR><BR><BR>ascii(char)&nbsp;char(ascii)&nbsp;两函数对应,取ascii码,根据ascii吗取字符&nbsp;<BR><BR><BR>字符串查找&nbsp;<BR><BR>charindex(char_expr,expression)&nbsp;返回char_expr的起始位置&nbsp;<BR><BR>patindex("%pattern%",expression)&nbsp;返回指定模式的起始位置,否则为0&nbsp;<BR><BR><BR>2.数学函数&nbsp;<BR><BR>abs(numeric_expr)&nbsp;求绝对值&nbsp;<BR><BR>ceiling(numeric_expr)&nbsp;取大于等于指定值的最小整数&nbsp;<BR><BR>exp(float_expr)&nbsp;取指数&nbsp;<BR><BR>floor(numeric_expr)&nbsp;小于等于指定值得最大整数&nbsp;<BR><BR>pi()&nbsp;3.1415926.........&nbsp;<BR><BR>power(numeric_expr,power)&nbsp;返回power次方&nbsp;<BR><BR>rand([int_expr])&nbsp;随机数产生器&nbsp;<BR><BR>round(numeric_expr,int_expr)&nbsp;安int_expr规定的精度四舍五入&nbsp;<BR><BR>sign(int_expr)&nbsp;根据正数,0,负数,,返回+1,0,-1&nbsp;<BR><BR>sqrt(float_expr)&nbsp;平方根&nbsp;<BR><BR><BR>3.日期函数&nbsp;<BR><BR>getdate()&nbsp;返回日期&nbsp;<BR><BR>datename(datepart,date_expr)&nbsp;返回名称如&nbsp;June&nbsp;<BR><BR>datepart(datepart,date_expr)&nbsp;取日期一部份&nbsp;<BR><BR>datediff(datepart,date_expr1.dateexpr2)&nbsp;日期差&nbsp;<BR><BR>dateadd(datepart,number,date_expr)&nbsp;返回日期加上&nbsp;number&nbsp;<BR><BR>上述函数中datepart的&nbsp;<BR><BR>写法&nbsp;取值和意义&nbsp;<BR><BR>yy&nbsp;1753-9999&nbsp;年份&nbsp;<BR><BR>qq&nbsp;1-4&nbsp;刻&nbsp;<BR><BR>mm&nbsp;1-12&nbsp;月&nbsp;<BR><BR>dy&nbsp;1-366&nbsp;日&nbsp;<BR><BR>dd&nbsp;1-31&nbsp;日&nbsp;<BR><BR>wk&nbsp;1-54&nbsp;周&nbsp;<BR><BR>dw&nbsp;1-7&nbsp;周几&nbsp;<BR><BR>hh&nbsp;0-23&nbsp;小时&nbsp;<BR><BR>mi&nbsp;0-59&nbsp;分钟&nbsp;<BR><BR>ss&nbsp;0-59&nbsp;秒&nbsp;<BR><BR>ms&nbsp;0-999&nbsp;毫秒&nbsp;<BR><BR><BR>日期转换&nbsp;<BR><BR>convert()&nbsp;<BR><BR><BR>4.系统函数&nbsp;<BR><BR>suser_name()&nbsp;用户登录名&nbsp;<BR><BR>user_name()&nbsp;用户在数据库中的名字&nbsp;<BR><BR>user&nbsp;用户在数据库中的名字&nbsp;<BR><BR>show_role()&nbsp;对当前用户起作用的规则&nbsp;<BR><BR><BR>db_name()&nbsp;数据库名&nbsp;<BR><BR>object_name(obj_id)&nbsp;数据库对象名&nbsp;<BR><BR>col_name(obj_id,col_id)&nbsp;列名&nbsp;<BR><BR>col_length(objname,colname)&nbsp;列长度&nbsp;<BR><BR>valid_name(char_expr)&nbsp;是否是有效标识符&nbsp;<BR><img src ="http://www.blogjava.net/jackybu/aggbug/1573.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:25 <a href="http://www.blogjava.net/jackybu/articles/1573.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL高手篇:精妙SQL语句介绍 </title><link>http://www.blogjava.net/jackybu/articles/1572.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:23:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1572.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1572.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1572.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1572.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1572.html</trackback:ping><description><![CDATA[<DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"></FONT></P>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：复制表(只复制结构,源表名：a 新表名：b)</FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SQL: select * into b from a where 1&lt;&gt;1</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：拷贝表(拷贝数据,源表名：a 目标表名：b)</FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SQL: insert into b(a, b, c) select d,e,f from b;</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：显示文章、提交人和最后回复时间</FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SQL: select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：外连接查询(表名1：a 表名2：b)</FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：日程安排提前五分钟提醒</FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SQL:&nbsp; select * from 日程安排 where datediff('minute',f开始时间,getdate())&gt;5</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><BR>说明：两张关联表，删除主表中已经在副表中没有的信息<BR>SQL:&nbsp; </FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">delete from info where not exists ( select * from infobz where info.infid=infobz.infid&nbsp; </FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：--<BR>SQL:&nbsp; <BR></FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px">SELECT A.NUM, A.NAME, B.UPD_DATE, B.PREV_UPD_DATE<BR>&nbsp; FROM TABLE1, <BR>&nbsp;&nbsp;&nbsp; (SELECT X.NUM, X.UPD_DATE, Y.UPD_DATE PREV_UPD_DATE<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM (SELECT NUM, UPD_DATE, INBOUND_QTY, STOCK_ONHAND<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TABLE2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = TO_CHAR(SYSDATE, 'YYYY/MM')) X, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (SELECT NUM, UPD_DATE, STOCK_ONHAND<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TABLE2<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE TO_CHAR(UPD_DATE,'YYYY/MM') = <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TO_CHAR(TO_DATE(TO_CHAR(SYSDATE, 'YYYY/MM') ¦¦ '/01','YYYY/MM/DD') - 1, 'YYYY/MM')&nbsp; Y, <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE X.NUM = Y.NUM （+）<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AND X.INBOUND_QTY + NVL(Y.STOCK_ONHAND,0) &lt;&gt; X.STOCK_ONHAND&nbsp; B<BR>WHERE A.NUM = B.NUM</FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px">说明：--<BR>SQL:&nbsp; </FONT></P>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><BR>&nbsp;</FONT></P>
<DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px"></FONT></FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">select * from studentinfo where not exists(select * from student where studentinfo.id=student.id) and 系名称='"&amp;strdepartmentname&amp;"' and 专业名称='"&amp;strprofessionname&amp;"' order by 性别,生源地,高考总成绩</FONT></FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">说明：<BR>从数据库中去一年的各单位电话费统计(电话费定额贺电化肥清单两个表来源）<BR>SQL: <BR></FONT></FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">SELECT a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy') AS telyear,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '01', a.factration)) AS JAN,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '02', a.factration)) AS FRI,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '03', a.factration)) AS MAR,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '04', a.factration)) AS APR,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '05', a.factration)) AS MAY,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '06', a.factration)) AS JUE,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '07', a.factration)) AS JUL,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '08', a.factration)) AS AGU,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '09', a.factration)) AS SEP,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '10', a.factration)) AS OCT,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '11', a.factration)) AS NOV,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; SUM(decode(TO_CHAR(a.telfeedate, 'mm'), '12', a.factration)) AS DEC<BR>FROM (SELECT a.userper, a.tel, a.standfee, b.telfeedate, b.factration<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FROM TELFEESTAND a, TELFEE b<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WHERE a.tel = b.telfax) a<BR>GROUP BY a.userper, a.tel, a.standfee, TO_CHAR(a.telfeedate, 'yyyy')</FONT></FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">说明：四表联查问题：</FONT></FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">SQL: select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c&nbsp; inner join d on a.a=d.d where .....</FONT></FONT></DIV>
<P><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">说明：得到表中最小的未使用的ID号<BR>SQL:</FONT></FONT></P>
<DIV class=quote><FONT id=zoomt style="FONT-SIZE: 14px"><FONT id=zoomt style="FONT-SIZE: 14px">SELECT (CASE WHEN EXISTS(SELECT * FROM Handle b WHERE b.HandleID = 1) THEN MIN(HandleID) + 1 ELSE 1 END) as HandleID<BR>&nbsp;FROM&nbsp; Handle<BR>&nbsp;WHERE NOT HandleID IN (SELECT a.HandleID - 1 FROM Handle a)</FONT></FONT></DIV></DIV></DIV><img src ="http://www.blogjava.net/jackybu/aggbug/1572.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:23 <a href="http://www.blogjava.net/jackybu/articles/1572.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SQL的基本操作</title><link>http://www.blogjava.net/jackybu/articles/1571.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:20:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1571.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1571.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1571.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1571.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1571.html</trackback:ping><description><![CDATA[1.数据类型 
<P>数据类弄是数据的一种属性，表示数据所表示信息的类型。任何一种计算机语言都定义了自己的数据类型。当然，不同的程序语言都具有不同的特点，所定义的数据类型的各类和名称都或多或少有些不同。SQL Server 提供了 25 种数据类型： </P>
<P>·Binary [(n)] </P>
<P>·Varbinary [(n)] </P>
<P>·Char [(n)] </P>
<P>·Varchar[(n)] </P>
<P>·Nchar[(n)] </P>
<P>·Nvarchar[(n)] </P>
<P>·Datetime </P>
<P>·Smalldatetime </P>
<P>·Decimal[(p[,s])] </P>
<P>·Numeric[(p[,s])] </P>
<P>·Float[(n)] </P>
<P>·Real </P>
<P>·Int </P>
<P>·Smallint </P>
<P>·Tinyint </P>
<P>·Money </P>
<P>·Smallmoney </P>
<P>·Bit </P>
<P>·Cursor </P>
<P>·Sysname </P>
<P>·Timestamp </P>
<P>·Uniqueidentifier </P>
<P>·Text </P>
<P>·Image </P>
<P>·Ntext </P>
<P><BR>(1)二进制数据类型 </P>
<P>二进制数据包括 Binary、Varbinary 和 Image. </P>
<P>Binary 数据类型既可以是固定长度的(Binary),也可以是变长度的。 </P>
<P>Binary[(n)] 是 n 位固定的二进制数据。其中，n 的取值范围是从 1 到 8000。其存储窨的大小是 n + 4 个字节。 </P>
<P>Varbinary[(n)] 是 n 位变长度的二进制数据。其中，n 的取值范围是从 1 到 8000。其存储窨的大小是 n + 4个字节，不是 n 个字节。 </P>
<P>在 Image 数据类型中存储的数据是以位字符串存储的，不是由 SQL Server 解释的，必须由应用程序来解释。例如，应用程序可以使用 BMP、TIEF、GIF 和 JPEG 格式把数据存储在 Image 数据类型中。 </P>
<P>(2)字符数据类型 </P>
<P>字符数据的类型包括 Char，Varchar 和 Text。 </P>
<P>字符数据是由任何字母、符号和数字任意组合而成的数据。 </P>
<P>Varchar 是变长字符数据，其长度不超过 8KB。Char 是定长字符数据，其长度最多为 8KB。超过 8KB 的ASCII 数据可以使用Text 数据类型存储。例如，因为 Html 文档全部都是 ASCII 字符，并且在一般情况下长度超过 8KB，所以这些文档可以 Text 数据类型存储在 SQL Server 中。 </P>
<P>(3)Unicode 数据类型 </P>
<P>Unicode 数据类型包括 Nchar,Nvarchar 和Ntext。 </P>
<P>在 Microsoft SQL Server 中，传统的非 Unicode 数据类型允许使用由特定字符集定义的字符。在 SQL Server 安装过程中，允许选择一种字符集。使用 Unicode 数据类型，列中可以存储任何由Unicode 标准定义的字符。在 Unicode 标准中，包括了以各种字符集定义的全部字符。使用Unicode 数据类型，所战胜的窨是使用非 Unicode 数据类型所占用的窨大小的两倍。 </P>
<P>在 SQL Server 中，Unicode 数据以 Nchar、Nvarchar 和 Ntext 数据类型存储。使用这种字符类型存储的列可以存储多个字符集中的字符。当列的长度变化时，应该使用 Nvarchar 字符类型，这时最多可以存储 4000 个字符。当列的长度固定不变时，应该使用 Nchar 字符类型，同样，这时最多可以存储 4000 个字符。当使用 Ntext 数据类型时，该列可以存储多于 4000 个字符。 </P>
<P>(4)日期和时间数据类型 </P>
<P>日期和时间数据类型包括 Datetime 和 Smalldatetime 两种类型。 </P>
<P>日期和时间数据类型由有效的日期和时间组成。例如，有效的日期和时间数据包括“4/01/98 12:15:00:00:00 PM”和“1:28:29:15:01 AM 8/17/98”。前一个数据类型是日期在前，时间在后一个数据类型是霎时间在前，日期在后。在 Microsoft SQL Server 中，日期和时间数据类型包括Datetime 和 Smalldatetime 两种类型时，所存储的日期范围是从 1753 年 1 月 1 日开始，到 9999 年12 月 31 日结束(每一个值要求 8 个存储字节)。使用 Smalldatetime 数据类型时，所存储的日期范围是 1900 年 1 月 1日 开始，到 2079 年 12 月 31 日结束(每一个值要求 4 个存储字节)。 </P>
<P>日期的格式可以设定。设置日期格式的命令如下： </P>
<P>Set DateFormat {format | @format _var| </P>
<P>其中，format | @format_var 是日期的顺序。有效的参数包括 MDY、DMY、YMD、YDM、MYD 和 DYM。在默认情况下，日期格式为 MDY。 </P>
<P>例如，当执行 Set DateFormat YMD 之后，日期的格式为年 月 日 形式；当执行 Set DateFormat DMY 之后，日期的格式为 日 月有年 形式 </P>
<P>（5）数字数据类型 </P>
<P>数字数据只包含数字。数字数据类型包括正数和负数、小数（浮点数）和整数 。 </P>
<P>整数由正整数和负整数组成，例如 39、25、0-2 和 33967。在 Micrsoft SQL Server 中，整数存储的数据类型是 Int，Smallint 和 Tinyint。Int 数据类型存储数据的范围大于 Smallint 数据类型存储数据的范围，而 Smallint 据类型存储数据的范围大于 Tinyint 数据类型存储数据的范围。使用 Int 数据狗昔存储数据的范围是从 -2 147 483 648 到 2 147 483 647（每一个值要求 4个字节存储空间）。使用 Smallint 数据类型时，存储数据的范围从 -32 768 到 32 767（每一个值要求2个字节存储空间）。使用 Tinyint 数据类型时，存储数据的范围是从0 到255（每一个值要求1个字节存储空间）。 </P>
<P>精确小娄数据在 SQL Server 中的数据类型是 Decimal 和 Numeric。这种数据所占的存储空间根据该数据的位数后的位数来确定。 </P>
<P>在SQL Server 中，近似小数数据的数据类型是 Float 和 Real。例如，三分之一这个分数记作。3333333，当使用近似数据类型时能准确表示。因此，从系统中检索到的数据可能与存储在该列中数据不完全一样。 </P>
<P>（6）货币数据表示正的或者负的货币数量 。在 Microsoft SQL Server 中，货币数据的数据类型是Money 和 Smallmoney。Money 数据类型要求 8 个存储字节，Smallmoney 数据类型要求 4 个存储字节。 </P>
<P>（7）特殊数据类型 </P>
<P>特殊数据类型包括前面没有提过的数据类型。特殊的数据类型有3种，即 Timestamp、Bit 和 Uniqueidentifier。 </P>
<P>Timestamp 用于表示SQL Server 活动的先后顺序，以二进投影的格式表示。Timestamp 数据与插入数据或者日期和时间没有关系。 </P>
<P>Bit 由 1 或者 0 组成。当表示真或者假、ON 或者 OFF 时，使用 Bit 数据类型。例如，询问是否是每一次访问的客户机请求可以存储在这种数据类型的列中。 </P>
<P>Uniqueidentifier 由 16 字节的十六进制数字组成，表示一个全局唯一的。当表的记录行要求唯一时，GUID是非常有用。例如，在客户标识号列使用这种数据类型可以区别不同的客户。 </P>
<P>2.用户定义的数据类型 </P>
<P>用户定义的数据类型基于在 Microsoft SQL Server 中提供的数据类型。当几个表中必须存储同一种数据类型时，并且为保证这些列有相同的数据类型、长度和可空性时，可以使用用户定义的数据类型。例如，可定义一种称为 postal_code 的数据类型，它基于 Char 数据类型。 </P>
<P>当创建用户定义的数据类型时，必须提供三个数：数据类型的名称、所基于的系统数据类型和数据类型的可空性。 </P>
<P>（1）创建用户定义的数据类型 </P>
<P>创建用户定义的数据类型可以使用 Transact-SQL 语句。系统存储过程 sp_addtype 可以来创建用户定义的数据类型。其语法形式如下： </P>
<P>sp_addtype {type},[,system_data_bype][,'null_type'] </P>
<P>其中，type 是用户定义的数据类型的名称。system_data_type 是系统提供的数据类型，例如 Decimal、Int、Char 等等。 null_type 表示该数据类型是如何处理空值的，必须使用单引号引起来，例如'NULL'、'NOT NULL'或者'NONULL'。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Exec sp_addtype ssn,'Varchar(11)',"Not Null' </P>
<P>创建一个用户定义的数据类型 ssn，其基于的系统数据类型是变长为11 的字符，不允许空。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Exec sp_addtype birthday,datetime,'Null' </P>
<P>创建一个用户定义的数据类型 birthday，其基于的系统数据类型是 DateTime，允许空。 </P>
<P>例子： </P>
<P>Use master </P>
<P>Exec sp_addtype telephone,'varchar(24),'Not Null' </P>
<P>Eexc sp_addtype fax,'varchar(24)','Null' </P>
<P>创建两个数据类型，即 telephone 和 fax </P>
<P>（2）删除用户定义的数据类型 </P>
<P>当用户定义的数据类型不需要时，可删除。删除用户定义的数据类型的命令是 sp_droptype {'type'}。 </P>
<P>例子： </P>
<P>Use master </P>
<P>Exec sp_droptype 'ssn' </P>
<P>注意：当表中的列还正在使用用户定义的数据类型时，或者在其上面还绑定有默认或者规则时，这种用户定义的数据类型不能删除。 </P>
<P><BR>2.数据库的相关操作</P>
<P><BR>1.如何创建数据库 </P>
<P>(1).使用 Create Database 创建数据库 </P>
<P><BR>Create Database 语名的语法形式如下： </P>
<P><BR>Create Database database_name </P>
<P>[On </P>
<P>{[Primary](Name=logical_file_name, </P>
<P>Filename='os_file_name' </P>
<P>[,Size=size] </P>
<P>[,Maxsize=max_size] </P>
<P>}[,...n] </P>
<P>] </P>
<P>[Log On </P>
<P>}(Name=Logical_name, </P>
<P>Filename='os_file_name' </P>
<P>[,Size=size]) </P>
<P>}[,...n] </P>
<P>] </P>
<P>[For Restore] </P>
<P><BR>注释： </P>
<P>Primary：该选项是一个关键字，用来指定主文件组中的文件。主文件组不公包含了数据库系统表中的全部内容，而且还包含了没有在用户文件组中包含的全部对象。一个数据库只能有一个主文件。在默认情况下，即在没有指定Primary关键字时，列在语句中的第一个文件就是主文件。 </P>
<P>Name：该选项指定数据库的逻辑名字，这是在SQL Server 系统中使用的名称，是数据库在SQL Server 中标识符。 </P>
<P>Filename：该选项用来指定数据库所在文件的操作系统文件名称和路径。在os_file_name中的路径必须是SQL Server 所在服务器上的一个文件夹。该操作系统文件名称与Name 的逻辑名称是一一对应的。 </P>
<P>Size：该选项用来指定数据库操作系统文件的大小。在指定文件大小的时候，既可以使用MB单位，也可以使用KB单位。如果没有指定单位，那么系统默认的单位是MB。文件最小是1MB，也就是说，数据库所在的文件不能小于1MB。在默认情况下，数据库数据文件的大小是3MB，数据库日志文件的大小是 1MB。 </P>
<P>Maxsize：该选项用来指定操作系统文件可以增长的最大尺寸。在指定文件增长尺寸的时候，既可以使用MB单位，也可以使用KB单位。如果没有指定单位，那么系统的默认单位是MB。如果没有指定文件可以增长的最大尺寸，那么系统的增长是没有限制的，可以占满整个磁盘空间。 </P>
<P>FielGrowth：该选取项用来指定文件的增量，当然该选项不能与Maxsize选项有冲突。该选项指定的数据值为零时，表示文件不能增长。该选项可以用MB、KB和百分比指定。 </P>
<P><BR>例子： </P>
<P>创建一个cust数据库，该数据库的主数据文件的逻辑名称是cust_data，操作系统文件是cust.mdf，大小是15MB，最大是 30MB，以20%的速度增加；该数据库的日志文件的逻辑名称是cust_log，操作系统是cust.ldf，大小是3MB，最大是10MB，以1MB 的速度增加。 </P>
<P><BR>Create Database cust </P>
<P>On </P>
<P>Primary (Name=cust_data, </P>
<P>Filename='d:cust.mdf', </P>
<P>Size=15MB, </P>
<P>Maxsize=30MB, </P>
<P>Filegrowth=20%) </P>
<P>Log On </P>
<P>(Name=cust_log, </P>
<P>Filename='d:cust.ldf', </P>
<P>Size=3MB, </P>
<P>Maxsize=10MB, </P>
<P>FileGrowth=1MB) </P>
<P><BR>2.如何增加数据库的大小 </P>
<P>(1).使用Alter Database命令来增加数据库文件的大小 </P>
<P>如果在创建数据库文件时没有配置文件的大小自动增长，那么可以使用Alter Database命令来增加文件的大小。 </P>
<P><BR>例子： </P>
<P>将数据库cust的数据文件cust_data的大小调整为50MB。 </P>
<P>Alter Database cust </P>
<P>Modify File (Name='cust_data',Size=50) </P>
<P><BR>(2).使用Add File 增加一个次要文件 </P>
<P>通过为数据库增加次要的数据文件和日志文件来增加数据库的大小。 </P>
<P>例子： </P>
<P>Alter Database cust </P>
<P>Add File </P>
<P>(Name=cust_data2,Filename='d:cust2.mdf', </P>
<P>Size=5MB, </P>
<P>Maxsize=10MB, </P>
<P>Filegrowth=10%) </P>
<P><BR>3.压缩数据库和数据文件 </P>
<P>(1)使用Dbcc Shrinkdatabase 命令压缩整个数据库 </P>
<P>例子： </P>
<P>将cust数据库的大小压缩到10% </P>
<P>Dbcc Shrinkdatabase (cust,10) </P>
<P>(2)使用Dbcc ShrinkFile命令压缩数据库中的某一个数据文件 </P>
<P>例子： </P>
<P>将cust数据文件的大小压缩到5MB </P>
<P>Dbcc ShrinkFile (cust,5) </P>
<P><BR>4.删除数据库 </P>
<P>(1)使用Drop命令删除数据库 </P>
<P>例子： </P>
<P>将删除cust数据库 </P>
<P>Drop Database cust </P>
<P><BR>3.表的相关操作） </P>
<P><BR>1.创建表 </P>
<P>(1)用Create Table 命令创建表 </P>
<P>语法： </P>
<P>Create Table tabl_name </P>
<P>({ </P>
<P>}column_name As computed_column_expression </P>
<P>} </P>
<P>}[,...n] </P>
<P>) </P>
<P>[On {fiegroup | Default}] </P>
<P>[Textimage_On {fiegroup | Default}] </P>
<P><BR>例子： </P>
<P>打开cust数据库，创建一个表，该表包含了学生的有关信息，即有学号、姓名、性别、出生日期、籍贯、联系电话、住址和备注信息。 </P>
<P>Use cust </P>
<P>Create Table students </P>
<P>( </P>
<P>number int not null, </P>
<P>name varchar(10) not null, </P>
<P>sex char(2) null, </P>
<P>birthday datetime null, </P>
<P>hometown varchar(30) null, </P>
<P>telphone_no varchar(12) null, </P>
<P>address varchar(30) null, </P>
<P>others varchar(50) null </P>
<P>) </P>
<P>在这个表中number表示学生代号，数据类型为int，不允许为空；name表示学生姓名，数据类型为varchar，长度为10，不允许为空； sex表示学生的性别，数据类型为char，长度为2，允许为空；birthday表示学生的出生日期，数据类型为datetime，允许为空； hometown表示学生的籍贯，数据类型为varchar，长度为30，允许为空；telephone_no表示学生的联系电脑，数据类型为 varchar，长度为12，允许为空；address表示学生的住址，数据类型为varchar，长度为30，允许为空；others表示学生的备注信息，长度为50，允许为空。 </P>
<P><BR>2.修改表的结构 </P>
<P>(1)使用T-SQL语句增加和删除一个新列 </P>
<P>语法： </P>
<P>Alter Table table </P>
<P>{ </P>
<P>ADO </P>
<P>{[] </P>
<P>|colun_name As computed_column_expression </P>
<P>|[] </P>
<P>}[,...n] </P>
<P>|Drop </P>
<P>{Column column </P>
<P>}[,...n] </P>
<P>} </P>
<P><BR>例子：打开cust数据库，修改其中的表students的结构，增加一个新字段，字段名为ying，数据类型是varchar，长度是10，没有默认值，充许为空。 </P>
<P>Use cust </P>
<P>Alter Table students Add ying varchar(10) null </P>
<P><BR>打开cust数据库，修改其中的表students的结构，删除一个字段，字段名为ying。 </P>
<P>Use cust </P>
<P>Alter Table students Drop Column ying </P>
<P><BR>3.向表中插入数据 </P>
<P>(1)用 Insert 语句 </P>
<P>语法如下： </P>
<P>Insert [Into] </P>
<P>{table_name|view_name}[(column_list)] </P>
<P>{Values|values_list|select_statement} </P>
<P>注意：在插入数据时，字符数据和日期数据要使用引号引起来。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Insert Into students </P>
<P>Values (11,"影子","男","1999-12-12","湖北","83779805","武汉市桥口区","VB爱好者") </P>
<P>打开cust数据库，向students表中插入数据 </P>
<P><BR>(2)用Default 选项 </P>
<P>在插入数据时，可以使用Default选项。Default选项有两种形式，一种形式是Default Values，另一种是Default。 </P>
<P>Default Values 形式为表中的某一行的所有列插入默认值。使用这种形式的前提条件是表中的所有列必须是这四种类型之一：Identity属性，Timestamp数据类型，允许为Null，或者有一个指定的默认值。否则，会错误信息。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Insert Into students Default Values </P>
<P>这个例子会出现错误，因为students表的number字段是设置为不允许为空的。 </P>
<P><BR>Default 形式是为表中的某一列插入默认值。要插入的该列必须具备一定的条件，即该列要么是Timestamp 数据类型，要么是允许为Null，要么是有一个指定的默认值，否则，会出现错误信息。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Insert Into students Values(11,"影子",Default,Default,Default,Default,Default,Default) </P>
<P>由天前2个字段不能为空，所以要赋值，否则会出现错误，而后面的6个字段允许为空，因此可以调用Default默认。 </P>
<P><BR>(3)插入部分数据 </P>
<P>在使用Insert语句插入数据是，还可以插入部分数据，也就是可以为每一行的指定的部分列插入数据。在插入部分数据时，应该注意以下三个问题： </P>
<P>☆在 Insert 子句中，指定要插入数据的列名。 </P>
<P>☆在 Values 子句中，列出与列名对应的数据。列名的顺序和数据的顺序应该完全对应。 </P>
<P>☆在 Insert 子句中，没有列出的列应该至少具有这四种类型之一：Identtty 属性，Timestamp 数据类型，允许为 Null，或者有一个指定的默认值。否则，会出现错误信息。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Insert Into students (number,name) </P>
<P>Values (110,"影子") </P>
<P>打开cust数据库，向students表中插入一行数据 </P>
<P>注意：如用下例语句将发生错误，因为name字段是不允许为空的（在创建数据库时设定的） </P>
<P>Insert Into students (number) </P>
<P>Values (110) </P>
<P><BR>(4)用 Select 语句插入多条数据 </P>
<P>Insert 语句插入数据的特点是每一次只能插入一行数据。相反，Select 也可以用在 Insert 语句中，并且可以一次插入多条数据。使用 Select 语句插入数据的语法形式如下： </P>
<P>Insert table_name </P>
<P>Select column_list </P>
<P>From table_list </P>
<P>Where search_conditions </P>
<P>在使用 Select 语句插入数据时，应该注意下面几点： </P>
<P>☆在 Insert 语句中使用 Select 时，他们参考的表既可以是相同的，也可以是不同的。 </P>
<P>☆要插入数据的表必须已经存在。 </P>
<P>☆要插入数据的表必须和 Select 的结果集兼容。兼容的含义是列的数量和顺序必须相同，列的数据类型或者相同，或者SQL Server 可以自动转换。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Insert students </P>
<P>Select number,name,sex,birthday,hometown,telphone_no,address,others </P>
<P>From students </P>
<P>注意： </P>
<P>Select 后面的字段要输完整，这个例子是自己向自己插入多条数据（自己向自己插入是被允许的） </P>
<P>补充： </P>
<P>你还可以“From students”后面加上“Where name="影子"”，只插入name等于影子的记录，可以用And 和 Or 加上多个条件。 </P>
<P><BR>(5)使用 Select Into 插入数据到一个新表中 </P>
<P>带有 Into 子句的 Select 语句允许用户定义一个新表并且把数据插入到新表中。这种方法不同于前面讲述的那些方法。在前面的那些方法中，一个共同的特点，是在数据输入之前表已经存在。而使用 Select Into 插入数据的方法，是在插入数据的过程中建立新表。 </P>
<P>Select Into 语句的语法如下： </P>
<P>Select select_list </P>
<P>Into new_table_name </P>
<P>From table_list </P>
<P>Where search_conditions </P>
<P>在使用 Select Into 插入数据时，要注意下面几点： </P>
<P>☆在某个数据库中使用 Select Into 插入数据时，设置该数据库的 Select Into/Bulk Copy 为真。 </P>
<P>☆新表不能存在，否则会产生错误信息。 </P>
<P>☆新表中的列和行是基于查询结果集 </P>
<P>☆要插入的数据不记录在日志中。 </P>
<P>☆在select_list 中出现的列应该使用别名，否则，新表中的列没有列名。没列名的表只能通过 Select * From new_table_name 的形式查询。因此，应该为列起个别名。 </P>
<P>☆这种方法多用在对列进行各种计算的情况。 </P>
<P>例子： </P>
<P>Select number,name </P>
<P>Into newcust1 </P>
<P>From students </P>
<P>创建新的表newcust1，插入students表中的number和name字段的所有数据。 </P>
<P>补充：如果要插入所有字段的记录，则“Select *”，也可在“From students”后加条件，方法和上个例子一样。 </P>
<P><BR>(6)用 UPdate 语句修改表中的数据 </P>
<P>Update 语句用来修改表中已存在的数据。Update 语句既可以一次修改一行数据，也可以一次修改许多行，甚至可以一次修改表中的全部数据。Update 语句使用 Where 子句指定要修改的行，使用 Set 子句给出新的数据。新数据可以是常量，也可以是指定的表达式，还可以是使用 From 子句来自其他表的数据。 </P>
<P>Update 语句的语法如下： </P>
<P>Update {table_name|view_name} </P>
<P>Set {column_list}=expression [，. . .] </P>
<P>[Where clause] </P>
<P>在使用 Update 语句时，如果没有使用 Where 子句，那么就对表中所有的行进行修改。如果使用Update 语句修改数据时与数据完整性约束有冲突，那么修改就不会发生，整个修改事务全部滚回。例如，这种冲突可能是所输入的值是错误的数据类型，或者所输入的值违背了在该列定义的规则约束，等等。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Update students </P>
<P>Set name=name+"007" </P>
<P>Where number&gt;100 </P>
<P>打开cust数据库，修改students表，使number&gt;100的数据的name的值全部加"007"。 </P>
<P><BR>4.用 Delete 语句删除表中的数据 </P>
<P>当数据库中的数据不需要的进修可以删除。一般情况下，删除数据使用 Delete 语句。Delete 语句可以一次从一个表中删除一条或者多条数据行。 </P>
<P>Delete 语句的语法如下： </P>
<P>Delete [From] table_name </P>
<P>Where search_conditions </P>
<P>在 Delete 语句中如果使用了 Where 子句，那么就从指定的表中删除满足 Where 子句条件的数据行。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Delete students </P>
<P>Where number&gt;100 </P>
<P>删除 students中，number&gt;100的数据 </P>
<P>补充： </P>
<P>如果在 Delete 语句中没有指定 Where 子句，那么就将表中所有的记录全部删除，即 Delete students 语句删除表中的全部记录。 </P>
<P>在删除表中的全部数据时，还可以使用 Truncate Table 语句。Truncate Table 语句和 Delete 语句都可以将表中的全部数据删除，但是，两条语句又有不同的特点。当用户使用 Delete 语句删除数据时，被删除的数据要记录在日志中。并不将对数据的变化记录在日志中。因此，使用 Truncate Table students 语句删除记录的速度快于使用 Delete students 语句删除表中记录的速度。 </P>
<P><BR>5.用 Drop Table 命令删除表 </P>
<P>当数据库中的表不需要时可以删除。删除表可以使用 Drop Table 语句。删除表就是删除表的定义以及表的全部数据、索引、触发器、约束和指定该表的许可。当删除表时，基于表的视图不能被删除，必须使用 Drop View 语句删除视图。 </P>
<P>Drop Table 语句的语法如下： </P>
<P>Drop Table table_name </P>
<P>例子： </P>
<P>Use cust </P>
<P>Drop Table students </P>
<P>删除cust数据库中的students表。 </P>
<P>补充： </P>
<P>不能使用 Drop Table 语句删除正在被约束参考的表，必须首先要么删除外键约束，要么删除参考表。表的所有者可以删除表。当删除表是时，绑定在该表上的规则或者默认则失掉了绑定，该表的约束或者触发器则自动被删除。如果重新创建表，必须重新绑定相应的规则和默认、重新创建触发器和增加必要的约束。另外，系统表不能删除。 </P>
<P>删除表的许可属于表的所有者。然而，数据所有者（DBO）、系统管理员（SA）和DLL管理员可以删除数据库中的任何对象。 </P>
<P><BR>4.数据的检索</P>
<P><BR>1.用 Select 子句检索记录 </P>
<P>Select 子句是每一个检索数据的查询核心。它告诉数据库引擎返回什么字段。 </P>
<P>Select 子句的常见形式是： </P>
<P>Select * </P>
<P>该子句的意思是“返回在所指定的记录源中能找到的所有字段”。这种命令形式很方便，因为你无需知道从表中检索的字段名称。然而，检索表中的所有列是低效的。因此，因该只检索需要的字段，这样可以大大的提高查询的效率。 </P>
<P>2.使用 From 子句指定记录源 </P>
<P>From 子句说明的是查询检索记录的记录源；该记录源可以是一个表或另一个存储查询。 </P>
<P>你还能从多个表中检索记录，这在后面的章节中将介绍。 </P>
<P>例子： </P>
<P>Select * From students 检索students表中的所有记录 </P>
<P>3.用 Where 子句说明条件 </P>
<P>Where 子句告诉数据库引擎根据所提供的一个或多个条件限定其检索的记录。条件是一个表达式，可具有真假两种判断。 </P>
<P>例子： </P>
<P>Select * From students Where name="影子" </P>
<P>返回students中name字段为影子的列表，这次所返回的结果没有特定顺序，除非你使用了 Order By 子句。该子句将在后面的章节介绍。 </P>
<P>注意：Where 子句中的文本字符串界限符是双引号，在VB中因改为单引号，因为在VB中字符串的界定符是双引号。 </P>
<P>补充： </P>
<P>使用 And 和 Or 逻辑可以将两个或更多的条件链接到一起以创建更高级的 Where 子句。 </P>
<P>例子： </P>
<P>Select * From students Where name="影子" And number&gt;100 </P>
<P>返回name为影子number大于100的列表。 </P>
<P>例子： </P>
<P>Select * From students Where name="影子" And (number&gt;100 Or number&lt;50) </P>
<P>返回name为影子，number大于100或者小于50的列表。 </P>
<P><BR>Where 子句中用到的操作符 </P>
<P>操作符 功能 </P>
<P>&lt; 小于 </P>
<P>&lt;= 小于或等于 </P>
<P>&gt; 大于 </P>
<P>&gt;= 大于或等于 </P>
<P>= 等于 </P>
<P>&lt;&gt; 不等于 </P>
<P>Between 在某个取值范围内 </P>
<P>Like 匹配某个模式 </P>
<P>In 包含在某个值列表中 </P>
<P>SQL中的等于和不等于等操作符与VB中的意义和使用相同 </P>
<P><BR>例子： </P>
<P>（1）.Between 操作符 </P>
<P>Use cust </P>
<P>Select * From students </P>
<P>Where number Between 1 and 100 </P>
<P>Between 操作符返回的是位于所说明的界限之内的所有记录值。这个例子就返回 number 字段 1 到 100 之间的全部记录。 </P>
<P><BR>（2）. Like 操作符和通配符 </P>
<P>Use cust </P>
<P>Select * From students </P>
<P>Where name Like "%影%" </P>
<P>Like 操作符把记录匹配到你说明的某个模式。这个例子是返回含“影”的任意字符串。 </P>
<P><BR>四种通配符的含义 </P>
<P>通配符 描述 </P>
<P>% 代表零个或者多个任意字符 </P>
<P>_（下划线） 代表一个任意字符 </P>
<P>[] 指定范围内的任意单个字符 </P>
<P>[^] 不在指定范围内的任意单个字符 </P>
<P><BR>全部示例子如下： </P>
<P>Like "BR%" 返回以"BR"开始的任意字符串 </P>
<P>Like "br%" 返回以"Br"开始的任意字符串 </P>
<P>Like "%een" 返回以"een"结束的任意字符串 </P>
<P>Like "%en%" 返回包含"en"的任意字符串 </P>
<P>Like "_en" 返回以"en"结束的三个字符串 </P>
<P>Like "[CK]%" 返回以"C"或者"K"开始的任意字符串 </P>
<P>Like "[S-V]ing" 返回长为四个字符的字符串，结尾是"ing"，开始是从S到V。 </P>
<P>Like "M[^c]%" 返回以"M"开始且第二个字符不是"c"的任意字符串。 </P>
<P><BR>4. 使用 Order By 对结果排序 </P>
<P>Order By 子句告诉数据库引擎对其检索的记录进行排序。可以对任何字段排序，或者对多个字段排序，并且可以以升序或隆序进行排序。 </P>
<P>在一个正式的 Select 查询之后包含一个 Order By 子句，后跟想排序的字段（可以有多个）便可以说明一个排序顺序。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Select * From students </P>
<P>Where name Like "%影%" </P>
<P>Order By number </P>
<P>对返回的结果按 number 进行排序。 </P>
<P><BR>以降序排序 </P>
<P>如要以隆序排序，只需在排序的字段之后使用 Desc 关键字。 </P>
<P>例子： </P>
<P>Use cust </P>
<P>Select * From students </P>
<P>Where name Like "%影%" </P>
<P>Order By number Desc </P>
<P><BR>5. 使用 Top 显示某个范围的第一个记录或最后一个记录。 </P>
<P>使用 Top 关键字可以只显示一个大记录前面或后面的少数几个记录。在查询中，Top 关键字与排序子句一起把结果集限制为少数几个记录或按某个百分比显示整个结果记录集合中的一部分。 </P>
<P>例子： </P>
<P>Select Top 3 * From students 返回 students 表中的前3条记录 </P>
<P>Select Top 10 Percent * From students 返回 students 表中前面的10%个记录 </P>
<P>Select Top 3 * From students Order By number desc 返回 students 表中 number 最大的（最后）的3条记录 </P>
<P><BR>6. 用 As 对字段名进行别名化 </P>
<P>为什么在查询中对字段命以别名，或重新命名，这样做的原因有两个： </P>
<P>☆所涉及的表的字段名很长，想使字段在结果集中更易处理一些。 </P>
<P>☆创建的查询产生了某些计算或合计列，需要对之进行命名。 </P>
<P>不管是什么原因对字段命以别名，在 SQL 中都可以容易地使用 As 子句做得。 </P>
<P>例子： </P>
<P>Select number As 学号 ,name As 姓名 From students </P>
<P><BR>7. 合并查询 </P>
<P>合并查询（ Union Query ）用于合并具有相同字段结构的两个表的内容，如果想在一个结果集中显示多个记录源中的不相关的记录时，这十分有用。 </P>
<P>例子： </P>
<P>Select * </P>
<P>From students </P>
<P>Union </P>
<P>Select * </P>
<P>From students1 </P>
<P>该查询结果集把 students 和 students1 中的记录合并到一个结果中，其输出就和原表归档之前一模一样。 </P>
<P>注意：缺省情况下，合并查询不会返回重复记录（如果记录归档系统在把记录拷到归档表中后不将相应的记录删除，这时该功能就有用了），可以加上 All 关键字而让合并查询显示重复记录。 </P>
<P>例子： </P>
<P>Select * </P>
<P>From students </P>
<P>Union All </P>
<P>Select * </P>
<P>From students1 </P>
<P>该合并查询显示 students 表和 students1 表的内容时，没有对重复记录进行处理 </P>
<P>补充： </P>
<P>Union 运算符允许把两个或者多个查询结果合并到一个查询结果集中。如果比较 Union 和 Join 两咱运算符，那么 Union 运算符增加行的数量，而 Join 运算符增加列的数量。使用 Union 时应该注意，两个结果中的列的结构必须匹配，数据类型必须兼容等等。 </P>
<P>Union 运算符的语法形式如下： </P>
<P>Select select_list </P>
<P>From clause </P>
<P>Where clause </P>
<P>Group By clause </P>
<P>Having clause </P>
<P>Union [All] </P>
<P>Select select_list </P>
<P>From clause </P>
<P>Where clause </P>
<P>Group By clause </P>
<P>Having clause </P>
<P>Order By clause </P>
<P>Compute clause </P>
<P>对于 Union 运算符，有下列几点需要说明： </P>
<P>·在默认情况下，Union 运算符删除全部冗余行。如果使用All 选项，那么冗余行不删除。 </P>
<P>·在 Union 语句中的全部 select_list 必须有相同数量的列、兼容的数据类型并且按照同样的顺序出现。 </P>
<P>·在结果集中，列名来自第一个 Select 语句。 </P>
<P></P>
<P>8.连接查询 </P>
<P>在实际使用过程中经常需要同时从两个表或者两个以上表中检索数据。连接就是允许同时从两个表或者两个以上表中检索数据，指定这些表中某个或者某些列作为连接条件。在 SQL Server 中，可以使用两种连接语法形式，一种是 Ansi 连接语法形式，这是连接用在 From 子句中，另外一种是 SQL Server 连接语句形式，这是连接用在 Where 子句中。 </P>
<P>Ansi 连接语法形式如下： </P>
<P>Select table_name.column_name,table_name.column_name,... </P>
<P>From {table_name [join_type] Join table_name On search_conditions} </P>
<P>Where [search_conditions] </P>
<P>在 Ansi 语法形式中，可以 Ansi 连接关键字来确定使用的连接形式。例如： </P>
<P>☆使用 Inner Join 关键字，结果集中仅包含满足条件的行。 </P>
<P>☆使用 Cross Join 关键字，结果集中包含两个表中所有行的组合。 </P>
<P>☆使用 Outer Join 关键字，结果集中既包含那些满足条件的行，还包含那些其中某个表的全部行。 </P>
<P>SQL Server 连接语法形式如下所示： </P>
<P>Select table_name.column_name,table_name.column_name,... </P>
<P>From [table_name,tab</P><img src ="http://www.blogjava.net/jackybu/aggbug/1571.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:20 <a href="http://www.blogjava.net/jackybu/articles/1571.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我的第一个存储过程(转)</title><link>http://www.blogjava.net/jackybu/articles/1570.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Mon, 28 Feb 2005 13:06:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1570.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1570.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1570.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1570.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1570.html</trackback:ping><description><![CDATA[<P>存储过程学习记录1<BR>我的第一个存储过程<BR><BR>该存储过程的功能是去完成在多个无关系数据表中执行联合查询和计算，最后生成一个统计表。<BR><BR>这个存储过程中包括了：参数传递，存储过程间相互调用并返回结果集到临时表中，使用sp_executesql执行动态生成的Sql语句，临时表的创建以及使用<BR><BR>==============================================================<BR><BR>CREATE procedure sp_MakeCond<BR>&nbsp;@FdName nvarchar(20),<BR>&nbsp;@FdRecord nvarchar(250),<BR>&nbsp;@CXZT int,<BR>&nbsp;@GSBM nvarchar(10),<BR>&nbsp;@Cond nvarchar(250) output<BR>as</P>
<P>&nbsp;/*<BR>&nbsp;功能：<BR>&nbsp;&nbsp;根据@CXZT的状态，对于字段@FdName进行内容@FdRecord的匹配。<BR>&nbsp;&nbsp;当@FdRecord中有内容的时候，进行匹配<BR>&nbsp;&nbsp;当@GSBM中有内容的时候，添加GSBM的条件<BR>&nbsp;输入:<BR>&nbsp;&nbsp;@FdName&nbsp;字段名称<BR>&nbsp;&nbsp;@FdRecord&nbsp;&nbsp; &nbsp;字段内容<BR>&nbsp;&nbsp;@GSBM&nbsp;<BR>&nbsp;&nbsp;@CXZT&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;查询状态 0-表示精确，1-表示模糊，2-表示智能<BR>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;该状态仅对KHMC起作用<BR>&nbsp;输出：<BR>&nbsp;&nbsp;@Cond &nbsp;&nbsp;条件语句 例如:&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;输入&nbsp; &nbsp;dwmc,'上海',1,'RRL'<BR>&nbsp;&nbsp;&nbsp;&nbsp;输出&nbsp;dwmc like '上海%' and gsbm='RRL'&nbsp;<BR>&nbsp;*/<BR>&nbsp;<BR>&nbsp;/*<BR>&nbsp;创建人：&nbsp;<BR>&nbsp;创建日期：<BR>&nbsp;--对于改存储过程的版本更新记录在这个地方</P>
<P>&nbsp;*/<BR>&nbsp;declare @HaveFdRecord as int</P>
<P>&nbsp;Set @HaveFdRecord = 0<BR>&nbsp;Set @Cond = ''</P>
<P>&nbsp;/* 添加FdRecord */<BR>&nbsp;if len(rtrim(ltrim(@FdRecord)))&gt;0<BR>&nbsp;begin<BR>&nbsp;select @Cond=<BR>&nbsp;&nbsp;case @CXZT<BR>&nbsp;&nbsp;&nbsp;when 0 then <BR>&nbsp;&nbsp;&nbsp;&nbsp;@Cond + @FdName + N'=''' + @FdRecord + ''''<BR>&nbsp;&nbsp;&nbsp;when 1 then <BR>&nbsp;&nbsp;&nbsp;&nbsp;@Cond + @FdName + N' like ''' + @FdRecord + '%'''<BR>&nbsp;&nbsp;&nbsp;when 2 then<BR>&nbsp;&nbsp;&nbsp;&nbsp;@Cond + @FdName + N' like ''%' + @FdRecord + '%'''<BR>&nbsp;&nbsp;&nbsp;end<BR>&nbsp;&nbsp;set @HaveFdRecord = 1<BR>&nbsp;end</P>
<P>&nbsp;/* 添加GSBM */<BR>&nbsp;if len(rtrim(ltrim(@GSBM)))&gt;0<BR>&nbsp;begin<BR>&nbsp;&nbsp;if @HaveFdRecord=1<BR>&nbsp;&nbsp;begin<BR>&nbsp;&nbsp;&nbsp;Set @Cond = @Cond + ' and '<BR>&nbsp;&nbsp;end<BR>&nbsp;&nbsp;set @Cond = @Cond + ' gsbm=''' + @GSBM + ''''<BR>&nbsp;end<BR>GO<BR><BR><BR>==============================================================<BR><BR>CREATE Procedure sp_Math_KHYE<BR>&nbsp;@KHMC nvarchar(250),<BR>&nbsp;@JZRQ datetime,<BR>&nbsp;@CXZT int,<BR>&nbsp;@GSBM nvarchar(10)<BR>as<BR>&nbsp;/*<BR>&nbsp;功能：<BR>&nbsp;输入：<BR>&nbsp;&nbsp;@KHMC &nbsp;客户名称 <BR>&nbsp;&nbsp;@CXZT&nbsp;查询状态 0-表示精确，1-表示模糊，2-表示智能<BR>&nbsp;&nbsp;&nbsp;&nbsp;该状态仅对KHMC起作用<BR>&nbsp;&nbsp;@JZRQ &nbsp;截至日期<BR>&nbsp;&nbsp;@GSBM&nbsp;<BR>&nbsp;输出：<BR>&nbsp;&nbsp;@ReturnKHYE &nbsp;根据条件计算出来的客户余额<BR>&nbsp;说明：在调用该过程前，需按照如下语句定义一个命名为#KHYEReturn的临时表<BR>&nbsp;Create Table #KHYEReturn<BR>&nbsp;&nbsp;(dwmc nvarchar(250),khye decimal(15,6))<BR>&nbsp;在使用完毕#KHYEReturn后，应该立刻使用下列语句释放该临时表<BR>&nbsp;delete from #KHYEReturn<BR>&nbsp;drop Table #KHYEReturn<BR>&nbsp;*/</P>
<P>&nbsp;/*<BR>&nbsp;实现方法：<BR>&nbsp;&nbsp;<BR>&nbsp;*/</P>
<P>&nbsp;/*<BR>&nbsp;创建人：&nbsp;<BR>&nbsp;创建日期：</P>
<P>&nbsp;--对于改存储过程的版本更新记录在这个地方</P>
<P>&nbsp;*/<BR>&nbsp;<BR>&nbsp;Declare @SqlString nvarchar(1000)<BR>&nbsp;Declare @Cond nvarchar(250)</P>
<P>--&nbsp;制作查询条件，存入@Cond&nbsp;<BR>EXECUTE sp_MakeCond 'dwmc',@KHMC,@CXZT,@GSBM,@Cond output<BR>&nbsp;<BR>&nbsp;/*&nbsp; */<BR>&nbsp;set @SqlString = 'select dwmc,sum(xhsl*hsj) as xsje from xsdda where xsrq&lt;<A href="mailto:=@vJZRQ">=@vJZRQ</A> and ' + @Cond<BR>&nbsp;set @SqlString = @SqlString + ' group by dwmc'</P>
<P>&nbsp;Create table #sp_Math_KHYE_XSJE(dwmc nvarchar(250),xsje decimal(15,6))<BR>&nbsp;<BR>&nbsp;Declare @ParmDefinition nvarchar(100)<BR>&nbsp;set @ParmDefinition = <A href="mailto:'@vKHMC">'@vKHMC</A> nvarchar(250),@vJZRQ datetime'<BR><BR>--&nbsp;这个地方就是调用sp_executesql来执行动态SqlString并将结果返回到一张临时表里面<BR><BR>--&nbsp;在这里，曾经试图将结果返回到游标中间，但是没有成功。<BR>-- 根据资料 insert&nbsp;和 exec 是不能够嵌套执行的，不过在这个地方比较奇怪，这两个可以嵌套执行。<BR>-- 需要注意的地方：@ParmDefnition是用来定义在sp_executesql中间要使用的变量的。<BR>-- 曾经试验这个地方直接传一个字符串，不使用变量传递，结果报错。不知道有没有其它的人成功过<BR>--&nbsp;在@ParmDefinition后面就要传递一个变量列表，按照我的理解，<BR>-- 就是在这个地方给sp_executesql过程中要使用的变量（也就是Sql语句的变量）赋值<BR><BR>&nbsp;insert into #sp_Math_KHYE_XSJE EXECUTE sp_executesql&nbsp; @SqlString,&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @ParmDefinition,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @vKHMC=@KHMC,<BR>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; @vJZRQ=@JZRQ</P>
<P>&nbsp;/*&nbsp; */<BR>&nbsp;set @SqlString = ''<BR>&nbsp;set @SqlString = 'select dwmc,sum(bcsk+ysk) as fkje from xhskdda where skrq&lt;<A href="mailto:=@vJZRQ">=@vJZRQ</A> and ' + @Cond<BR>&nbsp;set @SqlString = @SqlString + ' group by dwmc'</P>
<P>&nbsp;Create table #sp_Math_KHYE_FKJE(dwmc nvarchar(250),fkje decimal(15,6))<BR>&nbsp;<BR>&nbsp;set @ParmDefinition=''<BR>&nbsp;set @ParmDefinition = <A href="mailto:'@vKHMC">'@vKHMC</A> nvarchar(250),@vJZRQ datetime'<BR>&nbsp;insert into #sp_Math_KHYE_FKJE EXECUTE sp_executesql&nbsp; @SqlString,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @ParmDefinition,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @vKHMC=@KHMC,<BR>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; @vJZRQ=@JZRQ<BR>&nbsp;<BR>&nbsp;Create Table #sp_Math_KHYE_Result(<BR>&nbsp;&nbsp;dwmc nvarchar(250),khye decimal(15,6))<BR><BR>-- 比较简单的Sql语句了，左联右联，BT的需求，只能用BT的写法</P>
<P>&nbsp;insert into #sp_Math_KHYE_Result<BR>&nbsp;select distinct T1.dwmc as dwmc,(T1.fkje-T1.xsje) as khye from<BR>&nbsp;(<BR>&nbsp;select <BR>&nbsp;&nbsp;#sp_Math_KHYE_XSJE.dwmc as dwmc,<BR>&nbsp;&nbsp;isnull(#sp_Math_KHYE_XSJE.xsje,0) as xsje,<BR>&nbsp;&nbsp;isnull(#sp_Math_KHYE_FKJE.fkje,0) as fkje<BR>&nbsp;from #sp_Math_KHYE_XSJE,#sp_Math_KHYE_FKJE<BR>&nbsp;where #sp_Math_KHYE_XSJE.dwmc*=#sp_Math_KHYE_FKJE.dwmc<BR>&nbsp;union<BR>&nbsp;select <BR>&nbsp;&nbsp;#sp_Math_KHYE_XSJE.dwmc as dwmc,<BR>&nbsp;&nbsp;isnull(#sp_Math_KHYE_XSJE.xsje,0) as xsje,<BR>&nbsp;&nbsp;isnull(#sp_Math_KHYE_FKJE.fkje,0) as fkje<BR>&nbsp;from #sp_Math_KHYE_XSJE,#sp_Math_KHYE_FKJE<BR>&nbsp;where #sp_Math_KHYE_FKJE.dwmc*=#sp_Math_KHYE_XSJE.dwmc<BR>&nbsp;) as T1</P>
<P>&nbsp;insert into #KHYEReturn select * from #sp_Math_KHYE_Result<BR>GO<BR><BR><BR>==================================================================<BR><BR><BR>CREATE Procedure sp_KHYEXYTJ<BR>&nbsp;@StartDate datetime,<BR>&nbsp;@EndDate datetime,<BR>&nbsp;@KHMC nvarchar(250),<BR>&nbsp;@CXZT int,<BR>&nbsp;@GSBM nvarchar(100)<BR>as<BR>&nbsp;/*<BR>&nbsp;功能：<BR>&nbsp;输入:<BR>&nbsp;&nbsp;@StartDate&nbsp;开始日期<BR>&nbsp;&nbsp;@EndDate&nbsp;&nbsp; &nbsp;截至日期<BR>&nbsp;&nbsp;@KHMC&nbsp;客户名称<BR>&nbsp;&nbsp;@CXZT&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;查询状态 0-表示精确，1-表示模糊，2-表示智能<BR>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;该状态仅对KHMC起作用<BR>&nbsp;&nbsp;@GSBM&nbsp;<BR>&nbsp;输出：<BR>&nbsp;&nbsp;<BR>&nbsp;&nbsp;表结构：<BR>&nbsp;&nbsp;&nbsp;dwmc&nbsp;ncye&nbsp;&nbsp;ssye&nbsp;&nbsp;bqxs&nbsp;&nbsp;qmye&nbsp;&nbsp;khxye&nbsp;&nbsp;cxye<BR>&nbsp;*/<BR>&nbsp;<BR>&nbsp;/*<BR>&nbsp;创建人：&nbsp;<BR>&nbsp;创建日期：</P>
<P>&nbsp;--对于改存储过程的版本更新记录在这个地方</P>
<P>&nbsp;*/<BR><BR>&nbsp;&nbsp;-- 这个地方求了一堆乱七八糟的数据，是需要用来输出的。</P>
<P>&nbsp;-- 求得表#sp_KHYEXYTJ_QMKHYE<BR>&nbsp;Create Table #sp_KHYEXYTJ_QMKHYE<BR>&nbsp;&nbsp;(dwmc nvarchar(250),QMkhye decimal(15,6))<BR>&nbsp;Create Table #KHYEReturn<BR>&nbsp;&nbsp;(dwmc nvarchar(250),khye decimal(15,6))<BR>&nbsp;execute sp_Math_KHYE @KHMC,@EndDate,@CXZT,@GSBM<BR>&nbsp;insert into #sp_KHYEXYTJ_QMKHYE(dwmc,QMKHYE) select * from #KHYEReturn<BR>&nbsp;delete from #KHYEReturn</P>
<P>&nbsp;-- 求得表#sp_KHYEXYTJ_QMKHYE<BR>&nbsp;Declare @NowDate datetime<BR>&nbsp;set @NowDate = GetDate()<BR>&nbsp;Create Table #sp_KHYEXYTJ_KHYE<BR>&nbsp;&nbsp;(dwmc nvarchar(250),khye decimal(15,6))<BR>&nbsp;execute sp_Math_KHYE @KHMC,@NowDate,@CXZT,@GSBM<BR>&nbsp;insert into #sp_KHYEXYTJ_KHYE select * from #KHYEReturn<BR>&nbsp;delete from #KHYEReturn</P>
<P>&nbsp;-- 求得表#sp_KHYEXYTJ_NCYE<BR>&nbsp;Create Table #sp_KHYEXYTJ_NCYE<BR>&nbsp;&nbsp;(dwmc nvarchar(250),ncye decimal(15,6))<BR>&nbsp;Set @NowDate=cast(str(year(GetDate()))+'-01-01 00:00:00' as datetime) <BR>&nbsp;execute sp_Math_KHYE @KHMC,@NowDate,@CXZT,@GSBM<BR>&nbsp;insert into #sp_KHYEXYTJ_NCYE select * from #KHYEReturn<BR>&nbsp;delete from #KHYEReturn<BR>&nbsp;drop table #KHYEReturn</P>
<P>&nbsp;--<BR>&nbsp;Declare @SqlString nvarchar(500)<BR>&nbsp;Declare @Cond nvarchar(100)<BR><BR>-- 这里也是求查询条件的地方<BR>&nbsp;EXECUTE sp_MakeCond 'dwmc',@KHMC,@CXZT,@GSBM,@Cond output</P>
<P>&nbsp;set @SqlString = 'select dwmc,sum(xhsl*hsj) as xsje from xsdda where xsrq&lt;<A href="mailto:=@vEndDate">=@vEndDate</A> and xsrq&gt;=@vStartDate and ' + @Cond<BR>&nbsp;set @SqlString = @SqlString + ' group by dwmc'</P>
<P>&nbsp;Create table #sp_KHYEXYTJ_XSJE(dwmc nvarchar(250),xsje decimal(15,6))<BR>&nbsp;<BR>&nbsp;Declare @ParmDefinition nvarchar(100)<BR>&nbsp;set @ParmDefinition = <A href="mailto:'@vKHMC">'@vKHMC</A> nvarchar(250),@vEndDate datetime,@vStartDate datetime'<BR>&nbsp;insert into #sp_KHYEXYTJ_XSJE EXECUTE sp_executesql&nbsp; @SqlString,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @ParmDefinition,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @vKHMC=@KHMC,<BR>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; @vEndDate=@EndDate,<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @vStartDate=@StartDate</P>
<P>&nbsp;-- 制作输出表<BR>&nbsp;Create Table #sp_KHYEXYTJ_ReslutTable<BR>&nbsp;&nbsp;(dwmc nvarchar(250),<BR>&nbsp;&nbsp;ncye decimal(15,6),<BR>&nbsp;&nbsp;ssye decimal(15,6),<BR>&nbsp;&nbsp;bqxs decimal(15,6),<BR>&nbsp;&nbsp;qmye decimal(15,6),<BR>&nbsp;&nbsp;khxye decimal(15,6),<BR>&nbsp;&nbsp;cxye decimal(15,6))<BR><BR>&nbsp; -- 下面就是一堆乱七八糟的东西了。本来是将数据放到游标中去，然后对游标进行循环处理<BR>&nbsp; --&nbsp; 不过好像速度却很慢，一共是3张数据表，三章表数据分别为1k,4k,2W，<BR>&nbsp; -- 用游标处理，最终返回统计表600条数据用了27秒，一个比较让人发傻的时间<BR>&nbsp; -- 可能是我写的不好吧，但是这个时间也确实太长了<BR>&nbsp; -- 所以，就又换成按照临时表来处理，分别将各个需要统计的数据分开统计，<BR>&nbsp; -- 然后放入到不同的临时表里面，最后再将所有的数据根据dwmc这个字段进行关联，一起输出。<BR>&nbsp; -- 最终查询结果，同样数据量，用时2秒钟。<BR>&nbsp; -- 对于这个时间来说，我还是比较满意的。因为算的数据比较多了，而且和前面用游标用了27s<BR>&nbsp; -- 根本就不是一个等量级。不管好坏，先可以拿出来见人了。</P>
<P>&nbsp;-- 写入输出表,并生成统计列表<BR>&nbsp;insert into #sp_KHYEXYTJ_ReslutTable(dwmc,bqxs) <BR>&nbsp;&nbsp;select dwmc,xsje from #sp_KHYEXYTJ_XSJE</P>
<P>&nbsp;-- 写入输出表<BR>&nbsp;update #sp_KHYEXYTJ_ReslutTable <BR>&nbsp;&nbsp;set #sp_KHYEXYTJ_ReslutTable.ssye = #sp_KHYEXYTJ_KHYE.khye<BR>&nbsp;&nbsp;from #sp_KHYEXYTJ_KHYE<BR>&nbsp;&nbsp;where #sp_KHYEXYTJ_ReslutTable.dwmc = #sp_KHYEXYTJ_KHYE.dwmc</P>
<P>&nbsp;--写入输出表<BR>&nbsp;update #sp_KHYEXYTJ_ReslutTable <BR>&nbsp;&nbsp;set #sp_KHYEXYTJ_ReslutTable.qmye = #sp_KHYEXYTJ_QMKHYE.QMkhye<BR>&nbsp;&nbsp;from #sp_KHYEXYTJ_QMKHYE<BR>&nbsp;&nbsp;where #sp_KHYEXYTJ_ReslutTable.dwmc = #sp_KHYEXYTJ_QMKHYE.dwmc</P>
<P>&nbsp;-- 写入输出表<BR>&nbsp;update #sp_KHYEXYTJ_ReslutTable <BR>&nbsp;&nbsp;set #sp_KHYEXYTJ_ReslutTable.ncye = #sp_KHYEXYTJ_NCYE.ncye<BR>&nbsp;&nbsp;from #sp_KHYEXYTJ_NCYE<BR>&nbsp;&nbsp;where #sp_KHYEXYTJ_ReslutTable.dwmc = #sp_KHYEXYTJ_NCYE.dwmc</P>
<P>&nbsp;-- 计算<BR>&nbsp;update #sp_KHYEXYTJ_ReslutTable<BR>&nbsp;&nbsp;set #sp_KHYEXYTJ_ReslutTable.khxye = isnull(xhkhda.khxye,0),<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #sp_KHYEXYTJ_ReslutTable.cxye = abs(#sp_KHYEXYTJ_ReslutTable.ssye)-isnull(xhkhda.khxye,0)<BR>&nbsp;&nbsp;from xhkhda<BR>&nbsp;&nbsp;where #sp_KHYEXYTJ_ReslutTable.dwmc = xhkhda.dwmc</P>
<P>&nbsp;--最终输出结果了，因为都是算得金额了，为了减小误差，在计算的时候<BR>&nbsp;-- 全部使用6位小数，在输出的时候，取了两位小数来输出</P>
<P>&nbsp;-- 输入表<BR>&nbsp;select <BR>&nbsp;&nbsp;rtrim(ltrim(dwmc)) as dwmc,<BR>&nbsp;&nbsp;cast(round(isnull(ncye,0),2) as decimal(15,2)) as ncye,<BR>&nbsp;&nbsp;cast(round(isnull(ssye,0),2) as decimal(15,2)) as ssye,<BR>&nbsp;&nbsp;cast(round(isnull(bqxs,0),2) as decimal(15,2)) as bqxs,<BR>&nbsp;&nbsp;cast(round(isnull(qmye,0),2) as decimal(15,2)) as qmye,<BR>&nbsp;&nbsp;cast(round(isnull(khxye,0),2) as decimal(15,2)) as khxye,<BR>&nbsp;&nbsp;cast(round(isnull(<BR>&nbsp;&nbsp;case<BR>&nbsp;&nbsp;&nbsp;when cxye&lt;= 0 then 0<BR>&nbsp;&nbsp;&nbsp;when cxye&gt;0 then cxye<BR>&nbsp;&nbsp;end,0),2) as decimal(15,2)) as cxye</P>
<P>&nbsp;from #sp_KHYEXYTJ_ReslutTable<BR>GO<BR><BR>这三个存储过程写的比较乱啦，毕竟是我的第一个存储过程嘛。可以谅解的。不过以后就不能写这么乱的存储过程了，否则不可饶恕。<BR><BR>在这三个存储过程中有一些地方写的还是不尽人意，比方说，存储过程A调用存储过程B，而存储过程B需要返回一个结果集供A使用。虽然用了一个临时表来作为存储用，可是总想象写OO一样，把临时表或者结果集象对象一样返回出去。记得在写这个地方的前一天偶然看了资料，可以把结果集放到游标中output出去。不过写的时候忘记了在什么地方看到的了，又犯了懒，所以干脆就直接使用一个临时表，反正游标返回出来后，也是要放到临时表里面去的嘛。</P><img src ="http://www.blogjava.net/jackybu/aggbug/1570.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-28 21:06 <a href="http://www.blogjava.net/jackybu/articles/1570.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>快速上手 MySQL －－图形化操作详解 </title><link>http://www.blogjava.net/jackybu/articles/1419.html</link><dc:creator>辰</dc:creator><author>辰</author><pubDate>Tue, 22 Feb 2005 04:41:00 GMT</pubDate><guid>http://www.blogjava.net/jackybu/articles/1419.html</guid><wfw:comment>http://www.blogjava.net/jackybu/comments/1419.html</wfw:comment><comments>http://www.blogjava.net/jackybu/articles/1419.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackybu/comments/commentRss/1419.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackybu/services/trackbacks/1419.html</trackback:ping><description><![CDATA[一、MySQL下载与安装
<DIV><STRONG><FONT size=4></FONT></STRONG>&nbsp;</DIV>
<DIV>&nbsp;<STRONG>1、下载介绍</STRONG></DIV>
<DIV><STRONG></STRONG>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp; MySQL相信大家一定听说过，如果不知道它是干什么的，可以去google一下。</DIV>
<DIV>&nbsp;&nbsp;&nbsp; MySQL的大本营：<A href="http://www.mysql.com/">http://www.mysql.com/</A></DIV>
<DIV>&nbsp;&nbsp;&nbsp; MySQL的下载地址：<A href="http://dev.mysql.com/downloads/">http://dev.mysql.com/downloads/</A>&nbsp;&nbsp; 因为要从这个地址下载不少东东，所以详细分析一下这个网页。&nbsp;&nbsp; </DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql001.jpg"></DIV>
<DIV>&nbsp;&nbsp;&nbsp; </DIV>
<DIV>&nbsp;</DIV>
<DIV>● 关于镜像网站，没有大陆的，有香港和台湾的。选择它，是为了加快下载速度，不过也不是绝对的，我经常就从北美的镜像下载，速度反而更快些。&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>● MySQL数据库服务器&nbsp; 这里我选择MySQL 4.1版本。版本太低，许多新特性用不上；太高，测试还没有完善，容易出Bug。这里选择它推荐的。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp; 点击这个链接，进入下载页面，可以看到，当前版本是4.1.8。找到“<STRONG>Windows downloads</STRONG>”，如图，因为我使用的是Windows平台。这里我选择“<STRONG>Without installer (unzip in C:\)”</STRONG>这个版本，因为我喜欢不需要安装的软件，用的不高兴，随时可以直接删除，当然需要自己配置一下才能使用。</DIV>
<DIV>&nbsp;&nbsp; 点击“Pick a mirror”,进入一个页面，那里的表格可以不填，直接选择一个链接下载它就可以了。下载后的文件名是“mysql-4.1.8-win-noinstall.zip”，大小是35.2M。</DIV>
<DIV>&nbsp;<IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql002.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV>● 关于“<STRONG>Graphical clients</STRONG>” 图形界面的客户端，选择一个吧，可以进行图形化操作，何乐而不为？只不过以前我一直用“MySQL Control Center”的，现在却不开发了。选择“MySQL Administrator”吧，下载后的文件名是“mysql-administrator-1.0.19-win-noinstall.zip”（这里我选择的是不需要安装版本），大小是4.5M。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp; 同样也选择“MySQL Query Browser”，它是来查询的。下载后的文件名是“mysql-query-browser-1.1.5-win-noinstall.zip”（不需要安装版本），大小是4.5M。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp; 关于这方面的软件比较多，如：MySQL-Front，EMS MySQL Manager等，比较好用，不过它们是要Money的。</DIV>
<DIV>&nbsp;</DIV>
<DIV>● “<STRONG>Application Programming Interfaces (APIs)</STRONG> ” 应用程序接口&nbsp; 由于我主要是面向Java应用，所以这里就选择“<STRONG>MySQL Connector/J</STRONG> ”，版本选择“MySQL Connector/J 3.0”，因为它是“Procdution”版本。下载后的文件名是“mysql-connector-java-3.0.16-ga.zip”，大小是1.2M。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV><STRONG>2、安装MySQL</STRONG></DIV>
<DIV><STRONG></STRONG>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;<SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN> 找到下载后的mysql-4.1.8-win-noinstall.zip，解压到D盘，是一个“mysql-4.1.8-win”文件夹，这里我把它改名为“mysql”，因为我不喜欢带版本号。即这时是“D:\mysql”目录，这个目录下有一个“data”目录，这里就是存放数据的地方。为了方便备份和升级，最好把它放在其它地方。这里我在D盘新建一个目录“mysql-data”，然后把“D:\mysql”目录下的“data”子目录剪切到“D:\mysql-data”目录中。</DIV>
<DIV>&nbsp;&nbsp; </DIV>
<DIV>&nbsp;&nbsp;<SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN>新建一个“my.ini”文件，注意后缀名是“ini”。内容如下：&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<TABLE border=0 borderColor=#000000 cellPadding=4 cellSpacing=0 width="75%">
<TBODY>
<TR>
<TD bgColor=#d9eaf2 height=33 style="BORDER-BOTTOM: rgb(51,51,204) thin inset" vAlign=top width="100%">
<DIV><FONT size=2><EM>E:\WINDOWS\my.ini</EM></FONT></DIV></TD></TR>
<TR>
<TD bgColor=#edf2b8 style="BORDER-TOP-COLOR: rgb(236,233,216); BORDER-TOP-STYLE: none" vAlign=top width="100%">
<DIV><FONT size=2>[WinMySQLAdmin]<BR>&nbsp;&nbsp; <FONT color=#0000ff>Server</FONT>=D:/mysql/bin/mysqld-nt.exe<BR>&nbsp;&nbsp; <BR>[mysqld]<BR>&nbsp;&nbsp; <FONT color=#0000ff>basedir</FONT>=D:/mysql<BR>&nbsp;&nbsp; <FONT color=#0000ff>datadir</FONT>=D:/mysql-data/data</FONT></DIV></TD></TR></TBODY></TABLE></DIV>
<DIV>&nbsp; 上面“Server”指向<FONT size=4><FONT size=3>MySQL</FONT>的执行主程序，“basedir”指向MySQL的安装目录，“datadir”指向MySQL的数据存放目录（因为我改变了它，所以需要特别指定）。</FONT></DIV>
<DIV><FONT size=4>&nbsp; </FONT>然后把这个文件移动到<STRONG>Windows的系统安装目录</STRONG>下，我这里是“E:\WINDOWS”。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;<SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN> 打开MS-DOS窗口，切换到“D:\mysql\bin”目录；或者把“D:\mysql\bin”添加到“环境变量”的“Path”变量中，这样可以避免切换到“D:\mysql\bin”目录。</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>&nbsp; ·</FONT></SPAN>加入到Windows XP的服务中：</DIV>
<DIV>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体>D:\mysql\bin&gt; <FONT color=#0000ff>mysqld-nt&nbsp; -install</FONT>&nbsp;&nbsp;</FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体>&nbsp;&nbsp;&nbsp;（这时打开“控制面板”-&gt;管理工具-&gt;服务：可以看到服务列表中存在“MySQL”服务，如果不希望它自动执行，可以改为手动，不用它的时候可以节省点内存）</FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql006.jpg"></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><BR><FONT face=宋体>&nbsp;&nbsp;<STRONG>&nbsp;· </STRONG>启动和停止mysql服务<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:\mysql\bin&gt;<FONT color=#0000ff>net&nbsp; start mysql</FONT> <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; D:\mysql\bin&gt;<FONT color=#0000ff>net&nbsp; stop&nbsp; mysql</FONT></FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"></SPAN>&nbsp;</DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql003.jpg"></FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>&nbsp;&nbsp; · </FONT></SPAN><FONT face=宋体>移出mysql服务</FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT color=#0000ff>mysqld-nt --remove</FONT></FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体>&nbsp;&nbsp; （如果你不再需要MySQL了，先停止MySQL服务，然后再移出MySQL服务，最后删除MySQL安装目录即可）</FONT></SPAN></DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"><FONT face=宋体></FONT></SPAN>&nbsp;</DIV>
<DIV><SPAN lang=EN style="FONT-FAMILY: Arial; FONT-SIZE: 12pt"></SPAN><STRONG><FONT size=4>二、基本操作</FONT></STRONG>&nbsp;&nbsp; </DIV>
<DIV>&nbsp;</DIV>
<DIV>● <STRONG>准备工作</STRONG></DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp; 在D盘建立一个mysql-software的目录，把刚才下载的 mysql-administrator-1.0.19-win-noinstall.zip 复制到这个子目录中，解压，得到一个 MySQL Administrator 1.0 的目录。</DIV>
<DIV>&nbsp; 同样如此操作 mysql-query-browser-1.1.5-win-noinstall.zip，得到一个 MySQL Query Browser 1.1 的目录。</DIV>
<DIV>&nbsp;&nbsp; </DIV>
<DIV>&nbsp;</DIV>
<DIV>● <STRONG>启动服务</STRONG>：</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN>&nbsp;双击D:\mysql-software\MySQL Administrator 1.0 目录下的 MySQLSystemTrayMonitor.exe，这时会在任务栏右侧出现一个图标。点击“Start Instance”,运行MySQL。</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql008.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>· </FONT></SPAN></SPAN>然后双击 D:\mysql-software\MySQL Administrator 1.0 目录中的 MySQLAdministrator.exe，或者直接点击上面右键菜单中的“MySQL Administrator ”：</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql007.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN> 创建一个连接名，可以随便填，这里是“mxj”，用户名：root，密码空着。这是因为mysql默认有一个没有密码的root帐号。点击“OK”，出现管理窗口：</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql009.jpg"></DIV>
<DIV>这没什么好说的，英文也很简单。只谈谈上面勾选的两项。</DIV>
<DIV>&nbsp;</DIV>
<DIV>● <STRONG>更改密码</STRONG></DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql010.jpg"></DIV>
<DIV>好了，我的root帐号的密码设置为：javamxj&nbsp;&nbsp; 最后，点击“Apply Change”。</DIV>
<DIV>&nbsp;</DIV>
<DIV>● 初始的数据库</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql011.jpg"></DIV>
<DIV>&nbsp; 上图可以看到，初始有两个数据库，mysql库中含有各种配置信息，不要在这个库中进行表操作。</DIV>
<DIV>test库初始是空的。<EM>另外，建立表时，不要和mysql库中的表名取名相同，以免冲突</EM>。</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>● <STRONG>数据创建与查询（兼谈谈字符编码）</STRONG></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN>现在来到查询浏览器，还是右击右下角“MySQL System Tray Monitor”图标，从中选择“MySQL Query Browser”，因为已经更改过root的密码，所以要填入新密码。</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql012.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·</FONT></SPAN></SPAN> 进入主界面，右击test数据库，创建一个新表。</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql013.jpg">&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3></FONT></SPAN></SPAN>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>·&nbsp; </FONT></SPAN></SPAN>如下简单创建一个表</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql014.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>· </FONT></SPAN></SPAN>切换到“Table Options”：</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql015.jpg"></DIV>
<DIV>&nbsp;&nbsp; 如果了解数据库的话，这些应该是很熟悉的，不多说了。注意字符设置默认是“Latin1”（保存改变，再次切换到这一栏，就能看到了）。</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>· </FONT></SPAN></SPAN>填入一些测试数据：</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql016.jpg"></DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>· </FONT></SPAN></SPAN>关闭“MySQL Query Browser”，再重新打开它，切换到testtable表，看到了没有？刚才输入的中文变成了“？？？？？？”，为什么呢？ 再次切换到“Table Options”：</DIV>
<DIV><IMG src="http://blog.csdn.net/images/blog_csdn_net/javamxj/87325/o_mysql017.jpg"></DIV>
<DIV>&nbsp;知道为什么了吧，原来默认字符是“latin1”，因为MySQL是瑞典一家公司的产品。中国人看来要努力了！</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'">● </SPAN>解决方法：</DIV>
<DIV>&nbsp;</DIV>
<DIV><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><SPAN style="FONT-FAMILY: 宋体; FONT-SIZE: 10.5pt; mso-bidi-font-family: 'Times New Roman'; mso-ascii-font-family: 'Times New Roman'; mso-hansi-font-family: 'Times New Roman'; mso-bidi-font-size: 12.0pt; mso-font-kerning: 1.0pt; mso-ansi-language: EN-US; mso-fareast-language: ZH-CN; mso-bidi-language: AR-SA"><FONT size=3>· </FONT></SPAN></SPAN>停止MySql服务，关闭所有与MySql相关的程序，打开<STRONG>Windows的系统安装目录</STRONG>下的 my.ini 文件，如下修改：</DIV>
<DIV>
<TABLE border=0 borderColor=#000000 cellPadding=4 cellSpacing=0 width="75%">
<TBODY>
<TR>
<TD bgColor=#d9eaf2 height=33 style="BORDER-BOTTOM: rgb(51,51,204) thin inset" vAlign=top width="100%">
<DIV><FONT size=2><EM>E:\WINDOWS\my.ini</EM></FONT></DIV></TD></TR>
<TR>
<TD bgColor=#edf2b8 style="BORDER-TOP-COLOR: rgb(236,233,216); BORDER-TOP-STYLE: none" vAlign=top width="100%">
<DIV><FONT size=2>[WinMySQLAdmin]<BR>&nbsp;&nbsp; <FONT color=#0000ff>Server</FONT>=D:/mysql/bin/mysqld-nt.exe<BR>&nbsp;&nbsp; <BR>[mysqld]<BR>&nbsp;&nbsp; <FONT color=#0000ff>basedir</FONT>=D:/mysql<BR>&nbsp;&nbsp; <FONT color=#0000ff>datadir</FONT>=D:/mysql-data/data</FONT></DIV>
<DIV>&nbsp;&nbsp; <FONT size=2><FONT color=#0000ff>default-character-set</FONT>=gbk<BR>&nbsp;&nbsp; <BR>[client]<BR>&nbsp;&nbsp; <FONT color=#0000ff>default-character-set</FONT>=gbk</FONT></DIV></TD></TR></TBODY></TABLE></DIV>
<DIV>添加的两条语句的含义是在客户端和服务端都使用GBK字符集进行编码。</DIV>
<DIV>&nbsp;</DIV>
<DIV>保存后，重新激活 MySql 服务，打开“MySQL Query Browser”，再次创建一个表，输入中文，一切OK！</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;</DIV>
<DIV><STRONG><FONT size=4>后记</FONT></STRONG>&nbsp;&nbsp; </DIV>
<DIV>&nbsp;</DIV>
<DIV>&nbsp;&nbsp;&nbsp;关于在DOS端如何用命令行进行 MySQL 的操作，这里就不谈了，网上这方面的资料很多。图形界面进行 MySQL 操作的软件还有很多，不过大多数是需要破费的。自己看着用吧。</DIV>
<DIV></DIV>
<DIV>&nbsp;&nbsp;&nbsp;至于 mysql-connector-java-3.0.16-ga.zip 这个文件，在以后开发 EJB 的时候会用到的，到时再说。</DIV><img src ="http://www.blogjava.net/jackybu/aggbug/1419.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackybu/" target="_blank">辰</a> 2005-02-22 12:41 <a href="http://www.blogjava.net/jackybu/articles/1419.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>