Click here to view and discuss this page in DocCommentXchange. In the future, you will be sent there automatically.

SQL Anywhere 11.0.1 (Deutsch) » SQL Anywhere Server - Programmierung » SQL Anywhere Datenzugriff-APIs » SQL Anywhere Embedded SQL » Daten abrufen

 

Mehr als eine Zeile auf einmal abrufen

Die FETCH-Anweisung kann so modifiziert werden, dass sie mehr als eine Zeile auf einmal abruft. Das kann die Performance verbessern. Man nennt diese Methode mehrzeiliges Abrufen (wide fetch) oder auch Array-Abrufen (array fetch).

SQL Anywhere unterstützt auch weites Speichern und weite Einfügungen. Weitere Hinweise finden Sie unter PUT-Anweisung [ESQL] und EXECUTE-Anweisung [ESQL].

Um weite Abrufe in Embedded SQL zu verwenden, fügen Sie die Abrufanweisung wie folgt in Ihren Code ein:

EXEC SQL FETCH ... ARRAY nnn

Dabei ist ARRAY nnn das letzte Element der FETCH-Anweisung. Die Abrufanzahl nnn kann eine Hostvariable sein. Die Anzahl der Variablen im SQLDA-Bereich muss das Produkt aus nnn multipliziert mit der Anzahl der Spalten pro Zeile sein. Die erste Zeile wird in die SQLDA-Variablen von 0 bis (Spalten pro Zeile)-1 geschrieben, usw.

Jede Spalte muss in jeder Zeile des SQLDA-Bereichs vom selben Typ sein, sonst wird der Fehler SQLDA_INCONSISTENT ausgegeben.

Der Server gibt in SQLCOUNT die Anzahl der Datensätze zurück, die abgerufen wurden. Diese Anzahl ist immer größer als 0 (Null), außer wenn ein Fehler oder eine Warnung ausgegeben wird. Bei einem mehrzeiligen Abruf gibt ein SQLCOUNT von 1 ohne Fehlerzustand an, dass eine gültige Zeile abgerufen wurde.

Beispiel

Der folgende Beispielcode zeigt den Gebrauch von mehrzeiligen Abrufen. Dieser Code befindet sich in Beispielverzeichnis\SQLAnywhere\esqlwidefetch\widefetch.sqc.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sqldef.h"
EXEC SQL INCLUDE SQLCA;

EXEC SQL WHENEVER SQLERROR { PrintSQLError();
        goto err; };

static void PrintSQLError()
{
  char buffer[200];

  printf( "SQL error %d -- %s\n",
     SQLCODE,
     sqlerror_message( &sqlca,
              buffer,
              sizeof( buffer ) ) );
} 
static SQLDA * PrepareSQLDA(
  a_sql_statement_number stat0,
  unsigned  width,
  unsigned  *cols_per_row )

/* Allocate a SQLDA to be used for fetching from
   the statement identified by "stat0". "width"
   rows are retrieved on each FETCH request.
   The number of columns per row is assigned to
   "cols_per_row". */
{
  int           num_cols;
  unsigned      row, col, offset;
  SQLDA *       sqlda;
  EXEC SQL BEGIN DECLARE SECTION;
  a_sql_statement_number  stat;
  EXEC SQL END DECLARE SECTION;
  stat = stat0;
  sqlda = alloc_sqlda( 100 );
  if( sqlda == NULL ) return( NULL );
  EXEC SQL DESCRIBE :stat INTO sqlda;
  *cols_per_row = num_cols = sqlda->sqld;
  if( num_cols * width > sqlda->sqln ) 
  {
    free_sqlda( sqlda );
    sqlda = alloc_sqlda( num_cols * width );
    if( sqlda == NULL ) return( NULL );
    EXEC SQL DESCRIBE :stat INTO sqlda;
  }
  // copy first row in SQLDA setup by describe
  // to following (wide) rows
  sqlda->sqld = num_cols * width;
  offset = num_cols;
  for( row = 1; row < width; row++ ) 
  {
    for( col = 0;
      col < num_cols;
      col++, offset++ ) 
    {
      sqlda->sqlvar[offset].sqltype =
          sqlda->sqlvar[col].sqltype;
      sqlda->sqlvar[offset].sqllen =
          sqlda->sqlvar[col].sqllen;
      // optional: copy described column name
      memcpy( &sqlda->sqlvar[offset].sqlname,
              &sqlda->sqlvar[col].sqlname,
              sizeof( sqlda->sqlvar[0].sqlname ) );
    }
  }
  fill_s_sqlda( sqlda, 40 );
  return( sqlda ); 
err:
  return( NULL );
} 
static void PrintFetchedRows( 
  SQLDA * sqlda,
  unsigned cols_per_row )
{
  /* Print rows already wide fetched in the SQLDA */
  long      rows_fetched;
  int       row, col, offset;

  if( SQLCOUNT == 0 ) 
  {
    rows_fetched = 1;
  } 
  else 
  {
    rows_fetched = SQLCOUNT;
  }
  printf( "Fetched %d Rows:\n", rows_fetched );
  for( row = 0; row < rows_fetched; row++ ) 
  {
    for( col = 0; col < cols_per_row; col++ ) 
    {
      offset = row * cols_per_row + col;
      printf( " \"%s\"",
        (char *)sqlda->sqlvar[offset].sqldata );
     }
     printf( "\n" );
  }
} 
static int DoQuery( 
  char * query_str0,
  unsigned fetch_width0 )
{
  /* Wide Fetch "query_str0" select statement
   * using a width of "fetch_width0" rows" */
  SQLDA *                 sqlda;
  unsigned                cols_per_row;
  EXEC SQL BEGIN DECLARE SECTION;
  a_sql_statement_number  stat;
  char *                  query_str;
  unsigned                fetch_width;
  EXEC SQL END DECLARE SECTION;

  query_str = query_str0;
  fetch_width = fetch_width0;

  EXEC SQL PREPARE :stat FROM :query_str;
  EXEC SQL DECLARE QCURSOR CURSOR FOR :stat
       FOR READ ONLY;
  EXEC SQL OPEN QCURSOR;
  sqlda = PrepareSQLDA( stat,
    fetch_width,
    &cols_per_row );
  if( sqlda == NULL ) 
  {
    printf( "Error allocating SQLDA\n" );
    return( SQLE_NO_MEMORY );
  }
  for( ;; ) 
  {
    EXEC SQL FETCH QCURSOR INTO DESCRIPTOR sqlda
      ARRAY :fetch_width;
    if( SQLCODE != SQLE_NOERROR ) break;
    PrintFetchedRows( sqlda, cols_per_row );
  }
  EXEC SQL CLOSE QCURSOR;
  EXEC SQL DROP STATEMENT :stat;
  free_filled_sqlda( sqlda );
err:
  return( SQLCODE );
} 
void main( int argc, char *argv[] )
{
  /* Optional first argument is a select statement,
   * optional second argument is the fetch width */
  char *query_str =
    "SELECT GivenName, Surname FROM Employees";
  unsigned fetch_width = 10;

  if( argc > 1 ) 
  {
    query_str = argv[1];
    if( argc > 2 ) 
    {
      fetch_width = atoi( argv[2] );
      if( fetch_width < 2 ) 
      {
        fetch_width = 2;
      }
    }
  }
  db_init( &sqlca );
  EXEC SQL CONNECT "DBA" IDENTIFIED BY "sql";

  DoQuery( query_str, fetch_width );

  EXEC SQL DISCONNECT;
err:
  db_fini( &sqlca );
}
Hinweise zur Verwendung von mehrzeiligen Abrufen
  • Die Funktion PrepareSQLDA weist den SQLDA-Bereich mithilfe der Funktion alloc_sqlda einem Speicherbereich zu. So wird Platz für Indikatorvariable ermöglicht, anstatt die Funktion alloc_sqlda_noind zu verwenden.

  • Falls weniger als die angeforderte Anzahl von Zeilen, jedoch nicht NULL, abgerufen wurden (zum Beispiel am Ende des Cursors), wird für die nicht abgerufenen SQLDA-Elemente jeweils NULL zurückgegeben, indem der entsprechende Indikatorwert gesetzt wird. Falls keine Indikatorvariable vorhanden ist, wird ein Fehler erzeugt (SQLE_NO_INDICATOR: keine Indikatorvariable für ein NULL-Ergebnis).

  • Falls eine Zeile zurückgegeben wird, die aktualisiert wurde, und die eine Warnung SQLE_ROW_UPDATED_WARNING hervorgerufen hat, wird der Abruf in der Zeile angehalten, die die Warnung verursacht hat. Die Werte aller bis zu diesem Zeitpunkt abgearbeiteten Zeilen werden zurückgegeben (einschließlich der Zeile, die die Warnung verursacht hat). SQLCOUNT enthält die Anzahl der Zeilen, die abgerufen wurden, einschließlich der Zeile, die die Warnung verursacht hat. Alle verbleibenden SQLDA-Elemente werden mit NULL gekennzeichnet.

  • Falls eine Zeile, die abgerufen werden soll, gelöscht oder gesperrt wurde und so einen Fehler hervorruft (SQLE_NO_CURRENT_ROW oder SQLE_LOCKED), enthält SQLCOUNT die Anzahl der Zeilen, die vor dem Fehler gelesen wurden. Dies schließt nicht die Zeile ein, die den Fehler verursachte. Der SQLDA-Bereich enthält keine Werte für die Zeilen, denn bei Fehlern werden keine SQLDA-Werte zurückgegeben. Der Wert von SQLCOUNT kann verwendet werden, um den Cursor neu zu positionieren und, falls nötig, um die Zeilen zu lesen.