• Aucun résultat trouvé

Connexion à une base de données

N/A
N/A
Protected

Academic year: 2022

Partager "Connexion à une base de données"

Copied!
9
0
0

Texte intégral

(1)

1

Connexion à une base de données

„

On souhaite réaliser la connexion d'un programme avec des sources de données

„ Ici, des bases de données relationnelles

„

Deux approches sont possibles qui mettent en œuvre chacune son propre jeu de classes MFC

„ La première approche concerne l'interface DAO ( Data Access Objects).

„L'approche DAO est une interface sur le moteur de données Jet qui permet de stocker et d'extraire des données dans différents SGBD.

„Jet est le moteur utilisé par le SGBD Microsoft Access (.mdb)

„ Aussi si l'application à développer concerne essentiellement des bases de données Access, l'approche DAO peut être conseillée.

2

Connexion à une base de données

„ La deuxième approche concerne l'interface ODBC (Open Database Connectivity).

„ Cette approche permet de manier tous les formats de données pour lesquels le pilote ODBC approprié existe.

„ Ce pilote existe pour les bases comme : Microsoft Access, Oracle, DBase 5, …

„ Si l'application doit travailler sur différentes sources de données dans un environnement client/serveur, l'approche ODBC est préférable.

„ ODBC est une interface, indépendante du système, avec un environnement de bases de données avec un pilote ODBC.

„ Le pilote définit l'interface entre les appels pour des opérations sur les bases de données (indépendants du système) et les spécificités de la mise en œuvre d'une BD particulière.

„ Nous allons uniquement étudier l'approche ODBC, avec ici, une base de données relationnelle sous Microsoft Access

„ et créer une application capable d'aller interroger la base de données

3

Connexion à une base de données Schéma de la base de données

„ On considère une base de données sur des étudiants, dont le schéma est le suivant.

1,n

1,n 1,n

ETUDIANT NoEtudiant Nom Prenom Adresse Age

DIPLOME NoDiplome Libelle Option 1,n

1,1 1,n

1,n

FACULTE NoFaculte Nom Adresse

UNIVERSITE NoUniversite Libelle

1,1 1,n

1,1 1,n

MATIERE NoMatiere Libelle

MODULE NoModule Libelle EPREUVE

NoEpreuve Libelle Coefficient

A reussi Année Obtention Obtient

Note

Appartient Fait partie

Est attaché à

4

Connexion à une base de données Développement d'une application

„

Enregistrement d'une Base de Données pour ODBC

„

Avant de pouvoir utiliser une BD avec OBDC, il faut l'inscrire dans la base de registres.

„

Ceci se fait par l'intermédiaire de la boîte de dialogue "Administrateur de sources de données ODBC"

„

accessible sous :

„

Démarrer -> Panneau de configuration (->Outils d'administration) -> Sources de données ODBC

Connexion à une base de données Développement d'une application

„

Enregistrement d'une Base de Données ODBC

Connexion à une base de données Développement d'une application

„

Pour ajouter une nouvelle source de données, on clique

sur le bouton Ajouter, la fenêtre suivante apparaît :

(2)

7

Connexion à une base de données Développement d'une application

„

On sélectionne le driver souhaité : ici une Base de Données Microsoft Access, puis on clique sur Terminer et on obtient :

8

Connexion à une base de données Développement d'une application

„

Puis on sélectionne, la Base de Données avec l'option Sélectionner :

9

Connexion à une base de données Développement d'une application

„

A ce niveau, la Base de Données Base.mdb est accessible via l'interface ODBC.

„

A partir de là, on peut construire une application Visual C++ qui pourra accéder à la Base de Données

Base de Données Application

Visual C++

ODBC

10

Connexion à une base de données Développement d'une application

„

La création d'un squelette d’application qui manipule une Base de Données peut se faire en sélectionnant certaines options lors de la création du projet sous AppWizard.

„

On peut sélectionner :

„

Une application « Single document » avec une architecture « Document/View ».

„

Et l'option « Vue d'une Base de Données » (sans gestion de fichiers), on ne souhaite pas

conserver les données dans des fichiers.

11

Connexion à une base de données Développement d'une application

„

On sélectionne la Source de données…

pour choisir la base de données et le mode de travail.

12

Connexion à une base de données Développement d'une application

„

On obtient ensuite une

fenêtre permettant de

sélectionner une (ou

plusieurs tables) sur

laquelle on veut

travailler (d'autres

pourront être ajoutées

ensuite…).

(3)

13

Connexion à une base de données Développement d'une application

„ Les étapes suivantes sont inchangées. On obtient enfin :

„ Les classes CBDView et CBDSet vont servir à stocker et visualiser les données de la table Etudiant sélectionnée précédemment.

„ Aussi on renomme ces classes :

„ CBDView ÆCEtudiantView

„ BDView.h ÆEtudiantView.h

„ BDView.cppÆEtudiantView.cpp

„ CBDSet ÆCEtudiantSet

„ BDSet.h ÆEtudiantSet.h

„ BDSet.cppÆEtudiantSet.cpp

14

Les classes MFC prenant en charge ODBC

„

La prise en charge d'ODBC par les MFC est faite à l'aide de 5 classes :

„

CDatabase,

„

CRecordSet,

„

CRecordView,

„

CFieldExchange,

„

CDBException.

15

Connexion à une base de données La classe CDataBase

„

Un objet de la classe CDatabase représente une connexion à la base de données manipulée.

„

Cette connexion doit être faite avant toute opération sur la base.

„

Cette classe possède un certain nombre de méthodes permettant de

„

se connecter à la base (Open, OpenEx), se déconnecter (Close),

„

tester les propriétés de la base (GetConnect, IsOpen, GetDatabaseName, CanUpdate, CanTransact, …),

„

faire des opérations sur la base.

16

Connexion à une base de données La classe CRecordSet

„

Un objet d'une classe dérivée de cette classe représente le résultat d'une opération SELECT de SQL.

„ Lorsqu'une requête est exécutée sur la base,

„ le résultat peut être manipulé grâce à la classe CRecorSet

„ ou plus exactement une classe dérivée de CRecordSet.

„

Cette classe possède plusieurs attributs :

„ m_hstmt: Numéro de handle de la connexion

„ m_nFields: Nombre d'attributs de l'enregistrement

„ m_nParams: Nombre de paramètres (pour la requête)

„ m_pDatabase: Pointeur sur un objet de type CDatabase (connexion)

„ m_strFilter: Chaîne CString qui spécifie la partie WHERE d'une requête SELECT de SQL (Filtre pour la récupération des informations)

„ m_strSort: Chaîne CString qui spécifie une requête SQL avec ORDER BY pour effectuer un tri

Connexion à une base de données La classe CRecordSet

„

Cette classe possède de nombreuses méthodes dont certaines sont à surcharger.

„

Elles permettent :

„

de construire un objet de la classe,

„

de tester les propriétés,

„

de mettre à jour les valeurs,

„

de parcourir les valeurs,

„

etc …

Connexion à une base de données La classe CRecordView

„

Un objet d'une classe dérivée de CRecordView permet :

„

d'afficher la ligne en cours d'un jeu de lignes (c'est-à- dire l'enregistrement courant parmi l'ensemble des enregistrements).

„

Cet objet « vue » utilise une boîte de dialogue pour afficher les données.

„

Il existe des mécanismes automatiques de mise à jour des contrôles de la boîte de dialogue

„

échange d'informations entre la boîte de dialogue, la

classe CRecordSet et la base de données.

(4)

19

Connexion à une base de données La classe CRecordView

„

L'aspect par défaut d'une fenêtre d'affichage dérivée de CRecordView est celle ci-dessus.

20

Connexion à une base de données La classe CFieldExchange

„

Cette classe permet l'échange de données entre la base de données et un jeu de lignes (i.e. un objet de type CRecordSet).

„

Des mécanisme automatiques permettent ces échanges.

„

La méthode SetFieldType permet de définir le mode d'échange souhaité.

21

Connexion à une base de données La classe CDBException

„

Cette classe est la classe des exceptions produites lors d'opérations erronées avec OBDC.

„

Les attributs de cette classe sont :

„

m_nRetCode : Code d'erreur ODBC

„

m_strError : Chaîne décrivant l'erreur m_strStateNativeOrigin : Chaîne décrivant l'erreur (associé au code OBBC)

22

Le squelette d'application créé par l’assistant

„

Comme nous l'avons vu précédemment,

„

on a créé automatiquement un squelette d'application avec les classes

„

CEtudiantView, CEtudiantSet, CBDDoc, CBDApp et CMainFrame.

23

Le squelette d'application créé par l’assistant Les classes CMainFrame, CBDApp et CBDDoc

„ Les classes CMainFrame et CBDApp créées sont standard

„ et CApp possède la méthode InitInstance permettant la création de l'architecture document/vue.

„ La classe CBDDoc ne diffère de la classe généralement créée que par l'insertion d'un attribut de type CEtudiantSet :

class CBDDoc : public CDocument {protected: CBDDoc();

DECLARE_DYNCREATE(CBDDoc) public:

CEtudiantSet m_etudiantSet;

public:

virtual BOOL OnNewDocument();

virtual ~CBDDoc();

protected:

DECLARE_MESSAGE_MAP() };

24

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„

Cette classe permet l'extraction d'informations de la base de données.

„

Ici compte-tenu des options choisies lors de la création du projet avec la sélection de la table Etudiant,

„

la classe CEtudiantSet va permettre de stocker

les informations concernant un étudiant;

(5)

25

La classe CEtudiantSet

class CEtudiantSet : public CRecordSet {

public:

CEtudiantSet(CDatabase* pDatabase = NULL);

DECLARE_DYNAMIC(CEtudiantSet) // Field/Param Data

//{{AFX_FIELD(CEtudiantSet, CRecordset) long m_NoEtudiant;

CStringW m_Nom;

CStringW m_Prenom; // CStringW = CString en unicode CStringW m_Adresse;

long m_Age;

CStringW m_Sexe;

//}}AFX_FIELD // Overrides

// ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEtudiantSet)

public:

virtual CString GetDefaultConnect(); // Default connection string virtual CString GetDefaultSQL(); // default SQL for Recordset virtual void DoFieldExchange(CFieldExchange* pFX); // RFX support //}}AFX_VIRTUAL

};

26

La classe CEtudiantSet

„ Le constructeur et les attributs

„ Les attributs qui permettent le stockage des informations sur un étudiant sont automatiquement générés à partir des nom des attributs de la table Etudiant de la Base de Données (qui avait été sélectionnée).

„ Le constructeur possède un paramètre de type pointeur sur CDatabase

„ CEtudiant :: CEtudiantSet(CDatabase* pDatabase = NULL);

„ Ce paramètre permet de spécifier une connexion existante à une base de données ou vaut NULL si aucune connexion n'a encore été réalisée.

„ Ce constructeur est appelé pour initialiser l'attribut m_etudiantSet de type CEtudiantSet de la classe CBDDoc. Pour cet attribut, la valeur par défaut NULL du constructeur est utilisée.

„ Dans ce cas, le constructeur appelle la méthode GetDefaultConnect pour définir la base de données à utiliser pour l'objet CEtudiantSet.

27

Le squelette d'application créé par l’assistant

La classe CEtudiantSet - La connexion à la base de données

„ La méthode GetDefaultConnect est une méthode virtuelle pure de la classe de base CRecordSet qui doit donc être surchargée dans la classe dérivée CEtudiantSet.

„ Cette méthode retourne une chaîne de caractères qui permet l'identification de la base de données.

CString CEtudiantSet::GetDefaultConnect() {

return _T("ODBC;DSN=Etudiants");

}

„ Ici la base de données s'appelle Etudiants et l'accès se fait par une interface de type ODBC.

„ On peut aussi d'autres informations comme le nom de connexion de l'utilisateur de la base et son mot de passe.

CString CEtudiantSet::GetDefaultConnect() {

return _T("ODBC;DSN=Etudiants";UID=Cullot;PWD=secret);

}

28

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„

L’interrogation de la base de données

„ Comme nous l'avons vu précédemment, la classe CEtudiantSet possède un attribut pour chaque champ de la table Etudiant

„ Le type de l'attribut est identique à celui du champ de la table de la base de données.

// Field/Param Data

//{{AFX_FIELD(CEtudiantSet, CRecordset)

long m_NoEtudiant;

CStringW m_Nom;

CStringW m_Prenom;

CStringW m_Adresse;

long m_Age;

CStringW m_Sexe;

//}}AFX_FIELD

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„ L'opération SQL qui renseigne le jeu de lignes i.e. les données membres CEtudiantSet est spécifié dans la méthode GetDefaultSQL().

„ Attention, il est préférable de conserver toutes les colonnes même si elles ne sont pas utilisées ou bien de les supprimer à l'aide de AppWizard mais sans supprimer les clés primaires.

CString CEtudiantSet::GetDefaultSQL() {

return _T("[Etudiant]");

}

„ Ici, toute la table Etudiant de la base de données est sélectionnée. Cela correspond à une requête de la forme :

SELECT * FROM Etudiant

„ pour la base de données Etudiants.

„ En fait, la requête est construite à partir de la chaîne retournée par la fonction GetDefaultSQL().

„ D'autres informations pour décrire les clauses WHERE ou ORDER BY peuvent

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„ Les échanges de données entre la base et le jeu de lignes

„ Les échanges sont gérés grâce à la méthode DoFieldExchange de la classe CEtudiantSet.

„ Cette méthode fonctionne de façon un peu similaire à la méthode DoDataExchange qui assure les échanges entre les contrôles d'une boîte de dialogue et les attributs de la classe associée à la boîte.

void CEtudiantSet::DoFieldExchange(CFieldExchange* pFX) {

//{{AFX_FIELD_MAP(CEtudiantSet)

pFX->SetFieldType(CFieldExchange::outputColumn);

RFX_Long(pFX, _T("[NoEtudiant]"), m_NoEtudiant);

RFX_Text(pFX, _T("[Nom]"), m_Nom);

RFX_Text(pFX, _T("[Prenom]"), m_Prenom);

RFX_Text(pFX, _T("[Adresse]"), m_Adresse);

RFX_Long(pFX, _T("[Age]"), m_Age);

RFX_Text(pFX, _T("[Sexe]"), m_Sexe);

//}}AFX_FIELD_MAP

(6)

31

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„

Le paramètre pFX est une pointeur sur une objet de type CFieldExchange.

„

Le mode pour de transfert pour les fonctions RFX_ est fixé par la méthode : SetFieldType avec l'appel :

„ pFX->SetFieldType(CFieldExchange::outputColumn);

„

Ici, il s'agit d'un transfert de la base vers le jeu de lignes.

„

La correspondance entre la valeur d'un attribut de la base et l'attribut de la classe est fait par les macros AFX_ .

„

RFX_Long(pFX, _T("[NoEtudiant]"), m_NoEtudiant);

„ Ici le champs NoEtudiant de la base Etudiants est associé à la variable m_NoEtudiant de la classe CEtudiantSet. Le type de cette variable est long.

32

Le squelette d'application créé par l’assistant La classe CEtudiantSet

„

Le constructeur de la classe CEtudiantSet initialise les diiférents attributs de la base.

CEtudiantSet::CEtudiantSet(CDatabase* pdb) : CRecordset(pdb) {

//{{AFX_FIELD_INIT(CEtudiantSet) m_NoEtudiant = 0;

m_Nom = _T("");

m_Prenom = _T("");

m_Adresse = _T("");

m_Age = 0;

m_Sexe = _T("");

m_nFields = 6;

//}}AFX_FIELD_INIT m_nDefaultType = snapshot;

}

33

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

Le « dessin » de la vue est défini à l'aide d'une boîte de dialogue et la vue est liée à un objet du jeu de lignes.

„

Le mécanisme complet d'échange est le suivant :

Base de données Etudiants Table : Etudiant NoEtudiant Nom

….

long m_NoEtudiant CStringW m_Nom

Classe CEtudiantSet DoFieldExchange

Boîte de dialogue de la classe CEtudiantView

Edit (m_NoEtudiant)

….

DoDataExchange

34

Le squelette d'application créé par l’assistant La classe CEtudiantView

„ Entête de la classe CEtudiantView : class CEtudiantView : public CRecordView {

protected:

CEtudiantView();

DECLARE_DYNCREATE(CEtudiantView) public:

//{{AFX_DATA(CEtudiantView) enum{ IDD = IDD_BD_FORM };

CEtudiantSet* m_pSet;

//}}AFX_DATA CBDDoc* GetDocument();

public:

virtual CRecordset* OnGetRecordset();

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual void DoDataExchange(CDataExchange* pDX);

virtual void OnInitialUpdate();

DECLARE_MESSAGE_MAP() };

35

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

La classe CEtudiantView possède un attribut de type pointeur sur CEtudiantSet.

„

Cet attribut "met en œuvre" le lien entre la ligne de données et la vue.

„

De même, un type énuméré est défini :

„

enum{ IDD = IDD_BD_FORM };

„ou IDD_BD_FORM est l'identifiant de la ressource boîte de dialogue de la vue.

„

Cette boîte de dialogue est en partie prédéfinie dans le squelette de l'application proposée,

„

il suffit de compléter cette boîte avec les contrôles

d'édition souhaités.

36

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

Le constructeur de la classe CEtudiantView

CEtudiantView::CEtudiantView() : CRecordView(CEtudiantView::IDD)

{ m_pSet = NULL; }

„

Le constructeur par défaut de la classe CEtudiantView

„

appelle le constructeur avec paramètre de la classe CRecordView avec l'identifiant de la ressource de dialogue qui doit être associée à la vue.

„

Le pointeur sur une ligne est initialisé à NULL

(7)

37

La classe CEtudiantView

„

Initialisation de la vue

„

La valeur du pointeur m_pSet est affectée lors de la création de la vue

„

avec l'appel de la méthode OnInitialUpdate();

„

Elle est affectée à la valeur du pointeur m_EtudiantSet défini dans la classe CBDDoc.

„

Ce pointeur a été initialisé lors de la création de squelette avec les choix de la base de données et de la table.

„

Les deux pointeurs (celui de CBDDoc et de CEtudiantView) vont référencer le même objet;

38

La classe CEtudiantView void CEtudiantView::OnInitialUpdate() {

m_pSet = &GetDocument()->m_etudiantSet;

CRecordView::OnInitialUpdate();

GetParentFrame()->RecalcLayout();

ResizeParentToFit();

}

„

Les autres instructions assurent l'initialisation

„ CRecordView::OnInitialUpdate();

„

et le bon dimensionnement de la fenêtre cadre par rapport à la boîte de dialogue.

„ GetParentFrame()->RecalcLayout();

„ ResizeParentToFit();

39

Le squelette d'application créé par l’assistant La classe CEtudiantView

„ Création de la boîte de dialogue de vue

„ Cette étape consiste à compléter la boîte de dialogue

„ en introduisant des contrôles d'édition pour les différents attributs de la classe CEtudiantSet.

„ Forme initiale de la boîte de dialogue proposée :

40

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

On construit donc la boîte de dialogue souhaitée :

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

Pour chaque attribut, un contrôle statique et un contrôle d'édition sont définis.

„

L’assistant détermine un nom de variable pour un contrôle d'édition

„ en utilisant le texte du contrôle statique qui le précède.

„

L'ordre est déterminé par la séquence de touches Tab.

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

Liaison entre les contrôles de la boîte et le jeu de lignes

„

Pour que les échanges entre la boîte de dialogue de la vue et le jeu de lignes s'effectuent

correctement,

„

il faut que la méthode DoDataExchange de la classe CEtudiantView soit complétée.

„

Il faut définir le lien entre les contrôles d'édition

et l'attribut m_pSet de la classe CEtudiantView.

(8)

43

Le squelette d'application créé par l’assistant La classe CEtudiantView

„

On complète la méthode DoDataExchange :

void CEtudiantsView::DoDataExchange(CDataExchange* pDX) {

CRecordView::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CEtudiantsView)

DDX_FieldText(pDX, IDC_NOM, m_pSet->m_Nom, m_pSet);

DDX_FieldText(pDX, IDC_PRENOM, m_pSet->m_Prenom, m_pSet);

DDX_FieldText(pDX, IDC_ADRESSE, m_pSet->m_Adresse, m_pSet);

DDX_FieldText(pDX, IDC_SEXE, m_pSet->m_Sexe, m_pSet);

DDX_FieldText(pDX, IDC_NOETUDIANT, m_pSet->m_NoEtudiant, m_pSet);

DDX_FieldText(pDX, IDC_AGE, m_pSet->m_Age, m_pSet);

//}}AFX_DATA_MAP }

44

Le squelette d'application créé par l’assistant Test de l’application complète

„ L'application développée permet d'accéder à la base de données "Etudiants" par une interface ODBC.

„ Cette application récupère toutes les informations de la table "Etudiant" et permet leur affichage dans une vue spécialisée.

„ La vue dispose d'outils pour faire "défiler" les enregistrements, se placer sur le 1er enregistrement ou le dernier.

45

Le squelette d'application créé par l’assistant Ajout d’un deuxième jeu de lignes

„

On peut décider d'ajouter d'autres jeux de lignes

„

pour traiter les informations d'autres tables de la base de données.

„

Le principe consiste à définir

„

Une nouvelle classe dérivée de CRecordSet,

„par exemple CObtientSet si on s'intéresse aux épreuves obtenues par un étudiant.

„

Une classe « vue » associée à cette table, pour afficher les informations (aussi dérivée de CRecordView)

„

L'application devra prendre en charge l'affichage des différentes vues.

46

Le squelette d'application créé par l’assistant Ajout d’un deuxième jeu de lignes

„

Ajout de la classe CObtientSet

47

Le squelette d'application créé par l’assistant Ajout d’un deuxième jeu de lignes

„ Comme précédemment, la classe CObtientSet a été créée class CObtientSet : public CRecordset

{ public:

long m_NoEtudiantParam;

CObtientSet(CDatabase* pDatabase = NULL);

DECLARE_DYNAMIC(CObtientSet) //{{AFX_FIELD(CObtientSet, CRecordset)

long m_NoEtudiant;

long m_NoEpreuve;

float m_Note;

//}}AFX_FIELD

//{{AFX_VIRTUAL(CObtientSet) public:

virtual CString GetDefaultConnect();

virtual CString GetDefaultSQLvirtual void DoFieldExchange(CFieldExchange* pFX);

//}}AFX_VIRTUAL

}; 48

Le squelette d'application créé par l’assistant Ajout d’un deuxième jeu de lignes

„

Un attribut de type pointeur sur sur

CObtientSet a aussi été ajouté dans la classe cBDDoc :

„

CObtientSet m_ObtientSet;

(9)

49

Ajout d’un deuxième jeu de lignes

„

Création de la ressource dialogue

50

Ajout d’un deuxième jeu de lignes

„

Puis on associe une classe à cette boîte de dialogue.

„

La classe CObtientView qui dérive de la classe CRecordView.

51

Le squelette d'application créé par l’assistant Ajout d’un deuxième jeu de lignes

„

Utilisation des différentes vues

„

Ces deux ensembles d'objet de jeux de lignes :

„

CEtudiantSet et CObtientSet

„

et les vues associées

„

CEtudiantsView et CObtientView

„

permettent de travailler avec les tables « Etudiant » et « Obtient » de la base de données

« Etudiants ».

„

L'application devra se charger de gérer ces différentes vues.

52

Connexion à une base de données Bilan

„

L'exemple présenté montre

„

la lecture d'information dans une base de données

„

l'affichage de ces informations dans des vues.

„

La mise à jour des données de la base nécessite de définir des notions complémentaires

„

comme les transactions, les opérations de mises à jour …

„

etc …

Références

Documents relatifs

La table Tests enregistre également des notes sur le même principe, elle ne sera utilisée que dans la deuxième partie du problème (pour tester l’algorithme)... 3 Interroger

Vous trouverez l''''intégralité des informations et des données dans la documentation pour l''utilisateur

Une base de données est un ensemble structuré de données enregistrées avec le minimum de redondance pour satisfaire simultanément plusieurs utilisateurs de façon sélective en un

[r]

On désire afficher, dans une zone de texte située sous les zones de coordonnées, le nom de la ville située sous la souris (si elle est connue). Proposez une solution (ne

 Le titre et l'année des livres parus après 1999 sans doublons. SELECT DISTINCT l.titre, l.annéeParution FROM

‚ Par exemple : le nom d’un livre et de ses auteurs ñ Inutile de faire plusieurs requêtes. ñ Sélection sur

‚ Par exemple : le nom d’un livre et de ses auteurs ñ Inutile de faire plusieurs requêtes. ñ Sélection sur