Abrufen von Ergebnisdaten

Eine ODBC-Anwendung bietet drei Optionen zum Abrufen von Ergebnisdaten.

Die erste Option basiert auf SQLBindCol. Vor dem Abrufen des Resultsets verwendet die Anwendung SQLBindCol, um jede Spalte im Resultset an eine Programmvariable zu binden. Nachdem die Spalten gebunden wurden, überträgt der Treiber bei jedem Aufrufen von SQLFetch oder SQLFetchScroll durch die Anwendung die Daten der aktuellen Zeile in die an die Resultsetspalten gebundenen Variablen. Der Treiber führt Datenkonvertierungen durch, wenn die Resultsetspalte und die Programmvariable verschiedene Datentypen aufweisen. Wenn für die Anwendung SQL_ATTR_ROW_ARRAY_SIZE auf einen höheren Wert als 1 festgelegt ist, können Ergebnisspalten an Variablenarrays gebunden werden, die alle bei jedem Aufruf von SQLFetchScroll gefüllt werden.

Die zweite Option basiert auf SQLGetData. Die Anwendung verwendet nicht SQLBindCol, um Resultsetspalten an Programmvariablen zu binden. Nach jedem Aufruf von SQLFetch ruft die Anwendung für jede Spalte im Resultset einmal SQLGetData auf. Mit SQLGetData wird der Treiber angewiesen, Daten aus einer bestimmten Resultsetspalte in eine spezielle Programmvariable zu übertragen, und der Datentyp der Spalte und der Variablen wird angegeben. Dies ermöglicht es dem Treiber, Daten zu konvertieren, wenn die Datentypen der Ergebnisspalte und der Programmvariablen nicht übereinstimmen. Text-, ntext- und image-Spalten sind normalerweise zu groß für eine Programmvariable, können aber weiterhin mithilfe von SQLGetData abgerufen werden. Wenn die Daten für text, ntext oder image in der Ergebnisspalte größer sind als die Programmvariable, gibt SQLGetData SQL_SUCCESS_WITH_INFO und SQLSTATE 01004 (Zeichenfolgendaten, rechts abgeschnitten) zurück. Aufeinander folgende Aufrufe von SQLGetData geben aufeinander folgende Abschnitte der text- oder image-Daten zurück. Wenn das Ende der Daten erreicht wird, gibt SQLGetData SQL_SUCCESS zurück. Jeder Abruf gibt einen Satz von Zeilen oder ein Rowset zurück, wenn SQL_ATTR_ROW_ARRAY_SIZE größer als 1 ist. Vor der Verwendung von SQLGetData müssen Sie zuerst SQLSetPos verwenden, um eine bestimmte Zeile innerhalb des Rowsets als aktuelle Zeile anzugeben.

Die dritte Option besteht darin, eine Mischung aus SQLBindCol und SQLGetData zu verwenden. Eine Anwendung könnte beispielsweise die ersten zehn Spalten eines Resultsets binden und dann bei jedem Abruf dreimal SQLGetData aufrufen, um die Daten aus drei ungebundenen Spalten abzurufen. Dies würde i. d. d.R. verwendet werden, wenn ein Resultset mindestens eine text- oder image-Spalte enthält.

Abhängig von den für das Resultset angegebenen Cursoroptionen kann eine Anwendung auch die Optionen für das Scrollen von SQLFetchScroll verwenden, um einen Bildlauf im Resultset auszuführen.

Die übermäßige Verwendung von SQLBindCol zum Binden einer Resultsetspalte an eine Programmvariable ist sehr aufwendig, da durch SQLBindCol ein ODBC-Treiber Speicher zuordnet. Wenn Sie eine Resultsetspalte an eine Variable binden, bleibt diese Bindung wirksam, bis Sie entweder SQLFreeHandle aufrufen, um das Anweisungshandle freizugeben, oder SQLFreeStmt aufrufen, wobei fOption auf SQL_UNBIND festgelegt ist. Die Bindungen werden nicht automatisch rückgängig gemacht, wenn die Anweisung abgeschlossen ist.

Diese Logik ermöglicht Ihnen das effektive Ausführen derselben SELECT-Anweisung mehrere Male mit verschiedenen Parametern. Da das Resultset dieselbe Struktur beibehält, können Sie das Resultset einmal binden, alle SELECT-Anweisungen verarbeiten und anschließend nach der letzten Ausführung SQLFreeStmt aufrufen, wobei fOption auf SQL_UNBIND festgelegt ist. Rufen Sie SQLBindCol nicht auf, um die Spalten in einem Resultset zu binden, ohne zuerst SQLFreeStmt mit fOption festgelegt auf SQL_UNBIND aufzurufen, um alle vorherigen Bindungen freizugeben.

Wenn Sie SQLBindCol verwenden, können Sie entweder zeilen- oder spaltenbezogene Bindung durchführen. Zeilenbezogene Bindungen sind etwas schneller als spaltenbezogene Bindungen.

Sie können SQLGetData verwenden, um Daten Spalte für Spalte abzurufen, anstatt Resultsetspalten mithilfe von SQLBindCol zu binden. Wenn ein Resultset nur ein paar Zeilen umfasst, ist die Verwendung von SQLGetData anstelle von SQLBindCol schneller. Andernfalls bietet SQLBindCol die beste Leistung. Wenn Sie Daten nicht immer in demselben Variablensatz ablegen, sollten Sie SQLGetData verwenden, anstatt ständig neue Bindungen auszuführen. Sie können SQLGetData nur für Spalten verwenden, die sich in der Auswahlliste befinden, nachdem alle Spalten mit SQLBindCol gebunden sind. Die Spalte muss außerdem nach allen Spalten angezeigt werden, für die Sie bereits SQLGetData verwendet haben.

Die ODBC-Funktionen, die für das Verschieben von Daten in oder aus Programmvariablen zuständig sind, wie etwa SQLGetData, SQLBindCol und SQLBindParameter, unterstützen die implizite Datentypkonvertierung. Wenn beispielsweise eine Anwendung eine Spalte mit ganzen Zahlen an eine Zeichenfolgen-Programmvariable bindet, konvertiert der Treiber automatisch die Daten aus einer ganzen Zahl in ein Zeichen, bevor sie in der Programmvariablen abgelegt werden.

Datenkonvertierungen in Anwendungen sollten reduziert werden. Nur wenn eine Datenkonvertierung für die von der Anwendung durchgeführte Verarbeitung erforderlich ist, sollten Anwendungen Spalten und Parameter an Programmvariablen desselben Datentyps binden. Wenn die Daten von einem Typ in einen anderen konvertiert werden müssen, ist es effektiver, wenn der Treiber die Konvertierung durchführt, anstatt dies in der Anwendung durchzuführen. Der ODBC-Treiber für SQL Server Native Client überträgt normalerweise einfach Daten direkt aus den Netzwerkpuffern an die Variablen der Anwendung. Wenn Sie die Datenkonvertierung durch den Treiber anfordern, zwingt dies den Treiber, die Daten zu puffern und CPU-Zyklen für das Konvertieren der Daten zu verwenden.

Programmvariablen sollten groß genug sein, Daten aufzunehmen, die aus einer Spalte übertragen wurden, mit Ausnahme von text-, ntext- und image-Daten. Wenn eine Anwendung versucht, Resultsetdaten abzurufen und in einer Variablen abzulegen, die für die Aufnahme dieser Daten zu klein ist, generiert der Treiber eine Warnung. Dies zwingt den Treiber, Speicher für die Meldung zu reservieren, und sowohl der Treiber als auch die Anwendung müssen CPU-Zyklen für die Verarbeitung der Meldung und die Durchführung der Fehlerbehandlung aufwenden. Die Anwendung sollte entweder eine Variable zuordnen, die groß genug ist, die abgerufenen Daten aufzunehmen, oder die SUBSTRING-Funktion in der Auswahlliste verwenden, um die Größe der Spalte im Resultset zu reduzieren.

Beim Verwenden von SQL_C_DEFAULT zur Angabe des Typs der C-Variablen müssen Sie mit Bedacht vorgehen. SQL_C_DEFAULT gibt an, dass der Typ der C-Variablen mit dem SQL-Datentyp der Spalte oder des Parameters übereinstimmt. Wenn SQL_C_DEFAULT für eine ntext-, nchar- oder nvarchar-Spalte angegeben ist, werden Unicode-Daten an die Anwendung zurückgegeben. Dies kann verschiedene Probleme verursachen, wenn die Anwendung nicht codiert wurde, um Unicode-Daten zu behandeln. Dieselbe Art von Problemen kann mit dem uniqueidentifier (SQL_GUID)-Datentyp auftreten.

text-, ntext- und image-Daten sind normalerweise zu groß für eine einzige Programmvariable und werden i. d. R. mit SQLGetData anstelle von SQLBindCol verarbeitet. Wenn Servercursor verwendet werden, wird der ODBC-Treiber für SQL Server Native Client optimiert und überträgt keine Daten für ungebundene text-, ntext- oder image-Spalten, während die Zeile abgerufen wird. Die text-, ntext- oder image-Daten werden tatsächlich erst dann von dem Server abgerufen, wenn die Anwendung SQLGetData für die Spalte ausgibt.

Diese Optimierung kann auf Anwendungen angewendet werden, sodass keine text-, ntext- oder image-Daten angezeigt werden, während ein Benutzer einen Bildlauf nach oben oder unten mit einem Cursor ausführt. Nachdem der Benutzer eine Zeile ausgewählt hat, kann die Anwendung SQLGetData aufrufen, um die text-, ntext- oder image-Daten abzurufen. Dadurch ist es nicht notwendig, die text-, ntext- oder image-Daten für alle Zeilen zu übertragen, die der Benutzer nicht ausgewählt hat. So kann die Übertragung sehr großer Datenmengen vermieden werden.