使用命令对象

命令对象代表一个命令（例如，一个SQL查询或一个SQL存储过程）。第22章，“Activex数据对象”，和第23章，“使用记录集”，分别介绍了如何用连接对象的Execute方法和记录集对象的Open方法执行命令字符串。考虑下面这两个例子：

RS.Open

“SELECT * FROM Mytable”,MyConn

MyConn.Execute

“UPDATE Mytable SET Mycolumn=’Hello’”

这两个例子都使用了SQL命令字符串。在第一个例子中，用命令字符串打开记录集。在第二个例子中，执行命令字符串来更新数据。

代替命令字符串，你可以使用命令对象。命令对象可以用来代表一个专门的命令。你可以用命令对象的一个实例返回记录集或执行一个不返回记录集的SQL命令。这里有一个例子：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandText=

”UPDATE Mytable SET Mycolumn=’Hello’”

MyCommand.CommandType=adCMDText

MyCommand.Execute

MyConn.Close

%>

在这个例子中，创建了命令对象的一个实例。接着，ActiveConnection属性把命令和 一个打开的连接联系在一起。（用Set语句完成这个任务，因为你是在分配一个对象。）CommandText属性指定要执行什么SQL语句。CommandType属性指明该命令是一个命令的文本定义。最后，调用Execute方法执行这个命令。

在这个例子中，命令对象用来返回一个记录集。但是，使用命令对象，你可以通过两种途径返回记录集。这是第一种途径：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdText

MyCommand.commandText=

”SELECT * FROM Mytable”

Set RS=MyCommand.Execute()

RS.Close

MyConn.Close

%>

在这段脚本中，命令对象的Execute()方法被用来返回一个记录集。注意引号的使用，因为该方法被用来返回结果。用命令对象创建了记录集对象的一个实例后，你可以用标准的方式操作它。

你也可以和一个已经存在的记录集一起使用命令对象，象这样：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

Set RS=Sever.CreateObject(

“ADODB.RecordSet”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdText

MyCommand.commandText=

”SELECT * FROM Mytable”

RS.Open MyCommand,adOpenStatic,adLockOptimstic

RS.Close

MyConn.Close

%>

用命令对象打开一个已经存在的记录集对象的好处是你可以指定记录集的游标和锁定类型。在这个例子中，命令对象用来打开一个使用静态游标和adLockOptimistic锁定的记录集。注意打开记录集时如果使用了命令对象，那么你不需指定连接对象，命令对象决定该使用哪个连接。

上面的例子讲述了如何使用命令对象。但是没有讲述为什么要使用连接对象。为什么你要专门创建一个命令对象，而不使用命令字符串呢？

使用命令对象有一个主要的优点。你可以和命令对象一起使用SQL存储过程。

使用SQL存储过程有什么好处

第12章，“高级SQL”，讲述了如何创建SQL存储过程。当你建设好一个站点后，把尽可能多的SQL命令转换为存储过程是个好主意。与其在ASP网页内部执行SQL查询，不如调用包含这些查询的存储过程。

使用SQL存储过程的理由有很多：

■SQL存储过程执行起来比SQL命令文本快得多。当一个SQL语句包含在存储过程中时，服务器不必每次执行它时都要分析和编译它。

■你可以在多个网页中调用同一个存储过程。这使你的站点易于维护。如果一个SQL语句需要做某些改动，你只要做一次即可。

■你可以在存储过程中利用Transact-SQL的强大功能。一个SQL存储过程可以包含多个SQL语句。你可以使用变量和条件。这意味着你可以用存储过程建立非常复杂的查询，以非常复杂的方式更新数据库。

■最后，这也许是最重要的，在存储过程中可以使用参数。你可以传送和返回参数。你还可以得到一个返回值（从SQL RETURN语句）。

简而言之，能用存储过程就要用存储过程。存储过程有着极大的优点

使用命令对象调用存储过程

假设你想取出表Mytable中的所有记录并在一个ASP网页中显示它们。而且，假设你想以尽可能高效的方式从表中取出记录。在这种情况下，你应该使用存储过程。

要建立应该新的存储过程，从Microsoft SQL Sever程序组中启动ISQL/w。然后，在查询窗口中输入以下的文本：

CREATE PROCEDURE sp_myporc AS

SELECT * FROM Mytable

单击执行查询按钮（看起来象一个绿色三角形），建立这个存储过程。该存储过程的名字是sp_myproc。

要在一个ASP网页中调用sp_myproc，你可以使用命令对象的一个实例。这里有一个例子：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdStoredProc

MyCommand.commandText=

”sp_myproc”

Set RS=MyCommand.Execute()

WHILE NOT RS.EOF

Response.Write(

“<BR>”&RS(“Mycolumn”))

RS.MoveNext

WEND

RS.Close

MyConn.Close

%>

这段脚本通过调用存储过程sp_myproc取出记录，显示了表Mytable中的所有记录。当你用命令对象调用存储过程时，你应该把该命令对象的CommandType属性设为adCMDStoredProc。CommandText属性用来指定要调用的存储过程。

使用返回状态值

你可以用命令对象从一个存储过程得到返回状态值。例如，假设你想统计一个表中的记录总数。效率最高的方法是建立一个存储过程，如下例所示：

CREATE PROCEDURE sp_CountMytabe AS

RETURN(SELECT COUNT(*) FROM Mytable)

这个存储过程返回表Mytable中的记录总数。SQL集合函数COUNT（）计算该表中的记录数。RETURN语句返回这个数。

要得到一个存储过程的返回状态值，你必须为命令对象建立一个参数。命令对象有一个名为Parameters的集合，是一个参数对象的集合。

你可以用命令对象的CreateParameter()方法建立一个参数。接下来，用Append方法把这个参数添加到命令对象的Parameters集合中。这里有一个例子：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdStoredProc

MyCommand.CommandText=

“sp_CountMytable”

Set MyParam=Mycommand.CreateParameter(

“RetVal”,adInteger,adParamReturnValue)

MyCommand.Parameters.Append MyParam

MyCommand.Execute

%>

There are <%=MyCommand(

“RetVal”)%> records in Mytable.

<%

MyConn.Close

%>

在这个脚本中，用CreateParameter()方法建立了一个参数对象。此例中CreateParameter()方法有三个参数：

- 第一个参数为新参数指定一个名字。

- 第二个参数指定数据类型。

- 最后，第三个参数指定新参数的类型。在此例中，常量adParamReturnValue指明该参数是一个返回参数。

建立了任何新参数之后，都必须把它添加到命令对象的Parameters集合中。Append方法用来把新参数添加到这个集合中。

命令执行后，参数的值可以被取出。因为该参数是命令对象的Parameters集合中的一员，用MyCommand(

“RetVal”)可以返回该参数的值。实际上，用以下的任何一个表达式都可以得到这个值：

MyCommand(

“RetVal”)

MyCommand(0)

MyCommand.Parameters(

“RetVal”)

MyCommand.Parameters(0)

MyCommand.Parameters.Item(

“RetVal”)

MyCommand.Parameters.Item(0)

这些方法都可以用来取出一个参数的值，因为一个参数是命令对象的参数集合的一部分。注意，对所有的集合，你都可以通过名字或顺序号指定一个参数。

使用输出参数

上一节的例子演示了如何得到返回状态值。从一个存储过程取出输出参数值与此非常相似。使用输出参数的好处是输出参数可以有一个或多个。而且，输出参数可以是任何数据类型。

比如有一个表Webusers保存了在你站点上注册的用户的名字。这个表只有一个字段UserName。现在假设你想取出按字母顺序排在最前和最后的用户名。你可以使用下面的存储过程：

CREATE PROCEDURE sp_HighAndLow

(@HighUser VARCHAR(30) OUTPUT,@LowUser VARCHAR(30) OUTPUT)

AS

SELECT @HighUser=MAX(UserName) FROM Webusers

SELECT @LowUser=MIN(UserName) FROM WebUsers

这个存储过程有两个输出参数，@HighUser和@LowUser。@HighUser包含按字母顺序排在最后的用户名（例如，Zeek Zimmerman）。@LowUser包含按字母顺序排在最前的用户名（例如，Anne Arnold）。

要在ASP网页中调用这个存储过程，你可以使用如下的脚本：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdStoredProc

MyCommand.CommandText=

“sp_HighandLow”

Set MyFirstParam=MyCommand.CreateParameter(

“HighUser”,adVarChar,adParamOutput,30)

MyCommand.Parameters.Append.MyFirstParam

Set MySecondParam=MyCommand.CreateParameter(

“LowUser”,adVarChar,adParamOutput,30)

MyCommand.ParaMeters.Append MySecondParam

MyCommand.Execute

%>

<p>The person with the alphabetically Hiighest name is

<%=MyCommand(

“HighUser”)%>

<p>The person with the alphabetically lowest name is

<%=MyCommand(

“LowUser”)%>

<%

MyConn.Close

%>

这个脚本的结构与上一个非常相似。在这个脚本中，用CreateParameter（）方法创建了两个参数对象，两个参数都被定义为VARCHAR型。为了指明它们是输出参数，使用了常量adParamOutput。最后，在CreateParameter()方法中指定了每个参数的最大长度，30。当你建立的参数是变长度数据类型，如VARCHAR型时，你必须指定一个最大长度。

使用输入参数

现在讨论另外一种参数。SQL存储过程可以接收输入参数。输入参数使你能够把数据传递给存储过程。

例如，假设有一个表保存了用户名和密码。假设你想建立一个检查密码的存储过程。使用下面的这个存储过程，你可以检查一个用户是否输入了合法的密码。

CREATE PROCEDURE sp_CheckPass

(@CHKName VARCHAR(30),@CHKPass VARCHAR(30),@ISValid CHAR(4) OUTPUT)

AS

IF EXISTS(SELECT UserName FROM WebUsers

WHERE

UserName=@CHKName AND UserPass=@CHKPass)

SELECT @ISVaid=

”Good”

ELSE

SELECT @ISValid=

”Bad”

这个存储过程接收两个输入参数。输入参数@CHKaName向存储过程传递一个用户名。@CHKPass向存储过程传递一个密码。如果有用户拥有指定的密码，输出参数将返回“Good

”，否则，返回“Bad”。

使用输入参数的方法与使用输出参数的方法非常相似。关键的差别是，命令执行前必须给输入参数分配一个值。这里有一个例子：

<!--#INCLUDE VIRTUAL=

”ADOVBS.inc”-->

<%

Set MyConn=Sever.CreateObject(

“ADODB.Connection”)

Set MyCommand=Sever.CreateObject(

“ADODB.Command”)

MyConn.Open

“FILEDSN=d:\Program Files\

Common Files\ODBC\Data Sources\MyData.dsn

Set MyCommand.ActiveConnection=MyConn

MyCommand.CommandType=adCMdStoredProc

MyCommand.CommandText=

“sp_CheckPass”

Set MyFirstParam=MyCommand.CreateParameter(

“UserName”,adVarChar,adParamIntput,30)

MyCommand.Parameters.Append.MyFirstParam

Set MySecondParam=MyCommand.CreateParameter(

“UserPass”,adVarChar,adParamInput,30)

MyCommand.ParaMeters.Append MySecondParam

Set MyThirdParam=MyCommand.CreateParameter(

“RetValue”,adChar,adParamOutput,4)

MyCommand.Parameters.Append MyThirdParam

MyCommand(

“UserName”)=”Bill Gates”

MyCommand(

“UserPass”)=”Billions”
MyCommand.Execute

%>

The password is <%=Mycommand(

“RetValue”)%>

<%

MyConn.Close

%>

在这个例子中，名字Bill Gates和密码Billions被传递给存储过程。如果表中存在这个名字－密码组合，则报告该密码为Good,否则报告该密码为Bad。

在这个脚本中，用常量adParamInput指定两个输入参数。注意两个输入参数在命令执行前都被分配了一个值。