#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include /**************************************************************************************************************** * NOTES ET OBSERVATIONS GENERALES * * QSqlRecord => Structure d'un enregistrement (comprend les objets champs en particulier qu'il manipule) * On l'utilise pour modifier la structure d'une table * QSqlQuery => Représente à la fois une requête, et les résultats de cette requête (si c'est une requête * de type SELECT). On l'utilise pour rechercher des valeurs, les modifier, les supprimer ... * * - Certains exemples travaillent sur une base de données ACCESS pour laquelle une source de donnée ODBC DNS * nommée Bdd_Running a été créée préalablement. * - Un autre exemple travaille sur une base de donnée ACCESS par son chemin d'accès, sans avoir créé de source * DNS préalablement. * - On a travaillé à la fois sur des tables existantes, mais également sur une table que l'on a créée dans la * procédure main() : la table ma_table. * * - Certaines méthodes ne semblent pas fonctionner avec ODBC (QSqlDriver.last() en particulier) * - L'accès aux données et enregistrement des données se font essentiellement via les requêtes SQL * - Ce projet a été créé et testé sur Windows 7. * ****************************************************************************************************************/ int main(int argc, char *argv[]) { QApplication app(argc, argv); QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "Bdd_Running"); db.setDatabaseName("Bdd_Running"); // DSN que nous avons préalablement créé. db.setUserName(""); db.setPassword(""); QString message("Opération sur la base de données :"); // Ouverture de la base de données if(!db.open()) { QMessageBox::critical(0, QObject::tr("Database Error"), db.lastError().text()); } else if(db.open()) { QMessageBox::information(0,"Ouverture" , "Source de données ouverte : " + db.databaseName()); } // Gestion des ERREURS : Création d'une requête qui ne fonctionne pas (QSqlQuery 'équivalent' de Recordset en VB) QSqlQuery requeteur(db); requeteur.exec("create database new_Yves"); // Cette requête SQL ne fonctionne pas => Récupération de l'erreur message = message + "\n" + "ERREUR survenue : " + requeteur.lastError().text() ; // Déplacement dans les enregistrements requeteur.exec("SELECT * FROM Secteurs_Run"); requeteur.seek(2); // Se positionne sur le 3° enregistrement (0 renvoie au 1° enregistrement) int rg = requeteur.at() + 1; // Donne la position de l'enregistrement courrant message = message + "\n" + QString::number(rg) + "° enregistrement " + ", champ 'libellé' = " + requeteur.value("libellé").toString(); // Recherche de noms de champs dans une table existante ou dans une requête créée dans C++ QSqlRecord secteurs_Parcours = db.record("Secteurs_Parcours"); QSqlRecord secteurs_Run = requeteur.record(); QSqlField champ = secteurs_Run.field(3); // Le rang des champs commence à 0 message = message + "\n" + "Le 4° champ de la table 'Secteurs_Run' est nommé : " + champ.name(); champ = secteurs_Parcours.field(3); // Le rang des champs commence à 0 message = message + "\n" + "Le 4° champ de la table 'Secteurs_Parcours' est nommé : " + champ.name(); // Travail sur les enregistrements type QSqlRecord //================================================ message = message + "\n" + "Le 5° champ du QSqlRecord 'secteurs_Run' vaut : " + secteurs_Run.value(4).toString(); // Création d'une table //===================== requeteur.exec("CREATE table ma_table (id_article INT NOT NULL, titre_article VARCHAR(50) NOT NULL, nom_auteur VARCHAR(30) NOT NULL, id_rubrique INT NOT NULL)"); // Ajout d'enregistrements via SQL //================================ // 1° Méthode : Exécution d'une requête SQL type INSERT QString valeurTitre = "Variable Nouveau Titre"; QString req = "INSERT INTO ma_table (id_article, titre_article, nom_auteur, id_rubrique) VALUES (1, '" + valeurTitre + "', 'aaa', 3)"; requeteur.exec(req); // 2° Méthode : Utilisation de variable bind QSqlQuery maRequete(db); req = "INSERT INTO ma_table (id_article, titre_article, nom_auteur, id_rubrique) VALUES (:id_article, :titre_article, :nom_auteur, :id_rubrique)"; if (maRequete.prepare(req)) { maRequete.bindValue(":id_article", 2); // Liaison entre la variable bind et la variable applicative pour l'identifiant. maRequete.bindValue(":titre_article", "valeurTitre Article"); maRequete.bindValue(":nom_auteur", "Nouvel auteur"); maRequete.bindValue(":id_rubrique", 5); maRequete.exec(); maRequete.bindValue(":id_article", 8); // Liaison entre la variable bind et la variable applicative pour l'identifiant. maRequete.bindValue(":titre_article", "valeurTitre Article" + valeurTitre); maRequete.bindValue(":nom_auteur", "Nouvel auteur 2"); maRequete.bindValue(":id_rubrique", 9); maRequete.exec(); if (maRequete.lastError().isValid()) { QMessageBox::information(0,"Erreur" , maRequete.lastError().text()); } } // Recherche d'enregistrement //=========================== /* *Nota : Les bases de données ACCESS ne supportent pas la fonction QSqlQuery::last() et génèrent une erreur */ req = "SELECT * from Parcours_Temp where(Id_Athlète = 2) ORDER BY Nom_Parcours"; QSqlQuery recherche(db); recherche.exec(req); recherche.seek(0); // Se positionne sur le 1° enregistrement recherche.first(); // Se positionne sur le premier enregistrement recherche.last(); // Se positionne sur le dernier enregistrement (ne semble pas fonctionner avec les Bdd Access) int cpt = 0; // Nombre d'enregistrements de la requête while (recherche.next()) { cpt++; } recherche.seek(cpt-1); // Se positionne sur le dernier enregistrement (0 désigne le 1° enregistrement) QString ValeurChamp = recherche.value(2).toString(); QMessageBox::information(0,db.databaseName() , QString::number(cpt) + " parcours pour l'athlète 2 - Dernier parcours de la liste = " + ValeurChamp); recherche.seek(1); // Se positionne sur le 2° enregistrement rg = recherche.at(); message = message + "\n" + "Nombre de secteurs pour athlète Id = 2 : " + QString::number(cpt+1) + " . " + QString::number(rg) + "° secteur de la liste = " + recherche.value("Nom_Parcours").toString(); // Test des erreurs survenues (ici sur l'objet 'recherche') //========================================================= if (recherche.lastError().isValid()) // Teste s'il y a eu une erreur sur l'objet 'recherche' { QMessageBox::information(0,"Erreur survenue" , recherche.lastError().text()); } // Test des fonctions acceptées par la Bdd //======================================== if (!db.driver()->hasFeature(QSqlDriver::QuerySize)) // Teste la prise en compte par la Bdd d'une fonction du driver (size() { std::cout << "------Fonction size non supportee ----------" << std::endl; message = message + "\n" + "Fonction size non supportee" ; } if (!db.driver()->hasFeature(QSqlDriver::QSqlDriver::Transactions)) // Teste la prise en compte par la Bdd des transactions { std::cout << "------Transactions non supportees ----------" << std::endl; message = message + "\n" + "Transactions non supportees" ; } // Création d'une connexion a une Bdd existante sans création de DNS ODBC préalable //================================================================================= QString fichier = QFileDialog::getOpenFileName(0, "Ouvrir un fichier de base de données", "D:\\Maison\\Applications Partagées\\Running", "Images (*.mdb *.odb)"); fichier = fichier.replace("\\", "\\\\", Qt::CaseSensitive); // Remplace les caractères '\' par '\\' (On double les caractères \ pour indiquer qu'il ne s'agit pas d'un marqueur du style \n qui est un retour chariot) QSqlDatabase newDb = QSqlDatabase::addDatabase("QODBC"); /* Nota important : Dans le chemin de connexion sous windows, il faut OBLIGATOIREMENT * remplacer l'anti-slash (\) par un double anti-slash (\\). * De plus, le fichier ne doit pas être utilisé par ailleurs, même en lecture simple * des données */ newDb.setDatabaseName("DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=" + fichier); newDb.open(); QSqlQuery new_req(newDb); new_req.exec("SELECT * FROM Secteurs_Run"); new_req.seek(3); std::string lect = new_req.value(4).toString().toStdString(); std::cout << lect << std::endl; message = message + "\n" + "Le champ '" + new_req.record().fieldName(4) + "' du 4° enregistrement vaut : " + new_req.value("libellé").toString(); // Création d'une table //===================== new_req.exec("CREATE table ma_table (id_article INT NOT NULL, titre_article VARCHAR(50) NOT NULL, nom_auteur VARCHAR(30) NOT NULL, id_rubrique INT NOT NULL)"); // Ajout d'enregistrements via SQL //================================ valeurTitre = "Nouveau Titre "; int i(0); while (i < 5) { req = "INSERT INTO ma_table (id_article, titre_article, nom_auteur, id_rubrique) VALUES (" + QString::number(i+1) + ", '" + valeurTitre + QString::number(i+1) + "', 'mon auteur " + QString::number(i+10) + "', 7)"; new_req.exec(req); i++; } // Modification des données d'un enregistrement //============================================= // Via record new_req.exec("SELECT * FROM ma_table"); new_req.seek(1); std::cout << "Position = " << new_req.at() << " - Champ " << new_req.record().field(2).name().toStdString() << " = " << new_req.record().field(2).value().toString().toStdString() << std::endl; QVariant valeur("aaa"); // ===== Portion de code ne fonctionnant pas ===== new_req.record().field(2).setValue(valeur); new_req.record().setValue(2, valeur); // ===== Fin portion de code ne fonctionnant pas ===== std::cout << "Position = " << new_req.at() << " - Champ " << new_req.record().field(2).name().toStdString() << " = " << new_req.record().value(2).toString().toStdString() << std::endl; // Via SQL new_req.exec("UPDATE ma_table SET titre_article='Titre modifié' where id_article = 3"); message = message + "\n" + "Le titre de l'article 3 a été modifié par '-Titre modifié-'" ; // Récupère les éventuelles erreurs lors de l'exécution des requêtes modif et suppression //======================================================================================= if (new_req.lastError().isValid()) { QMessageBox::information(0,db.databaseName() , new_req.lastError().text()); } if (newDb.lastError().isValid()) { QMessageBox::information(0,db.databaseName() , newDb.lastError().text()); } std::cout << "Erreurs relevées : " << newDb.lastError().text().toStdString() << " - " << new_req.lastError().text().toStdString() << std::endl; // Suppression d'enregistrement //============================= new_req.exec("DELETE FROM ma_table where id_article = 4"); message = message + "\n" + "L'article 4 a été supprimé" ; // Message récapitulatif des actions effectuées //============================================= QMessageBox::information(0,db.databaseName() , message); // Suppression d'une table //======================== QMessageBox::information(0,db.databaseName() , "Les objets créés vont être supprimés"); requeteur.exec("drop table ma_table"); new_req.exec("drop table ma_table"); if (requeteur.lastError().isValid()) // Si la table est verrouillée (ouverte en mode modif), une erreur se produit et interdit sa suppression { QMessageBox::information(0,"Erreur" , requeteur.lastError().text()); } return 0; }