我一直在使用ADO VBScript,它需要接受参数并将这些参数合并到传递数据库的Query字符串中。当记录集对象尝试打开时,我不断收到错误。如果我传递没有参数的查询,记录集将打开,我可以处理数据。当我通过调试器运行脚本时,命令对象不显示参数对象的值。在我看来,我错过了与Command对象和Parameter对象相关联的东西,但我不知道是什么。这里有一些VBScript代码:
...
'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对象显示正确的值,但根据我的调试器,命令对象的参数字段为null。
答案 0 :(得分:5)
答案 1 :(得分:3)
我从来没有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
答案 2 :(得分:1)
创建参数后,必须在执行命令之前将其附加到Command对象的Parameters集合中:
Set paramTotals = cmd.CreateParameter
With paramTotals
.Value = "tot%"
.Name = "Param1"
End With
cmd.Parameters.Append paramTotals
您可能还需要为参数指定Type
和Size
属性。通常,我使用CreateParameter函数的参数在一行中设置所有必需的属性:
Set paramTotals = cmd.CreateParameter("Param1", adVarChar, adParamInput, 30, "tot%")
cmd.Parameters.Append paramTotals