{"id":55000475,"date":"2025-06-01T00:00:00","date_gmt":"2025-08-27T13:29:43","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=475"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"ADODB_Datenzugriff_mit_der_CommandKlasse","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/ADODB_Datenzugriff_mit_der_CommandKlasse\/","title":{"rendered":"ADODB: Datenzugriff mit der Command-Klasse"},"content":{"rendered":"<p><b>In einem anderen Artikel namens &#8220;ADODB: SQL-Befehle schnell ausf&uuml;hren mit Execute&#8221; (www.vbentwickler.de\/447) haben wir bereits gezeigt, wie wir unter ADO mit der Execute-Methode der Connection-Klasse schnell SQL-Anweisungen zum Manipulieren von Daten ausf&uuml;hren oder Daten abrufen und mit einem Recordset durchlaufen k&ouml;nnen. Allerdings gibt es gerade f&uuml;r den Austausch von Daten mit dem SQL Server noch einige weitere M&ouml;glichkeiten. Dazu ben&ouml;tigen wir allerdings die Command-Klasse. Sie bietet prim&auml;r auch eine Execute-Methode, mit der wir die gleichen Dinge erledigen k&ouml;nnen, wie mit der gleichnamigen Methode der Connection-Klasse. Sie bietet allerdings viele weitere Optionen, mit denen wir zum Beispiel Parameter an eine gespeicherte Prozedur &uuml;bergeben k&ouml;nnen. <\/b><\/p>\n<h2>Warum die Command-Klasse?<\/h2>\n<p>Die <b>Command<\/b>-Klasse erm&ouml;glicht es Dir, Abfragen und gespeicherte Prozeduren sehr flexibel und sicher auszuf&uuml;hren.<\/p>\n<p>W&auml;hrend einfache SQL-Strings in der <b>Connection.Execute<\/b>-Methode direkt &uuml;bergeben werden, kannst Du mit Command auch Parameter definieren. Das ist gerade bei dynamischen Abfragen oder bei wiederverwendbaren SQL-Prozeduren entscheidend.<\/p>\n<h2>Wichtige Eigenschaften und Methoden der Command-Klasse<\/h2>\n<p>Hier findest Du die wichtigsten Eigenschaften und Methoden der <b>Command<\/b>-Klasse:<\/p>\n<ul>\n<li><b>ActiveConnection:<\/b> Gibt an, mit welcher Connection das Command-Objekt verbunden ist.<\/li>\n<li><b>Cancel:<\/b> Bricht eine laufende Ausf&uuml;hrung eines Command-Objekts ab.<\/li>\n<li><b>CommandStream:<\/b> Erm&ouml;glicht es, einen Stream (zum Beispiel XML) anstelle von SQL-Text zu verwenden.<\/li>\n<li><b>CommandText:<\/b> Enth&auml;lt den SQL-Befehl oder den Namen einer gespeicherten Prozedur.<\/li>\n<li><b>CommandTimeout:<\/b> Gibt an, wie viele Sekunden gewartet wird, bevor ein Command abgebrochen wird.<\/li>\n<li><b>CommandType:<\/b> Bestimmt, wie der Inhalt von <b>CommandText<\/b> interpretiert wird (zum Beispiel Text, Tabelle, Prozedur).<\/li>\n<li><b>CreateParameter:<\/b> Erstellt einen neuen Parameter f&uuml;r das <b>Command<\/b>-Objekt.<\/li>\n<li><b>Dialect:<\/b> Gibt die Syntax an, die f&uuml;r <b>CommandText <\/b>verwendet wird (zum Beispiel SQL-Dialect).<\/li>\n<li><b>Execute:<\/b> F&uuml;hrt den Befehl aus und liefert optional ein Recordset zur&uuml;ck.<\/li>\n<li><b>Name:<\/b> Name des <b>Command<\/b>-Objekts, kann f&uuml;r sp&auml;tere Referenzen verwendet werden.<\/li>\n<li><b>NamedParameters:<\/b> Gibt an, ob Parameter per Namen statt nach Reihenfolge &uuml;bergeben werden.<\/li>\n<li><b>Parameters:<\/b> Sammlung aller Parameter, die dem <b>Command<\/b>-Objekt zugeordnet sind.<\/li>\n<li><b>Prepared:<\/b> Gibt an, ob das <b>Command<\/b>-Objekt vorbereitet\/kompiliert ist, um schneller ausgef&uuml;hrt zu werden.<\/li>\n<li><b>Properties:<\/b> Sammlung zus&auml;tzlicher Eigenschaften, die f&uuml;r das <b>Command<\/b>-Objekt gelten.<\/li>\n<li><b>State:<\/b> Zeigt den aktuellen Status des <b>Command<\/b>-Objekts an (zum Beispiel ge&ouml;ffnet oder geschlossen).<\/li>\n<\/ul>\n<h2>Grundaufbau eines Command-Objekts<\/h2>\n<p>Ein <b>Command<\/b>-Objekt besteht grunds&auml;tzlich aus der Zuweisung der Connection, der Angabe des SQL-Befehls (oder Prozedurnamens) und der Einstellung des <b>CommandType<\/b>.<\/p>\n<p>Danach kannst Du &uuml;ber die <b>Parameters<\/b>-Auflistung <b>Parameter <\/b>hinzuf&uuml;gen und konfigurieren. Schlie&szlig;lich rufst Du die <b>Execute<\/b>-Methode auf, um den Befehl auszuf&uuml;hren oder ein Recordset zu erhalten.<\/p>\n<p>Im folgenden Beispiel &ouml;ffnen wir ein Recordset mit Hilfe eines <b>Command<\/b>-Objekts und geben die Inhalte direkt im Direktbereich aus:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>KundenPerCommand()\r\n     <span style=\"color:blue;\">Dim <\/span>cnn<span style=\"color:blue;\"> As <\/span>ADODB.Connection\r\n     <span style=\"color:blue;\">Dim <\/span>cmd<span style=\"color:blue;\"> As <\/span>ADODB.Command\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> cnn = CurrentProject.Connection\r\n     <span style=\"color:blue;\">Set<\/span> cmd = <span style=\"color:blue;\">New<\/span> ADODB.Command\r\n     cmd.ActiveConnection = cnn\r\n     cmd.CommandText = \"SELECT * FROM tblKunden\"\r\n     cmd.CommandType = adCmdText\r\n     <span style=\"color:blue;\">Set<\/span> rst = cmd.Execute\r\n     Do Until rst.EOF\r\n         <span style=\"color:blue;\">Debug.Print<\/span> rst!Vorname & \" \" & rst!Nachname\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     rst.Close\r\n     <span style=\"color:blue;\">Set<\/span> rst = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> cmd = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> cnn = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>ActiveConnection<\/h2>\n<p>Die Eigenschaft <b>ActiveConnection<\/b> legt fest, welche Verbindung das <b>Command<\/b>-Objekt verwendet. Meist weist Du hier eine bestehende Connection zu, damit das <b>Command<\/b>-Objekt genau wei&szlig;, gegen welche Datenbank es ausgef&uuml;hrt werden soll. Beispiel:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> cmd.ActiveConnection = cnn\r\ncmd.CommandText = \"SELECT * FROM tblKunden\"<\/pre>\n<h2>Cancel<\/h2>\n<p>Mit der Methode <b>Cancel<\/b> kannst Du einen laufenden <b>Command<\/b>-Vorgang abbrechen. Dies ist hilfreich, wenn ein Befehl sehr lange dauert oder der Benutzer den Vorgang abbricht. Beispiel:<\/p>\n<pre>cmd.Execute\r\ncmd.Cancel<\/pre>\n<h2>CommandStream<\/h2>\n<p>Die Eigenschaft <b>CommandStream<\/b> erlaubt es, anstelle von SQL-Text einen Datenstrom (Stream) an ein <b>Command<\/b>-Objekt zu &uuml;bergeben. Meist handelt es sich dabei um einen XML-Stream oder einen anderen bin&auml;ren Datenstrom, der als Eingabe f&uuml;r einen Befehl dient.<\/p>\n<p>Ein typisches Szenario ist der Import gro&szlig;er XML-Datenmengen in eine Datenbank oder das Ausf&uuml;hren von gespeicherten XML-Abfragen, die nicht als reiner Text &uuml;bergeben werden sollen. In solchen F&auml;llen wird ein <b>Stream<\/b>-Objekt erstellt (zum Beispiel mit der <b>ADODB.Stream<\/b>-Klasse), bef&uuml;llt und dann der Eigenschaft <b>CommandStream<\/b> zugewiesen.<\/p>\n<p>Beispiel (verk&uuml;rzt dargestellt):<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>stm<span style=\"color:blue;\"> As <\/span>ADODB.Stream\r\n<span style=\"color:blue;\">Set<\/span> stm = <span style=\"color:blue;\">New<\/span> ADODB.Stream\r\nstm.Open\r\nstm.WriteText \"&lt;root&gt;&lt;datensatz&gt;...&lt;\/datensatz&gt;&lt;\/root&gt;\"\r\n<span style=\"color:blue;\">Set<\/span> cmd.CommandStream = stm\r\ncmd.CommandType = adCmdText\r\ncmd.Execute<\/pre>\n<p>Die Verwendung von <b>CommandStream<\/b> ist eher selten und wird vor allem in komplexeren Szenarien mit XML-Daten, BLOBs (Binary Large Objects) oder bei bestimmten Webservice-Integrationen eingesetzt. In klassischen Access- und SQL Server-Szenarien spielt diese Eigenschaft nur eine untergeordnete Rolle.<\/p>\n<h2>CommandText<\/h2>\n<p>Hier gibst Du den eigentlichen SQL-Befehl oder den Namen einer gespeicherten Prozedur an. Beispiel:<\/p>\n<pre>cmd.CommandText = \"SELECT * FROM tblKunden\"\r\ncmd.CommandType = adCmdText<\/pre>\n<h2>CommandTimeout<\/h2>\n<p>Mit <b>CommandTimeout<\/b> legst Du die maximale Zeit in Sekunden fest, die auf die Ausf&uuml;hrung des Befehls gewartet wird. Beispiel:<\/p>\n<pre>cmd.CommandTimeout = 30<\/pre>\n<h2>CommandType<\/h2>\n<p>Mit <b>CommandType<\/b> steuerst Du, wie Access den Inhalt von <b>CommandText<\/b> interpretiert (Text, Tabelle, Prozedur et cetera). Beispiel:<\/p>\n<pre>cmd.CommandType = adCmdText<\/pre>\n<p>Die folgenden Werte k&ouml;nnen wir f&uuml;r die Eigenschaft <b>CommandType <\/b>verwenden:<\/p>\n<ul>\n<li><b>adCmdUnknown (8):<\/b> Standardwert, wenn der Typ des Befehls nicht angegeben ist. ADO versucht selbst zu erkennen, ob es sich um einen SQL-Text, eine Tabelle oder eine Prozedur handelt. Sollte m&ouml;glichst vermieden werden, da es zu unerwartetem Verhalten f&uuml;hren kann.<\/li>\n<li><b>adCmdText (1):<\/b> Gibt an, dass der Befehl ein SQL-Textbefehl ist (zum Beispiel <b>SELECT<\/b>-, <b>UPDATE<\/b>&#8211; oder <b>DELETE<\/b>-Befehl). Dies ist der am h&auml;ufigsten verwendete Typ f&uuml;r direkte SQL-Strings.<\/li>\n<li><b>adCmdTable (2):<\/b> Verweist auf eine ganze Tabelle. ADO erzeugt intern ein <b>SELECT * FROM [Tabelle]<\/b>. Ideal, wenn alle Datens&auml;tze einer Tabelle ohne Filter geladen werden sollen.<\/li>\n<li><b>adCmdStoredProc (4):<\/b> Kennzeichnet eine gespeicherte Prozedur. Wird verwendet, um auf SQL Server oder anderen Datenbanken gespeicherte Prozeduren auszuf&uuml;hren.<\/li>\n<li><b>adCmdFile (256):<\/b> Verweist auf eine Persisted Recordset-Datei, also eine gespeicherte Daten-Datei (zum Beispiel <b>.adtg<\/b>). Wird selten genutzt, wenn Daten aus einer Datei gelesen oder in eine Datei geschrieben werden.<\/li>\n<li><b>adCmdTableDirect (512):<\/b> &Ouml;ffnet die Tabelle direkt, ohne SQL-Parsing oder weitere Verarbeitung. Sehr schnelle Methode, aber ohne Filter oder Sortierungen. Nur f&uuml;r einfache Lesezugriffe geeignet.<\/li>\n<\/ul>\n<h2>CreateParameter<\/h2>\n<p>Mit <b>CreateParameter<\/b> erstellst Du einen neuen Parameter f&uuml;r Dein <b>Command<\/b>-Objekt. Dies ist vor allem n&uuml;tzlich bei gespeicherten Prozeduren oder dynamischen SQL-Abfragen. Der folgende Parameter &uuml;bergibt den Wert <b>5 <\/b>als Parameter f&uuml;r das Feld <b>KundenID<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> prm = cmd.CreateParameter(\"KundenID\", adInteger, adParamInput, , 5)\r\ncmd.Parameters.Append prm<\/pre>\n<h2>Dialect<\/h2>\n<p>Die Eigenschaft <b>Dialect<\/b> gibt an, welche SQL-Syntax oder welcher Dialekt f&uuml;r <b>CommandText<\/b> verwendet werden soll. Meist wird der Standard-SQL-Dialekt genutzt, sodass diese Eigenschaft oft nicht explizit gesetzt wird.<\/p>\n<h2>Dialect<\/h2>\n<p>Die Eigenschaft <b>Dialect<\/b> gibt an, welche Abfragesyntax das Command-Objekt f&uuml;r den Inhalt von <b>CommandText<\/b> verwenden soll. Standardm&auml;&szlig;ig wird der SQL-Dialekt des verwendeten Providers (meist ANSI SQL) genutzt. Folgende Werte k&ouml;nnen je nach Provider genutzt werden:<\/p>\n<ul>\n<li><b>adCmdUnknown (-1):<\/b> Der Dialekt ist nicht angegeben und wird automatisch vom Provider bestimmt.<\/li>\n<li><b>adCmdText (1):<\/b> Verwendet klassischen SQL-Text, der meist ANSI SQL entspricht.<\/li>\n<li><b>adCmdTable (2):<\/b> Interpretiert den Befehl als Tabellenname.<\/li>\n<li><b>adCmdStoredProc (4):<\/b> Verwendet den Namen einer gespeicherten Prozedur.<\/li>\n<\/ul>\n<p>Zus&auml;tzlich gibt es bei einigen OLE DB Providern propriet&auml;re Dialekte, die &uuml;ber eine Dialekt-URI (Uniform Resource Identifier) angegeben werden k&ouml;nnen, zum Beispiel f&uuml;r XML-Datenquellen. In der Praxis wird <b>Dialect<\/b> sehr selten explizit gesetzt, da der Standardwert f&uuml;r die meisten SQL-Statements vollkommen ausreichend ist. <\/p>\n<p>Erst bei speziellen XML- oder propriet&auml;ren Abfragen ist es n&ouml;tig, diesen Wert explizit festzulegen.<\/p>\n<h2>Execute<\/h2>\n<p>Mit <b>Execute<\/b> f&uuml;hrst Du das Command aus und erh&auml;ltst optional ein Recordset zur&uuml;ck. Beispiel:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> rst = cmd.Execute<\/pre>\n<h2>Die Execute-Methode und ihre Parameter<\/h2>\n<p>Mit der Methode <b>Execute<\/b> f&uuml;hrst Du ein <b>Command<\/b>-Objekt aus. Dabei kannst Du verschiedene Parameter verwenden, um das Verhalten der Ausf&uuml;hrung zu steuern. Die grundlegende Syntax lautet:<\/p>\n<pre><span style=\"color:blue;\">Set<\/span> rst = cmd.Execute(RecordsAffected, Parameters, _\r\n     Options)<\/pre>\n<ul>\n<li><b>RecordsAffected:<\/b> Diese optionale Variable (meist vom Typ <b>Long<\/b>) gibt zur&uuml;ck, wie viele Datens&auml;tze von der Aktion betroffen waren, zum Beispiel bei <b>UPDATE<\/b>&#8211; oder <b>DELETE<\/b>-Befehlen.<\/li>\n<li><b>Parameters:<\/b> Wird bei der <b>Command<\/b>-Klasse meist nicht verwendet, da Parameter &uuml;ber die <b>Parameters<\/b>-Auflistung verwaltet werden. Bei einfachen <b>Execute<\/b>-Aufrufen ohne <b>Command<\/b>-Objekt kann dieser Parameter jedoch genutzt werden.<\/li>\n<li><b>Options:<\/b> Mit diesem Parameter kannst Du steuern, wie ADO den Befehl interpretiert. Zum Beispiel kannst Du hier angeben, ob der Befehl als Text kommt (<b>adCmdText<\/b>) oder als gespeicherte Prozedur (<b>adCmdStoredProc<\/b>). Wird oft zusammen mit einfachen <b>Execute<\/b>-Aufrufen ohne <b>Command<\/b>-Objekt verwendet.<\/li>\n<\/ul>\n<p>Wenn Du die <b>Command<\/b>-Klasse mit vorher definierten Parametern nutzt, brauchst Du meist nur <b>RecordsAffected<\/b> als R&uuml;ckgabewert. Beispiel:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>lngBetroffen<span style=\"color:blue;\"> As Long<\/span>\r\ncmd.Execute lngBetroffen\r\n<span style=\"color:blue;\">Debug.Print<\/span> lngBetroffen & \" Datens&auml;tze wurden aktualisiert.\"<\/pre>\n<p>Mit diesen Parametern kannst Du also noch genauer steuern, wie Dein SQL-Befehl ausgef&uuml;hrt wird, und erh&auml;ltst wichtige R&uuml;ckmeldungen &uuml;ber das Ergebnis.<\/p>\n<h2>Name<\/h2>\n<p>Die Eigenschaft <b>Name<\/b> erlaubt es Dir, einem <b>Command<\/b>-Objekt einen eindeutigen Bezeichner zu geben. Das ist vor allem hilfreich, wenn Du mehrere <b>Command<\/b>-Objekte parallel verwalten m&ouml;chtest. Du kannst den Namen sp&auml;ter zum Beispiel beim Debuggen verwenden oder gezielt &uuml;ber diesen Namen in einer Collection auf das <b>Command<\/b>-Objekt zugreifen.<\/p>\n<p>Das kann wie folgt aussehen:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>cmd1<span style=\"color:blue;\"> As <\/span>ADODB.Command\r\n<span style=\"color:blue;\">Dim <\/span>cmd2<span style=\"color:blue;\"> As <\/span>ADODB.Command\r\n<span style=\"color:blue;\">Set<\/span> cmd1 = <span style=\"color:blue;\">New<\/span> ADODB.Command\r\n<span style=\"color:blue;\">Set<\/span> cmd2 = <span style=\"color:blue;\">New<\/span> ADODB.Command\r\ncmd1.Name = \"Kundenabfrage\"\r\ncmd2.Name = \"Bestellabfrage\"\r\n<span style=\"color:blue;\">Debug.Print<\/span> cmd1.Name\r\n<span style=\"color:blue;\">Debug.Print<\/span> cmd2.Name<\/pre>\n<h2>NamedParameters<\/h2>\n<p>Mit <b>NamedParameters<\/b> steuerst Du, ob Parameter nach Namen oder nach Reihenfolge &uuml;bergeben werden:<\/p>\n<pre>cmd.NamedParameters = <span style=\"color:blue;\">True<\/span><\/pre>\n<h2>Parameters<\/h2>\n<p>Die <b>Parameters<\/b>-Auflistung enth&auml;lt alle Parameter, die Du mit <b>CreateParameter <\/b>erstellt und an das <b>Command<\/b>-Objekt angeh&auml;ngt hast. &Uuml;ber diese Auflistung kannst Du die Werte sp&auml;ter &auml;ndern oder Parameter entfernen. Normalerweise wird man aber immer nur Parameter anh&auml;ngen.<\/p>\n<h2>Prepared<\/h2>\n<p>Die Eigenschaft <b>Prepared<\/b> gibt an, ob das <b>Command<\/b>-Objekt vorbereitet (vorkompiliert) werden soll.<\/p>\n<p>Wenn Du diese Eigenschaft auf <b>True <\/b>setzt, bereitet ADO die SQL-Anweisung oder die gespeicherte Prozedur einmal vor, sodass sie bei mehrfacher Ausf&uuml;hrung schneller verarbeitet werden kann. Das ist besonders sinnvoll, wenn Du ein <b>Command<\/b>-Objekt mit Parametern mehrfach aufrufst, etwa in einer Schleife oder bei wiederholten Benutzeraktionen.<\/p>\n<p>Durch das Vorbereiten muss die Anweisung nicht jedes Mal erneut interpretiert und optimiert werden.<\/p>\n<p>Beispiel: Du m&ouml;chtest eine gespeicherte Prozedur mehrfach mit verschiedenen Parameterwerten aufrufen. In diesem Fall setzt Du <b>Prepared<\/b> vor der ersten Ausf&uuml;hrung auf <b>True<\/b>.<\/p>\n<pre>cmd.Prepared = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">Set<\/span> prm = cmd.CreateParameter(\"KundenID\", adInteger, adParamInput, , 1)\r\ncmd.Parameters.Append prm\r\ncmd.Execute\r\ncmd.Parameters(\"KundenID\").Value = 2\r\ncmd.Execute<\/pre>\n<p>Nach dem ersten Aufruf bleibt das <b>Command<\/b>-Objekt vorbereitet und kann mit ge&auml;nderten Parametern immer wieder schnell ausgef&uuml;hrt werden. Damit sparst Du vor allem bei gro&szlig;en Abfragen oder bei Zugriffen auf SQL Server-Datenbanken sp&uuml;rbar Zeit.<\/p>\n<h2>Properties<\/h2>\n<p>Die <b>Properties<\/b>-Sammlung enth&auml;lt zus&auml;tzliche Einstellungen, die f&uuml;r das <b>Command<\/b>-Objekt gelten. Hier&uuml;ber kannst Du spezielle Optionen abrufen oder setzen, die je nach Provider variieren k&ouml;nnen. Diese Auflistung ist kompatibel mit den <b>Properties<\/b>-Auflistungen aller anderen g&auml;ngigen Klassen.<\/p>\n<h2>State<\/h2>\n<p>Die Eigenschaft <b>State<\/b> zeigt an, in welchem Zustand sich das <b>Command<\/b>-Objekt aktuell befindet.<\/p>\n<p>Sie gibt eine Zahl zur&uuml;ck, die einem bestimmten Status entspricht. Typische Werte sind:<\/p>\n<ul>\n<li><b>adStateClosed (0):<\/b> Das <b>Command<\/b>-Objekt ist geschlossen und es wurde noch kein Befehl ausgef&uuml;hrt.<\/li>\n<li><b>adStateOpen (1):<\/b> Das <b>Command<\/b>-Objekt ist ge&ouml;ffnet oder es l&auml;uft gerade eine Ausf&uuml;hrung.<\/li>\n<\/ul>\n<p>Die <b>State<\/b>-Eigenschaft ist vor allem dann n&uuml;tzlich, wenn Du pr&uuml;fen m&ouml;chtest, ob ein <b>Command<\/b>-Objekt gerade aktiv ist oder ob es noch verwendet werden kann.<\/p>\n<p>So kannst Du zum Beispiel vor einem erneuten Ausf&uuml;hren sicherstellen, dass kein vorheriger Vorgang mehr l&auml;uft.<\/p>\n<p>Dies pr&uuml;ft den Zustand und gibt diesen im Direktbereich aus:<\/p>\n<pre><span style=\"color:blue;\">If <\/span>cmd.State = adStateOpen<span style=\"color:blue;\"> Then<\/span>\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Command ist aktiv oder wird ausgef&uuml;hrt\"\r\n<span style=\"color:blue;\">Else<\/span>\r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Command ist geschlossen\"\r\n<span style=\"color:blue;\">End If<\/span><\/pre>\n<h2>Parameter an gespeicherte Prozeduren &uuml;bergeben<\/h2>\n<p>Eine besondere St&auml;rke der <b>Command<\/b>-Klasse ist die M&ouml;glichkeit, Parameter zu definieren. Dies eignet sich vor allem, wenn Du mit gespeicherten Prozeduren arbeitest. Hier kannst Du <b>Input<\/b>-Parameter, <b>Output<\/b>-Parameter oder auch Parameter mit einem R&uuml;ckgabewert definieren und verwalten.<\/p>\n<p>Ausf&uuml;hrliche Beispiele dazu findest Du im Artikel <b>ADODB: Beispiele f&uuml;r den Datenzugriff mit Command <\/b>(<b>www.vbentwickler.de\/470<\/b>).<\/p>\n<h2>Besonderheit bei gespeicherten Prozeduren<\/h2>\n<p>Eine wichtige Besonderheit der <b>Command-Klasse<\/b> ist, dass sie als einzige M&ouml;glichkeit in ADODB einen bearbeitbaren Zugriff auf die Ergebnisse einer gespeicherten Prozedur bietet.<\/p>\n<p>Mit einem reinen SQL-Text (<b>SELECT * FROM &#8230;<\/b>) &uuml;ber <b>Connection.Execute <\/b>kannst Du zwar Daten abrufen, aber nicht direkt bearbeiten.<\/p>\n<p>Verwendest Du jedoch die <b>Command<\/b>-Klasse mit <b>adCmdStoredProc<\/b>, kannst Du &#8211; abh&auml;ngig von der Datenquelle &#8211; ein Recordset erhalten, das bearbeitet und sp&auml;ter wieder gespeichert werden kann.<\/p>\n<p>Wichtig: Dies funktioniert nur, wenn die gespeicherte Prozedur ein sogenanntes &#8220;aktualisierbares&#8221; Recordset zur&uuml;ckgibt. Das bedeutet, die Prozedur darf keine komplexen Joins oder Aggregatfunktionen enthalten und muss so aufgebaut sein, dass ADODB eine eindeutige Zuweisung zu den zugrunde liegenden Tabellen herstellen kann.<\/p>\n<p>Diese M&ouml;glichkeit steht Dir vor allem bei SQL Server, Oracle und anderen professionellen relationalen Datenbanksystemen zur Verf&uuml;gung. Bei Access (JET\/ACE) sind gespeicherte Prozeduren in Form von Abfragen oft nicht direkt &uuml;ber <b>Command <\/b>mit Parametern ausf&uuml;hrbar und liefern in der Regel auch kein bearbeitbares Recordset.<\/p>\n<p>Damit eignet sich die <b>Command<\/b>-Klasse ideal f&uuml;r Szenarien, in denen Du Daten nicht nur anzeigen, sondern direkt in der Anwendung weiterbearbeiten m&ouml;chtest, zum Beispiel in Formularen oder bei automatisierten Aktualisierungsvorg&auml;ngen.<\/p>\n<p>Der gro&szlig;e Vorteil: Du kannst damit die Vorteile der schnellen Datenlieferung von gespeicherten Prozeduren in Zusammenhang mit Parametern als Kriterien nutzen und das Ergebnis gleichzeitig bearbeiten. Wenn Du eine gespeicherte Prozedur auf DAO-Basis mit einer Pass-Through-Abfrage &ouml;ffnest, ist das in jedem Fall unm&ouml;glich, weil diese Recordsets nicht bearbeitbar sind.<\/p>\n<h2>Praktische Tipps und typische Fehlerquellen<\/h2>\n<p>Neben den technischen Details zur <b>Command<\/b>-Klasse lohnt es sich, ein paar praktische Tipps und h&auml;ufige Fehlerquellen zu beleuchten. Gerade beim Arbeiten mit gespeicherten Prozeduren kann es leicht passieren, dass ein Recordset unerwartet schreibgesch&uuml;tzt ist. Der h&auml;ufigste Grund: Die Prozedur enth&auml;lt Joins oder berechnete Spalten, die nicht eindeutig einer Tabelle zugeordnet werden k&ouml;nnen.<\/p>\n<p>Ein weiterer h&auml;ufiger Stolperstein ist das Vergessen der L&auml;ngenangabe bei Zeichenkettenparametern (<b>adVarChar <\/b>oder <b>adVarWChar<\/b>). Ohne L&auml;nge interpretiert SQL Server den Parameter oft als L&auml;nge <b>0 <\/b>oder liefert Fehlermeldungen. Daher gilt: F&uuml;r jeden Parameter mit Zeichenketten immer explizit die L&auml;nge angeben, zum Beispiel <b>50 <\/b>f&uuml;r einen typischen <b>Varchar(50)<\/b>-Parameter.<\/p>\n<p>Dar&uuml;ber hinaus solltest Du, wenn m&ouml;glich, die Verwendung von Platzhaltern wie <b>SELECT * <\/b>vermeiden und stattdessen immer die ben&ouml;tigten Spalten explizit angeben. Das verbessert nicht nur die Performance, sondern reduziert auch das Risiko von Konflikten, falls sich die Tabellendefinition einmal &auml;ndert.<\/p>\n<p>Wenn Du die <b>Command<\/b>-Klasse f&uuml;r Daten&auml;nderungen verwendest, ist es oft sinnvoll, vor dem Aufruf von Execute die Eigenschaft <b>Prepared <\/b>auf <b>True <\/b>zu setzen. Das lohnt sich insbesondere bei wiederholten Aufrufen mit unterschiedlichen Parametern, weil die SQL-Anweisung dann nur einmal vom SQL Server vorbereitet (kompiliert) werden muss.<\/p>\n<p>Schlie&szlig;lich empfiehlt es sich, den R&uuml;ckgabewert von Execute (<b>RecordsAffected<\/b>) zu pr&uuml;fen. So stellst Du sicher, dass tats&auml;chlich Datens&auml;tze ge&auml;ndert wurden, und kannst auf unerwartete Situationen (zum Beispiel keine betroffenen Zeilen) reagieren. Das erh&ouml;ht die Stabilit&auml;t und Nachvollziehbarkeit Deiner VBA-Anwendungen erheblich.<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Mit der <b>Command<\/b>-Klasse steht Dir eine sehr leistungsf&auml;hige Alternative zur reinen <b>Execute<\/b>-Methode der <b>Connection<\/b>-Klasse zur Verf&uuml;gung. Du kannst SQL-Befehle flexibel steuern, Parameter nutzen und auch komplexe Prozeduren ansprechen.<\/p>\n<p>In einem weiteren Artikel namens <b>ADODB: Beispiele f&uuml;r den Datenzugriff mit Command <\/b>(<b>www.vbentwickler.de\/470<\/b>) zeigen wir Dir einige Beispiele f&uuml;r den Zugriff per ADODB\/Command auf Recordsets in Access- und SQL Server-Datenbanken.<\/p>\n<p>Hier schauen wir uns auch an, wo die Grenzen liegen beim Erstellen von Recordsets auf Basis des <b>Command<\/b>-Objekts.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In einem anderen Artikel namens &#8220;ADODB: SQL-Befehle schnell ausf&uuml;hren mit Execute&#8221; (www.vbentwickler.de\/447) haben wir bereits gezeigt, wie wir unter ADO mit der Execute-Methode der Connection-Klasse schnell SQL-Anweisungen zum Manipulieren von Daten ausf&uuml;hren oder Daten abrufen und mit einem Recordset durchlaufen k&ouml;nnen. Allerdings gibt es gerade f&uuml;r den Austausch von Daten mit dem SQL Server noch einige weitere M&ouml;glichkeiten. Dazu ben&ouml;tigen wir allerdings die Command-Klasse. Sie bietet prim&auml;r auch eine Execute-Methode, mit der wir die gleichen Dinge erledigen k&ouml;nnen wir mit der gleichnamigen Methode der Connection-Klasse. Sie bietet allerdings viele weitere Optionen, mit denen wir zum Beispiel Parameter an eine gespeicherte Prozedur &uuml;bergeben k&ouml;nnen. Was wir mit der Command-Klasse alles erledigen k&ouml;nnen, liest Du in diesem Artikel.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662025,66032025,44000008],"tags":[],"yst_prominent_words":[],"class_list":["post-55000475","post","type-post","status-publish","format-standard","hentry","category-662025","category-66032025","category-Datenzugriffstechnik"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000475","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000475"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000475\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000475"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000475"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000475"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000475"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}