SQL: Anpassen der SQL-Anweisung Ihres Recordsets (ODBC)

In diesem Thema wird Folgendes erläutert:

  • So konstruiert das Framework eine SQL-Anweisung

  • Überschreiben der SQL-Anweisung

Hinweis

Diese Informationen gelten für die MFC-ODBC-Klassen. Wenn Sie mit den MFC-DAO-Klassen arbeiten, lesen Sie das Thema „Comparison of Microsoft Jet Database Engine SQL and ANSI SQL“ in der DAO-Hilfe.

Konstruktion von SQL-Anweisungen

Die Datensatzauswahl Ihres Recordsets basiert in erster Linie auf einer SQL-Anweisung vom Typ SELECT. Wenn Sie Ihre Klasse mit einem Assistenten deklarieren, wird eine überschreibende Version der GetDefaultSQL-Memberfunktion geschrieben, die in etwa wie folgt aussieht (für eine Recordset-Klasse namens CAuthors):

CString CAuthors::GetDefaultSQL()
{
    return "AUTHORS";
}

Standardmäßig gibt diese Überschreibung den Tabellennamen zurück, den Sie mit dem Assistenten angegeben haben. In dem Beispiel lautet der Tabellenname „AUTHORS“. Wenn Sie später die Open-Memberfunktion des Recordsets aufrufen, konstruiert Open eine finale Anweisung vom Typ SELECT im folgenden Format:

SELECT rfx-field-list FROM table-name [WHERE m_strFilter]
       [ORDER BY m_strSort]

Dabei wird table-name durch Aufrufen von GetDefaultSQL abgerufen, und rfx-field-list wird über die RFX-Funktionsaufrufe in DoFieldExchange abgerufen. Das ist das Ergebnis für eine Anweisung vom Typ SELECT – es sei denn, Sie ersetzen sie zur Laufzeit durch eine überschreibende Version. Sie können allerdings auch die Standardanweisung mit Parametern oder einem Filter ändern.

Hinweis

Wenn Sie einen Spaltennamen angeben, der Leerzeichen enthält (oder enthalten kann), müssen Sie den Namen in eckige Klammern einschließen. Beispiel: Der Name „Zweiter Vorname“ muss als „[Zweiter Vorname]“ angegeben werden.

Wenn Sie die Standardanweisung SELECT überschreiben möchten, können Sie beim Aufrufen von Open eine Zeichenfolge mit einer vollständigen Anweisung vom Typ SELECT übergeben. Anstatt eine eigene Standardzeichenfolge zu konstruieren, verwendet das Recordset die von Ihnen angegebene Zeichenfolge. Wenn Ihre Ersatzanweisung eine Klausel vom Typ WHERE enthält, geben Sie in m_strFilter keinen Filter an, da sonst zwei Filteranweisungen vorhanden wären. Analog dazu gilt: Wenn Ihre Ersatzanweisung eine Klausel vom Typ ORDER BY enthält, geben Sie in m_strSort keine Sortierung an, damit nicht zwei Sortieranweisungen vorhanden sind.

Hinweis

Wenn Sie in Ihren Filtern (oder in anderen Teilen der SQL-Anweisung) literale Zeichenfolgen verwenden, müssen Sie diese ggf. zitieren (also in angegebene Trennzeichen einschließen), indem Sie sie mit mindestens einem DBMS-spezifischen Literalpräfix und Literalsuffix versehen.

Je nach DBMS können auch spezielle syntaktische Anforderungen für Vorgänge wie äußere Verknüpfungen gelten. Verwenden Sie ODBC-Funktionen, um diese Informationen aus Ihrem Treiber für das DBMS abzurufen. Rufen Sie z. B. ::SQLGetTypeInfo für einen bestimmten Datentyp (etwa SQL_VARCHAR) auf, um die Zeichen für „LITERAL_PREFIX“ und „LITERAL_SUFFIX“ anzufordern. Wenn Sie datenbankunabhängigen Code schreiben, sehen Sie sich Anhang C: SQL-Grammatik in der ODBC-Programmierreferenz an, um ausführliche Informationen zur Syntax zu erhalten.

Ein Recordset-Objekt konstruiert die zum Auswählen von Datensätzen verwendete SQL-Anweisung – es sei denn, Sie übergeben eine benutzerdefinierte SQL-Anweisung. Die Vorgehensweise hängt dabei hauptsächlich von dem Wert ab, den Sie an den Parameter lpszSQL der Open-Memberfunktion übergeben.

Das allgemeine Format einer SQL-Anweisung vom Typ SELECT lautet wie folgt:

SELECT [ALL | DISTINCT] column-list FROM table-list
    [WHERE search-condition][ORDER BY column-list [ASC | DESC]]

Eine Möglichkeit, der SQL-Anweisung Ihres Recordsets das Schlüsselwort DISTINCT hinzuzufügen, besteht darin, das Schlüsselwort in den ersten RFX-Funktionsaufruf in DoFieldExchange einzubetten. Zum Beispiel:

...
    RFX_Text(pFX, "DISTINCT CourseID", m_strCourseID);
...

Hinweis

Verwenden Sie diese Technik nur bei einem Recordset, das schreibgeschützt geöffnet wird.

Überschreiben der SQL-Anweisung

Die folgende Tabelle enthält die Möglichkeiten zum Öffnen (Open) des Parameters lpszSQL. Die Fälle aus der Tabelle werden im Anschluss an die Tabelle erläutert.

Der lpszSQL-Parameter und die resultierende SQL-Zeichenfolge

Case Übergabe an lpszSQL Resultierende SELECT-Anweisung
1 NULL SELECT RFX-Feldliste FROM Tabellenname

CRecordset::Open ruft GetDefaultSQL auf, um den Tabellennamen abzurufen. Die resultierende Zeichenfolge ist einer der Fälle 2 bis 5 (je nachdem, was von GetDefaultSQL zurückgegeben wird).
2 Ein Tabellenname SELECT RFX-Feldliste FROM Tabellenname

Die Feldliste stammt aus den RFX-Anweisungen in DoFieldExchange. Wenn m_strFilter und m_strSort nicht leer sind, wird die Klausel WHERE und/oder ORDER BY hinzugefügt.
3* Eine vollständige Anweisung vom Typ SELECT, aber ohne Klausel vom Typ WHERE oder ORDER BY Wie übergeben. Wenn m_strFilter und m_strSort nicht leer sind, wird die Klausel WHERE und/oder ORDER BY hinzugefügt.
4* Eine vollständige Anweisung vom Typ SELECT mit einer Klausel vom Typ WHERE und/oder ORDER BY Wie übergeben. m_strFilter und/oder m_strSort muss leer bleiben, da ansonsten zwei Filter- und/oder Sortieranweisungen erstellt werden.
5 * Aufruf einer gespeicherten Prozedur Wie übergeben.

* m_nFields muss kleiner oder gleich der Anzahl von Spalten sein, die in der Anweisung vom Typ SELECT angegeben sind. Der Datentyp jeder Spalte, die in der Anweisung vom Typ SELECT angegeben ist, muss mit dem Datentyp der entsprechenden RFX-Ausgabespalte übereinstimmen.

1. Fall: lpszSQL = NULL

Die Recordsetauswahl hängt davon ab, was von GetDefaultSQL beim Aufruf durch CRecordset::Open zurückgegeben wird. Die Fälle 2 bis 5 beschreiben die möglichen Zeichenfolgen.

2. Fall: lpszSQL = ein Tabellenname

Das Recordset verwendet den Datensatzfeldaustausch (Record Field Exchange, RFX), um die Spaltenliste auf der Grundlage der Spaltennamen zu erstellen, die in den RFX-Funktionsaufrufen in der Überschreibung der Recordset-Klasse von DoFieldExchange angegeben sind. Wenn Sie einen Assistenten zum Deklarieren der Recordset-Klasse verwendet haben, hat dieser Fall das gleiche Ergebnis wie der erste Fall (vorausgesetzt, Sie übergeben den gleichen Tabellennamen wie im Assistenten). Wenn Sie zum Schreiben Ihrer Klasse keinen Assistenten verwenden, ist der zweite Fall die einfachste Möglichkeit, um die SQL-Anweisung zu konstruieren.

Im folgenden Beispiel wird eine SQL-Anweisung konstruiert, die Datensätze aus einer MFC-Datenbankanwendung auswählt. Wenn das Framework die GetDefaultSQL-Memberfunktion aufruft, gibt die Funktion den Namen der Tabelle (SECTION) zurück.

CString CEnrollSet::GetDefaultSQL()
{
    return "SECTION";
}

Um die Namen der Spalten für die SQL-Anweisung vom Typ SELECT abzurufen, ruft das Framework die DoFieldExchange-Memberfunktion auf.

void CEnrollSet::DoFieldExchange(CFieldExchange* pFX)
{
    pFX->SetFieldType(CFieldExchange::outputColumn);
    RFX_Text(pFX, "CourseID", m_strCourseID);
    RFX_Text(pFX, "InstructorID", m_strInstructorID);
    RFX_Text(pFX, "RoomNo", m_strRoomNo);
    RFX_Text(pFX, "Schedule", m_strSchedule);
    RFX_Text(pFX, "SectionNo", m_strSectionNo);
}

Die vollständige SQL-Anweisung sieht wie folgt aus:

SELECT CourseID, InstructorID, RoomNo, Schedule, SectionNo
    FROM SECTION

3. Fall: lpszSQL = eine SELECT/FROM-Anweisung

Sie geben die Spaltenliste manuell an, anstatt sich auf die automatische Konstruktion durch RFX zu verlassen. Dies empfiehlt sich ggf. in folgenden Fällen:

  • Sie möchten nach SELECT das Schlüsselwort DISTINCT angeben.

    Ihre Spaltenliste muss den Spaltennamen und -typen in der gleichen Reihenfolge entsprechen, in der sie auch in DoFieldExchange aufgeführt sind.

  • Sie müssen Spaltenwerte manuell mithilfe der ODBC-Funktion ::SQLGetData abrufen, anstatt RFX zu nutzen, um Spalten für Sie zu binden und abzurufen.

    Vielleicht möchten Sie z. B. neue Spalten aufnehmen, die ein Kunde Ihrer Anwendung den Datenbanktabellen hinzugefügt hat, nachdem die Anwendung verteilt wurde. Sie müssen diese zusätzlichen Felddatenmember hinzufügen, die noch nicht bekannt waren, als die Klasse mit einem Assistenten deklariert wurde.

    Ihre Spaltenliste muss den Spaltennamen und -typen in der gleichen Reihenfolge entsprechen, in der sie auch in DoFieldExchange aufgeführt sind, gefolgt von den Namen der manuell gebundenen Spalten. Weitere Informationen finden Sie unter Recordset: Dynamisches Binden von Datenspalten (ODBC).

  • Sie möchten Tabellen verknüpfen, indem Sie mehrere Tabellen in der Klausel vom Typ FROM angeben.

    Weitere Informationen und ein entsprechendes Beispiel finden Sie unter Recordset: Ausführen einer Verknüpfung (ODBC).

4. Fall: lpszSQL = SELECT/FROM plus WHERE und/oder ORDER BY

Sie geben alles an: die Spaltenliste (basierend auf den RFX-Aufrufen in DoFieldExchange), die Tabellenliste und den Inhalt einer Klausel vom Typ WHERE und/oder einer Klausel vom Typ ORDER BY. Wenn Sie Ihre Klauseln vom Typ WHERE und/oder ORDER BY auf diese Weise angeben, verwenden Sie nicht m_strFilter und/oder m_strSort.

5. Fall: lpszSQL = Aufruf einer gespeicherten Prozedur

Wenn Sie eine vordefinierte Abfrage aufrufen müssen (z. B. eine gespeicherte Prozedur in einer Microsoft SQL Server-Datenbank), müssen Sie eine Anweisung vom Typ CALL in die Zeichenfolge schreiben, die Sie an lpszSQL übergeben. Das Deklarieren einer Recordset-Klasse zum Aufrufen einer vordefinierten Abfrage wird von den Assistenten nicht unterstützt. Nicht alle vordefinierten Abfragen geben Datensätze zurück.

Wenn eine vordefinierte Abfrage keine Datensätze zurückgibt, können Sie die CDatabase-Memberfunktion ExecuteSQL direkt verwenden. Bei einer vordefinierten Abfrage, die Datensätze zurückgibt, müssen auch die RFX-Aufrufe für alle von der Prozedur zurückgegebenen Spalten manuell in DoFieldExchange geschrieben werden. Die RFX-Aufrufe müssen sich in der gleichen Reihenfolge befinden und die gleichen Typen zurückgeben wie die vordefinierte Abfrage. Weitere Informationen finden Sie unter Recordset: Deklarieren einer Klasse für eine vordefinierte Abfrage (ODBC).

Weitere Informationen

SQL: SQL- und C++-Datentypen (ODBC)
SQL: Durchführen direkter SQL-Aufrufe (ODBC)