2010-04-01 4 views
5

Ho lavorato a un VBScript ADO che deve accettare i parametri e incorporare tali parametri nella stringa di query che viene passata al database. Continuo a ricevere errori quando l'oggetto Record Set tenta di aprirsi. Se passo una query senza parametri, si apre il recordset e posso lavorare con i dati. Quando eseguo lo script tramite un debugger, l'oggetto comando non mostra un valore per l'oggetto parametro. Mi sembra che mi manca qualcosa che associa l'oggetto Command e l'oggetto Parameter, ma non so cosa. Ecco un po 'di codice VBScript:Come associo i parametri agli oggetti Command in ADO con 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 

La stringa SQL che uso è abbastanza standard, tranne che voglio passare un parametro ad esso. E 'qualcosa di simile: "?"

SELECT column1 
FROM table1 
WHERE column1 IS LIKE ? 

Capisco che ADO dovrebbe sostituire la con il valore del parametro che assegno nello script. Il problema che sto vedendo è che l'oggetto Parameter mostra il valore corretto, ma il campo del parametro dell'oggetto comando è nullo secondo il mio debugger.

risposta

2

non ho mai avuto CreateParameter a fare quello che volevo. Parametrizzazione corretta è una necessità per evitare l'iniezione SQL, ma CreateParameter è un PITA completo. Per fortuna, c'è un'alternativa: Command.Execute accetta direttamente i parametri.

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)) 

È molto più bello quando è avvolto in un'astrazione adeguata. Ho scritto il mio database di classe wrapping classe ADODB.Connection quindi non avrei dovuto fare tutto questo manualmente. Essa si basa un po 'su altre classi personalizzate, ma l'essenza di esso dovrebbe essere evidente:

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

Questo ha funzionato per me --- grazie! I lettori notano che l'argomento 'Parameters' su' .Execute' richiede un 'Variant'. Riceverai messaggi di errore molto oscuri se il numero e i formati dei tuoi parametri non corrispondono a quelli che la query si aspetta! – cxw

0

Dopo aver creato il parametro, bisogna aggiungerlo alla collezione Parameters dell'oggetto Command prima di eseguire il comando:

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

cmd.Parameters.Append paramTotals 

potrebbe anche essere necessario per specificare le proprietà Type e Size per il parametro. In generale, io uso gli argomenti della funzione CreateParameter per impostare tutte le proprietà necessarie in una sola riga:

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

So che questo è vecchio, ma per chiunque ancora fiding questo (come ho fatto io tramite google):

Procedure Se stai utilizzando le stored:

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 

in caso contrario, ho beleive si cambia il .CommandText per l'istruzione SQL con punti interrogativi al posto ei tuoi parametri devono seguire lo stesso ordine.

Vedere http://www.devguru.com/technologies/ado/quickref/command_createparameter.html Per un elenco di quali valori si sta passando con CreateParameter, nonché un elenco di tipi e le relative descrizioni.

Problemi correlati