SQL : Personnalisation de l’instruction SQL du recordset (ODBC)

Cette rubrique explique :

  • Comment l’infrastructure construit une instruction SQL

  • Comment remplacer l’instruction SQL

Remarque

Ces informations s’appliquent aux classes ODBC MFC. Si vous utilisez les classes DAO MFC, consultez la rubrique « Comparaison SQL entre le moteur de base de données Microsoft Jet et ANSI » dans l’aide de DAO.

Construire des instructions SQL

Votre recordset base sa sélection d’enregistrements principalement sur une instruction SQL SELECT. Lorsque vous déclarez votre classe avec un Assistant, il écrit une version de substitution de la fonction membre GetDefaultSQL qui ressemble à ceci (pour une classe recordset appelée CAuthors).

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

Par défaut, cette substitution retourne le nom de table que vous avez spécifié avec l’Assistant. Dans l’exemple, le nom de la table est « AUTHORS ». Lorsque vous appelez ultérieurement la fonction membre Open du recordset, Open construit une instruction SELECT finale du formulaire :

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

table-name est obtenu en appelant GetDefaultSQL, et rfx-field-list est obtenu à partir des appels de fonction RFX dans DoFieldExchange. C’est ce que vous obtenez pour une instruction SELECT, sauf si vous la remplacez par une version substituée au moment de l’exécution, bien que vous puissiez également modifier l’instruction par défaut par des paramètres ou par un filtre.

Remarque

Si vous spécifiez un nom de colonne qui contient (ou peut contenir) des espaces, vous devez placer le nom entre crochets. Par exemple, le nom d’une colonne « Nom de famille » doit être écrit « [Nom de famille] ».

Pour remplacer l’instruction SELECT par défaut, transmettez une chaîne contenant une instruction SELECT complète lorsque vous appelez Open. Au lieu de construire sa propre chaîne par défaut, le recordset utilise la chaîne que vous fournissez. Si votre instruction de remplacement contient une clause WHERE, ne spécifiez pas de filtre dans m_strFilter, car vous auriez alors deux instructions de filtre. De même, si votre instruction de remplacement contient une clause ORDER BY, ne spécifiez pas de tri dans m_strSort pour ne pas vous retrouver avec deux instructions de tri.

Remarque

Si vous utilisez des chaînes littérales dans vos filtres (ou d’autres parties de l’instruction SQL), vous devrez peut-être « citer » (placer dans des délimiteurs spécifiés) ces chaînes avec un caractère (ou des caractères) de préfixe littéral spécifique au système de gestion de base de données (SGBD) et de suffixe littéral.

Vous pouvez également rencontrer des exigences syntactiques spéciales pour les opérations telles que les jointures externes, en fonction de votre SGBD. Utilisez des fonctions ODBC pour obtenir ces informations auprès de votre pilote pour le SGBD. Par exemple, appelez ::SQLGetTypeInfo pour un type de données particulier, tel que SQL_VARCHAR, pour demander les caractères LITERAL_PREFIX et LITERAL_SUFFIX. Si vous écrivez du code indépendant de la base de données, consultez Annexe C : Grammaire SQL dans Référence du programmeur ODBC pour obtenir des informations détaillées sur la syntaxe.

Un objet recordset construit l’instruction SQL qu’il utilise pour sélectionner des enregistrements, sauf si vous passez une instruction SQL personnalisée. La façon dont cela est fait dépend principalement de la valeur que vous passez dans le paramètre lpszSQL de la fonction membre Open.

La forme générale d’une instruction SQL SELECT est la suivante :

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

Une façon d’ajouter le mot clé DISTINCT à l’instruction SQL de votre recordset consiste à incorporer le mot clé dans le premier appel de fonction RFX dans DoFieldExchange. Par exemple :

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

Remarque

Utilisez cette technique uniquement avec un recordset ouvert en lecture seule.

Substitution de l’instruction SQL

Le tableau suivant présente les possibilités pour le paramètre lpszSQL de Open. Les cas du tableau sont expliqués en suivant le tableau.

Le paramètre lpszSQL et la chaîne SQL résultante

Case Ce que vous passez dans lpszSQL Instruction SELECT résultante
1 NULL SELECT rfx-field-list FROM table-name

CRecordset::Open appelle GetDefaultSQL pour obtenir le nom de la table. La chaîne résultante est l’un des cas de 2 à 5, selon ce que GetDefaultSQL retourne.
2 Un nom de table SELECT rfx-field-list FROM table-name

La liste de champs est extraite des instructions RFX dans DoFieldExchange. Si m_strFilter et m_strSort ne sont pas vides, ajoute les clauses WHERE et/ou ORDER BY.
3* Instruction SELECT complète, mais sans clause WHERE ou ORDER BY Tel qu’il a été passé. Si m_strFilter et m_strSort ne sont pas vides, ajoute les clauses WHERE et/ou ORDER BY.
4* Instruction SELECT complète avec une clause WHERE et/ou ORDER BY Tel qu’il a été passé. m_strFilter et/ou m_strSort doivent rester vides, ou deux instructions de filtre et/ou de tri sont produites.
5 * Un appel à une procédure stockée Tel qu’il a été passé.

* m_nFields doit être inférieur ou égal au nombre de colonnes spécifiées dans l’instruction SELECT. Le type de données de chaque colonne spécifiée dans l’instruction SELECT doit être identique au type de données de la colonne de sortie RFX correspondante.

Cas 1 lpszSQL = NULL

La sélection du recordset dépend de ce que GetDefaultSQL retourne quand CRecordset::Open l’appelle. Les cas 2 à 5 décrivent les chaînes possibles.

Cas 2 lpszSQL = un nom de table

Le recordset utilise Record Field Exchange (RFX) pour générer la liste des colonnes à partir des noms de colonnes fournis dans les appels de fonction RFX dans le remplacement de la classe recordset de DoFieldExchange. Si vous avez utilisé un Assistant pour déclarer votre classe de recordset, ce cas a le même résultat que le cas 1 (à condition que vous transmettiez le même nom de table que celui que vous avez spécifié dans l’Assistant). Si vous n’utilisez pas d’Assistant pour écrire votre classe, le cas 2 est le moyen le plus simple de construire l’instruction SQL.

L’exemple suivant construit une instruction SQL qui sélectionne les enregistrements d’une application de base de données MFC. Lorsque l’infrastructure appelle la fonction membre GetDefaultSQL, la fonction retourne le nom de la table, SECTION.

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

Pour obtenir les noms des colonnes de l’instruction SQL SELECT, l’infrastructure appelle la fonction membre DoFieldExchange.

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

Une fois terminée, l’instruction SQL ressemble à ceci :

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

Cas 3 lpszSQL = une instruction SELECT/FROM

Vous spécifiez la liste de colonnes vous-même plutôt que de compter sur RFX pour la construire automatiquement. Vous pouvez le faire lorsque :

  • Vous souhaitez spécifier le mot clé DISTINCT après SELECT.

    Votre liste de colonnes doit correspondre aux noms et types de colonnes dans le même ordre qu’ils sont répertoriés dans DoFieldExchange.

  • Pour certaines raisons, vous voulez récupérer manuellement les valeurs de colonne à l’aide de la fonction ODBC ::SQLGetData plutôt que de compter sur RFX pour lier et récupérer des colonnes pour vous.

    Par exemple, vous souhaiterez peut-être prendre en charge de nouvelles colonnes ajoutées par un client de votre application aux tables de base de données après la distribution de l’application. Vous devez ajouter ces membres de données de champ supplémentaires, qui n’étaient pas connus au moment où vous avez déclaré la classe avec un Assistant.

    Votre liste de colonnes doit correspondre aux noms et types de colonnes dans le même ordre qu’ils sont répertoriés dans DoFieldExchange, suivis des noms des colonnes liées manuellement. Pour plus d’informations, consultez Recordset : liaison dynamique de colonnes de données (ODBC).

  • Vous souhaitez joindre des tables en spécifiant plusieurs tables dans la clause FROM.

    Pour plus d’informations et pour obtenir un exemple, consultez Recordset : Création d’une jointure (ODBC).

Cas 4 lpszSQL = SELECT/FROM + WHERE et/ou ORDER BY

Vous spécifiez tout : la liste de colonnes (basée sur les appels RFX dans DoFieldExchange), la liste de tables et le contenu d’une clause WHERE et/ou ORDER BY. Si vous spécifiez vos clauses WHERE et/ou ORDER BY ainsi, n’utilisez pas m_strFilter et/ou m_strSort.

Cas 5 lpszSQL = un appel de procédure stockée

Si vous devez appeler une requête prédéfinie (par exemple, une procédure stockée dans une base de données Microsoft SQL Server), vous devez écrire une instruction CALL dans la chaîne que vous passez à lpszSQL. Les Assistants ne prennent pas en charge la déclaration d’une classe recordset pour appeler une requête prédéfinie. Toutes les requêtes prédéfinies ne retournent pas d’enregistrements.

Si une requête prédéfinie ne retourne pas d’enregistrements, vous pouvez utiliser directement la fonction membre CDatabase ExecuteSQL. Pour une requête prédéfinie qui retourne des enregistrements, vous devez également écrire manuellement les appels RFX dans DoFieldExchange pour toutes les colonnes retournées par la procédure. Les appels RFX doivent être dans le même ordre et retourner les mêmes types que la requête prédéfinie. Pour plus d’informations, consultez Recordset : Déclaration d’une classe pour une requête prédéfinie (ODBC).

Voir aussi

SQL : types de données SQL et C++ (ODBC)
SQL : appels SQL directs (ODBC)