2010-04-01 53 views
5

我一直在工作一个ADO VBScript,需要接受参数并将这些参数合并到传递数据库的查询字符串中。记录集对象尝试打开时,我不断收到错误。如果我传递一个没有参数的查询,记录集打开,我可以使用这些数据。当我通过调试器运行脚本时,命令对象不会显示参数对象的值。在我看来,我缺少一些与Command对象和Parameter对象相关的东西,但我不知道是什么。这里是一些VBScript代码:如何使用VBScript将参数关联到ADO中的命令对象?

... 
'Open Text file to collect SQL query string' 
Set fso = CreateObject("Scripting.FileSystemObject") 
fileName = "C:\SQLFUN\Limits_ADO.sql" 
Set tso = fso.OpenTextFile(fileName, FORREADING) 

SQL = tso.ReadAll 

'Create ADO instance' 
connString = "DRIVER={SQL Server};SERVER=myserver;UID=MyName;PWD=notapassword; Database=favoriteDB" 
Set connection = CreateObject("ADODB.Connection") 
Set cmd = CreateObject("ADODB.Command") 

    connection.Open connString 
    cmd.ActiveConnection = connection 
    cmd.CommandText = SQL 
    cmd.CommandType = adCmdText 

    Set paramTotals = cmd.CreateParameter 
    With paramTotals 
     .value = "tot%" 
     .Name = "Param1" 
    End With 

    'The error occurs on the next line' 
    Set recordset = cmd.Execute 

    If recordset.EOF then 
     WScript.Echo "No Data Returned" 
    Else 
     Do Until recordset.EOF 
      WScript.Echo recordset.Fields.Item(0) ' & vbTab & recordset.Fields.Item(1) 
      recordset.MoveNext 
     Loop 
    End If 

我使用的SQL字符串是相当标准的,除了我想传递一个参数给它。这是这样的:

SELECT column1 
FROM table1 
WHERE column1 IS LIKE ? 

据我所知,ADO应该取代“?”在脚本中分配参数值。我看到的问题是Parameter对象显示正确的值,但根据我的调试器,命令对象的参数字段为空。

回答

2

我从来没有得到CreateParameter做我想要的。正确的参数化是避免SQL注入的必要条件,但CreateParameter是一个完整的PITA。值得庆幸的是,还有一个选择:Command.Execute直接接受参数。

dim cmd, rs, rows_affected 
set cmd = Server.createObject("adodb.command") 
cmd.commandText = "select from Foo where id=?" 
set cmd.activeConnection = someConnection 
set rs = cmd.execute(rows_affected, Array(42)) 

在适当的抽象中包装它会更好。我写了自己的数据库类包装ADODB.Connection,所以我不必手动完成所有这些。它依赖于其他自定义类了一点,但它的精神应该是显而易见的:

class DatabaseClass 
' A database abstraction class with a more convenient interface than 
' ADODB.Connection. Provides several simple methods to safely query a 
' database without the risk of SQL injection or the half-dozen lines of 
' boilerplate otherwise necessary to avoid it. 
' 
' Example: 
' 
' dim db, record, record_set, rows_affected 
' set db = Database("/path/to/db") 
' set record = db.get_record("select * from T where id=?;", Array(42)) 
' set record_set = db.get_records("select * from T;", empty) 
' rows_affected = db.execute("delete from T where foo=? and bar=?", 
'        Array("foo; select from T where bar=", true)) 

    private connection_ 
'  An ADODB connection object. Should never be null. 

    private sub CLASS_TERMINATE 
     connection_.close 
    end sub 

    public function init (path) 
'  Initializes a new database with an ADODB connection to the database at 
'  the specified path. Path must be a relative server path to an Access 
'  database. Returns me. 

     set connection_ = Server.createObject ("adodb.connection") 
     connection_.provider = "Microsoft.Jet.OLEDB.4.0" 
     connection_.open Server.mapPath(path) 

     set init = me 
    end function 

    public function get_record (query, args) 
'  Fetches the first record returned from the supplied query wrapped in a 
'  HeavyRecord, or nothing if there are no results. 

     dim data: set data = native_recordset(query, args) 
     if data.eof then 
      set get_record = nothing 
     else 
      set get_record = (new HeavyRecordClass).init(data) 
     end if 
    end function 

    public function get_records (query, args) 
'  Fetches all records returned from the supplied query wrapped in a 
'  RecordSet (different from the ADODB recordset; implemented below). 

     set get_records = (new RecordSetClass).init(native_recordset(query, args)) 
    end function 

    public function execute (query, args) 
'  Executes the supplied query and returns the number of rows affected. 

     dim rows_affected 
     build_command(query).execute rows_affected, args 
     execute = rows_affected 
    end function 

    private function build_command (query) 
'  Helper method to build an ADODB command from the supplied query. 

     set build_command = Server.createObject("adodb.command") 
     build_command.commandText = query 
     set build_command.activeConnection = connection_ 
    end function 

    private function native_recordset (query, args) 
'  Helper method that takes a query string and array of arguments, queries 
'  the ADODB connection, and returns an ADODB recordset containing the 
'  result. 

     set native_recordset = build_command(query).execute(, args) ' Omits out-parameter for number of rows 
    end function 
end class 
+0

这对我有用---谢谢!读者请注意:'.Execute'的'Parameters'参数采用'Variant'。如果参数的数量和格式与查询期望的不匹配,您将得到非常模糊的错误消息! – cxw 2017-10-12 18:33:59

0

创建参数后,必须将其追加到Command对象的参数集合执行命令前:

Set paramTotals = cmd.CreateParameter 
With paramTotals 
    .Value = "tot%" 
    .Name = "Param1" 
End With 

cmd.Parameters.Append paramTotals 

您可能还需要指定参数的TypeSize属性。一般情况下,我使用CreateParameter函数的参数在一行中设置所有必要的属性:

Set paramTotals = cmd.CreateParameter("Param1", adVarChar, adParamInput, 30, "tot%") 
cmd.Parameters.Append paramTotals 
6

我知道这是老了,但仍然有人fiding这个(就像我通过谷歌所做的那样):

如果你使用存储过程:

set cmd = Server.CreateObject("ADODB.Command") 
with cmd 
    .ActiveConnection = db_connection 
    .CommandText = "stored_procedure_name" 
    .CommandType = adCmdStoredProc 
    .Parameters.Append .CreateParameter("@Parameter1",adInteger,adParamInput,,1) 
     .Parameters.Append .CreateParameter("@Parameter2",adVarChar,adParamInput,100,"Up to 100 chars") 
     .Parameters.Append .CreateParameter("@Parameter3",adBoolean,adParamInput,,true) 
     .Parameters.Append .CreateParameter("@Parameter4",adDBTimeStamp,adParamInput,,now()) 
end with 
set rs = cmd.execute 
    'do stuff with returned results from select or leave blank if insert/delete/etc stored procedure 
set rs = nothing 
set cmd = nothing 

如果没有,我beleive你在的地方改变.CommandText到您的SQL语句,问号和您的参数必须遵循相同的顺序。

请参阅http://www.devguru.com/technologies/ado/quickref/command_createparameter.html 有关CreateParameter传递的值的详细信息以及类型及其描述的列表。

相关问题