2010-04-01 10 views
5

Ich habe ein ADO-VBScript bearbeitet, das Parameter akzeptieren muss und diese Parameter in die Query-Zeichenfolge aufnehmen muss, die an die Datenbank übergeben wird. Ich bekomme immer wieder Fehler, wenn das Record Set Object versucht zu öffnen. Wenn ich eine Abfrage ohne Parameter übergebe, wird das Recordset geöffnet und ich kann mit den Daten arbeiten. Wenn ich das Skript über einen Debugger ausführe, zeigt das Befehlsobjekt keinen Wert für das Parameterobjekt an. Mir scheint, dass mir etwas fehlt, das das Command-Objekt und das Parameter-Objekt assoziiert, aber ich weiß nicht, was. Hier ist ein wenig von dem VBScript-Code:Wie verknüpfe ich Command-Objekte in ADO mit VBScript mit Parametern?

... 
'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 

Die SQL-Zeichenfolge, die ich benutze ist ziemlich Standard, außer ich einen Parameter zu übergeben will. Es ist so etwas wie dieses: „?“

SELECT column1 
FROM table1 
WHERE column1 IS LIKE ? 

Ich verstehe, dass ADO die ersetzen soll mit dem Parameterwert, den ich im Skript zugewiesen habe. Das Problem, das ich sehe, ist, dass das Parameter-Objekt den richtigen Wert zeigt, aber das Parameterfeld des Befehlsobjekts ist laut meinem Debugger null.

Antwort

2

Ich habe nie CreateParameter tun, was ich wollte. Die korrekte Parametrisierung ist eine Notwendigkeit, um eine SQL-Injektion zu vermeiden, aber CreateParameter ist eine vollständige PITA. Zum Glück gibt es eine Alternative: Command.Execute nimmt Parameter direkt auf.

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

Es ist viel schöner, wenn in einer richtigen Abstraktion verpackt. Ich schrieb meine eigene Datenbankklasse, die ADODB.Connection einwickelte, also würde ich nicht alles manuell tun müssen. Es stützt sich ein wenig auf andere benutzerdefinierte Klassen, aber der Kern sollte es offensichtlich sein:

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

Das hat für mich funktioniert --- danke! Leser beachten Sie bitte: das 'Parameters' Argument zu' .Execute' nimmt eine 'Variante'. Sie werden sehr obskure Fehlermeldungen erhalten, wenn die Anzahl und Formate Ihrer Parameter nicht mit den Erwartungen der Abfrage übereinstimmen! – cxw

0

Nachdem Sie den Parameter zu erstellen, müssen Sie es auf die Parameter Sammlung des Command-Objekt anhängen, bevor Sie den Befehl ausführen:

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

cmd.Parameters.Append paramTotals 

Sie müssen möglicherweise auch die Eigenschaften Type und Size für den Parameter angeben. Im Allgemeinen ich die Argumente der Create-Funktion alle notwendigen Eigenschaften in einer Zeile zu setzen:

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

Ich weiß, das ist alt, aber für jemand noch diese fiding (wie ich über Google tat):

Wenn Sie mit Stored Procedures:

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 

Wenn nicht, ich glaube, Sie .CommandText zu Ihrer SQL-Anweisung mit Fragen Markierungen vorhanden und Ihre Parameter müssen in der gleichen Reihenfolge folgen ändern.

Siehe http://www.devguru.com/technologies/ado/quickref/command_createparameter.html Für eine Aufschlüsselung der Werte, die Sie übergeben mit CreateParameter, sowie eine Liste von Typen und deren Beschreibungen.