Gambas France BETA


Pas de compte ? Incription

Appréhender SQLite avec Gambas

À propos de ce code

Tôt ou tard, on est amené à se diriger vers l'utilisation d'une base de données pour son projet.
Que ce soit l'utilisation d'une base de données pour une application ou un site internet, le besoin pointe toujours le bout de son nez :) .

Ce tutoriel vise uniquement l'utilisation de SQLite dans un contexte de projet qui nécessite une gestion de données pour une application. Cela dit, il n'y a que peu de différence avec l'utilisation de MySQL, PostgreSQL... (mais je vous conseille de vous référer à la documentation sur http://gambasdoc.org pour plus d'informations à leur sujet) .

Ce tutoriel est découpé en quatre parties :

1- Explication sur le fonctionnement d'une BDD (=Base de données).
2- Mise en oeuvre avec Gambas.
3- Afficher les données.
4- Les erreurs que vous pouvez rencontrer.

Explication sur le fonctionnement d'une BDD



Une BDD vous permet de stocker un nombre impressionnant de données de façon structurée.
L'image la plus utilisée dans les tutoriels ou cours concernant les BDD est l'armoire. Pour comprendre comment fonctionne une BDD, vous imaginez simplement votre armoire, qui contient lui-même des tiroirs, qui contiennent eux-mêmes les données :) . Sauf que vous êtes une personne organisée et vous décidez de coller une étiquette sur chaque tiroir (un pour les dossiers de la maison, un autre pour les comptes, un troisième pour votre collection de voitures, ...). Bien maintenant si on fait un petit transfert de vocabulaire, cela donne:

- Armoire = Base de données
- Tiroirs = Tables
- Dossiers = données

On va d'ailleurs même pousser le vice encore plus loin. Pour chaque voiture de votre collection, vous décidez d'indiquer le nom de la voiture, sa puissance, son prix.
Oui vous l'avez compris, ça ressemble dans votre tête à un bête tableau! Ce tableau n'est autre que la Table en langage BDD. Et comme tout bon tableau qui se respecte, ces derniers ont des colonnes! En langage BDD ... ça s'appelle des Champs (Fields en anglais). Ce qui donne pour une table :

- Colonne = Champ
- ligne = Entrée

Donc pour conclure, une base de données n'est rien d'autre qu'une armoire qui a plusieurs tiroirs (=tableaux -> tables) qui contiennent les données. :roll:
En revanche, il faut savoir que chaque Champ de votre Table (oui désormais j'emploie le jargon! :pirat: ) va contenir un type de données bien précis.
Admettons que vous ayez une Table que vous nommez Personne, cette dernière pourrait contenir les données d'un groupe de personnes tel que leurs noms, leurs prénoms et leurs âges.
Nous reconnaissons rapidement ici qu'il s'agit des simples types de données comme String ou Integer en Gambas. Donc ma Table Personne aura pour Champs :

nom = String
prenom = String
age = Integer

Facile n'est-ce pas? ;)
Mais j'ai envie de corser un peu la chose. Chaque entrée nouvelle que vous allez effectués, doivent pouvoir être accessible si quelqu'un vous demande l'âge de Robert! On va donc instaurer un ID(=identifiant unique) à chaque nouvelle entrée. Et pour cela, on va tout bonnement rajouter un Champ qui va contenir cet ID. Notre Table Personne ressemblera donc à celle-ci:

id = Serial
nom = String
prenom = String
age = Integer

Voilà qui est mieux. En revanche... quel est ce type "Serial" ?! :scratch:

C'est simplement une valeur unique, qui est incrémentée automatiquement lorsqu'on ajoute une nouvelle entrée à notre Table!
Oui parce que bon, vous pouvez gérer manuellement cette valeur, mais vous allez vite revenir à ce type croyez-moi :cheers: .
En d'autres termes, lors de vos manipulations sur la base de données, vous n'aurez pas à vous préoccuper de ce Champ. Non me remerciez pas c'est normal... 8)

Désormais, vous savez comment est constitué une base de données. Mais ce que vous savez pas, c'est qu'à lui seul, il utilise son propre langage pour communiquer avec vous! Et il porte le doux nom de SQL. Alors certains pourraient se poser cette question : "Je ne comprends pas, c'est pas Gambas qui va gérer la base de données?! :confused: " .
Et bien si. Gambas va utiliser le langage SQL pour dialoguer avec votre base de données. Un langage qui utilise un langage, c'est pas magnifique?

Ce langage SQL n'est pas vraiment compliqué à comprendre. Il ressemble à de simples phrases(en anglais bien évidemment) qui donnent des ordres à SQLite, comme par exemple:
- Donne-moi tout le contenu de la base de données.
- Donne-moi les personnes qui s'appellent Benoît.
- Ajoute à la table cette charmante nouvelle cliente.
- Modifie l'identité de cette personne, il a changé de prénom!
- Donne-moi toutes les personnes qui ont entre 20 et 30 ans.
- Et j'en passe...

Avec notre cher langage de programmation qui est Gambas, on va se servir de ces résultats pour notre programme.

Bon, j'ai l'honneur de vous informer que vous êtes parés à manger de la crevette moussaillon :pirat: !!
C'est parti!

Mise en oeuvre avec Gambas



Commencez par créer un nouveau projet, en veillant à bien inclure les composants gb.db et gb.sqlite3.

Il faut savoir que pour utiliser une BDD, il faut se connecter à elle. Qui dit connexion, dit également mot de passe, login, port ... et la liste habituelle.
Sauf qu'ici, on utilise SQLite. Et ce dernier n'a pas vraiment la notion d'utilisateur et tout ce qui s'en suit. Souvenez-vous que dans notre exemple, nous utilisons SQLite afin de stocker des informations d'une application locale. (Oui parce qu'utiliser des fichiers pour stocker le nom, prénom et l'age de 200 personnes ça va 5 minutes :roll: . D'autant plus qu'il faudrait coder un parser pour récupérer chaque données. Bref SQLite travaille très bien à ce poste!)
Comme je disais, c'est un peu différent avec lui. Vous avez l'habitude d'utiliser la propriété .Host pour indiquer une adresse IP. Et bien ici on va s'en servir pour indiquer le chemin d'accès à votre BDD sur votre disque dur. La propriété .Host va seulement contenir le chemin, pas le nom du fichier. Pour ce dernier, nous allons conjointement utiliser une propriété .Name.

Vous l'avez deviné, si j'ai parlé de propriété, c'est qu'il y a un objet derrière tout ça ;) ! Et cet objet va représenter notre connexion et notre base de données dans la foulée donc.
Et tant qu'on parle d'objets, autant vous dire directement que pour notre Table, on va utiliser aussi un objet!
Oh mais c'est pas tout. Vu qu'on va travailler avec ces tables, on va justement donner des ordres comme vu précédemment. Et je vous ai parlé de Résultat. Et bien il y aura aussi un objet résultat qui va contenir les informations sur les demandes qu'on a effectuées avec SQL. Je résume :

- 1 objet de type Connection
- 1 objet de type Table
- 1 objet de type Result

Il nous suffit de 3 objets pour gérer notre base de données!

A partir de ce point, je vais vous expliquer l'ordre d'utilisation de ces objets:

- On crée tout d'abord un objet Connection et on lance la connexion avec la méthode .Open. Mais avant de lancer la connexion, nous devons pré-configurer des infos tels que le type, l'hôte et le nom. Le type sert à indiquer quelles BDD on utilise. L'hôte est comme j'ai dis plus haut, et en dernier vous indiquez le nom de votre base de données.
Pour l'exemple, je me suis positionné dans mon home/ , et j'ai nommé ma BDD "MaBase.sq3" . A noter que l'extension est purement optionnel et vous pouvez la changer si vous le souhaitez (comme uneBase.sql ou encore uneBase.sqlite ... bref c'est à votre convenance.)

En regardant le code, je présume que vous vous dîtes, mais comment ça se fait que je fais appel à .Open alors que je n'ai pas renseigné la propriété .Name. Et bien si vous l'indiquez pas, Gambas utilisera un nom de fichier temporaire qui se trouvera dans /tmp. En lancant .Open j'obtiendrais une connexion donc, mais pas avec le nom que je voulais.
C'est la raison pour laquelle je teste derrière si mon fichier de BDD existe dans mon home/ et si ce n'est pas le cas, et bien je le crée.

"Mais... tu peux pas faire ça avant l'instruction .Open justement? Et puis à quoi ça sert désormais s'il utilise un fichier temporaire?"

Bonne remarque, et tout arrive justement ici. Remarquez dans le code la méthode que j'utilise pour vérifier et créer mon fichier "MaBase.sq3". Ces dernières pour être utilisées doivent avoir une connexion. Donc j'ouvre une connexion temporairement afin de créer mon fichier "MaBase.sq3" et derrière je vais fermer la connexion, de sorte que je puisse relancer une connexion mais cette fois avec MON fichier en paramètre et non plus le temporaire. N'hésitez pas à relire lentement si ce passage vous obscure ;) .

Une fois ma connexion établie et mon fichier "MaBase.sq3" créé. Je vais désormais procéder un peu de la même manière. C'est-à-dire que je vais vérifier si ma table Personne existe, et le cas échéant elle fera partie de ma BDD. Dans la foulée, je n'oublie pas de créer mes champs en indiquant le type de chacun.
A noter ces deux instructions suivantes :

1
2
$table.PrimaryKey = ["id"]
$table.Update


La première définit la clé primaire.
La deuxième crée la Table.

Arrive ensuite le passage où je décide d'ajouter 30 entrées à ma Table. Et c'est là que l'objet Result rentre en jeu.

1
2
3
4
5
6
7
FOR i = 1 TO 30
$result = $connexion.Create("Personne")
$result!nom = tabNom[Int(Rnd(0, tabnom.Length))]
$result!prenom = tabPrenom[Int(Rnd(0, tabPrenom.Length))]
$result!age = Int(Rnd(1, 90))
$result.Update
NEXT


La méthode .Create me crée une entrée pour la Table Personne et me la renvoie dans notre objet Result (afin de la manipuler).
Alors pour chaque entrée j'affece un nom, un prénom et un age aléatoire (histoire de remplir notre Table tout de même :tongue: )
Et je valide mon entrée avec .Update.

Rien de bien méchant à comprendre si ce n'est peu-être la syntaxe avec le point d'interrogation qui peut se montrer surprenante de prime abord. C'est l'équivalent de :
1
$result["nom"] = "dupont"


Concernant ces 3 lignes, c'est un exemple pour l'ajout de 3 entrées dans la Table Personne pour ceux qui souhaitent savoir comment envoyer une requête SQL par Gambas.
1
2
3
db.Exec("INSERT INTO Personne VALUES(NULL,'bourse','jean-baptiste',32)")
db.Exec("INSERT INTO Personne VALUES(NULL,'jaures','jean',21)")
db.Exec("INSERT INTO Personne VALUES(NULL,'zola','emile',23)")

Pour récupérer les données, c'est en dessous :) .

Afficher les données



Pour afficher les données, j'ai décidé d'utiliser un GridView dans ce tutoriel.
Cela dit, je vous donnerai un code indépendant du GridView avec une belle boucle For Each.

Avant tout de chose, j'espère que vous êtes au point avec l'utilisation du GridView. Si ce n'est pas le cas, je vous recommande chaudement d'aller lire mon tutoriel à son sujet:
http://gambasforge.org/code-5-exemple-du-gridview.html

Tout se passe dans cette portion de code :

1
2
3
4
5
6
7
8
$tab = NEW STRING[$result.Count, 3]

FOR i = 0 TO $result.Count - 1
$tab[i, 0] = $result!nom
$tab[i, 1] = $result!prenom
$tab[i, 2] = $result!age
$result.MoveNext
NEXT


Explication:

- Nous créons un tableau à deux dimensions dont le nombre de lignes est égal au nombre d'entrées dans notre Table.
- Pour remplir ce tableau, on utilise une boucle For allant du début à la fin de notre Table. Remarquez ici le ' -1 '. En effet dans notre Table notre ID démarre à 1 et non à zéro comme nos tableaux en Gambas. Donc n'oubliez surtout pas de faire ce retrait sinon vous aurez une belle erreur précisant que vous êtes allés trop loin :lol!:
- Ensuite, comme vous pouvez le remarquer, on remplit notre tableau ligne par ligne!
- Pour remplir une nouvelle ligne à notre tableau, nous devons passer à la prochaine entrée de notre Table, grâce à la méthode .MoveNext

Et voilà, il ne reste plus qu'à fournir ce tableau à notre GridView qui va se charger d'afficher pour vous les données à la bonne place:

1
2
3
4
5
PUBLIC SUB GridView1_Data(Row AS INTEGER, Column AS INTEGER)

GridView1.Data.Text = $tab[row, Column]

END


Je vous ai dis en début de cette partie que je vous montrerai une autre façon d'afficher les résultats. La voici:

1
2
3
4
5
6
7
$result = db.Exec("SELECT * FROM Personne")

FOR EACH $result
PRINT $result!nom
PRINT $result!prenom
PRINT $result!age
NEXT


Très simple à comprendre. Pour chaque entrée on affiche ses données.

Les erreurs que vous pouvez rencontrer



Unable to locate database



Votre fichier de BDD est introuvable.
Vous avez mal renseigné les propriétés .Host et .Name de votre objet Connection.


Connection already opened



Vous avez déjà une connexion avec le serveur. Deux raisons possibles :
- Vous avez lancé une seconde fois la méthode .Open de votre objet Connection dans votre code sans fermer la première.
- Vous tentez d'accéder aux méthodes de votre objet Connection avant votre appel à la méthode .Open.

Le dernier cas de figure arrive généralement lorsque vous tentez par exemple de vérifier la présence de votre fichier BDD avant l'appel .Open afin de le créer.
Revoyez le code ci-dessous pour comprendre votre erreur.

Mes requêtes SQL à l'aide de DB.Exec() échouent!



Êtes-vous sur que votre BDD a bien créé vos tables? ;)
C'est une erreur fréquente lorsqu'on ne pense pas à vérifier la présence de tables dans le fichier BDD.
Revoyez le code ci-dessous pour comprendre votre erreur.

No current connection



Cette erreur peut arriver lors de l'utilisation de DB.Exec() .
Ca signifie que SQLite a détecté plusieurs connexions et vous devez sélectionner celle qui va exécuter la requête SQL.

Pour corriger le problème :

1
DB.Current = $connexion


Avant les appels à DB.Exec() .

Code source

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
' Gambas class file

PRIVATE $connexion AS Connection
PRIVATE $table AS Table
PRIVATE $result AS Result
PRIVATE $tab AS String[]

PUBLIC SUB _new()

DIM tabPrenom AS String[] = ["francois", "fabrice", "vincent", "jerome", "fabien", "adrien", "manu"]
DIM tabNom AS String[] = ["dupont", "torvalds", "stallman", "gates", "jobs", "gambas", "crevette"]
DIM i AS INTEGER = 0

$connexion = NEW Connection

WITH $connexion
.Type = "sqlite3"
.Host = User.Home
END WITH

TRY $connexion.Open
IF ERROR THEN Message.Error(Error.Text)

IF NOT $connexion.Databases.Exist("MaBase.sq3") THEN $connexion.Databases.Add("MaBase.sq3")

$connexion.Name = "MaBase.sq3"
$connexion.Close
TRY $connexion.Open
IF ERROR THEN Message.Error(Error.Text)

IF NOT $connexion.Tables.Exist("Personne") THEN
$table = $connexion.Tables.Add("Personne")
$table.Fields.Add("id", db.Serial)
$table.Fields.Add("nom", db.String)
$table.Fields.Add("prenom", db.String)
$table.Fields.Add("age", db.Integer)
$table.PrimaryKey = ["id"]
$table.Update
ENDIF

FOR i = 1 TO 30
$result = $connexion.Create("Personne")
$result!nom = tabNom[Int(Rnd(0, tabnom.Length))]
$result!prenom = tabPrenom[Int(Rnd(0, tabPrenom.Length))]
$result!age = Int(Rnd(1, 90))
$result.Update
NEXT

db.Exec("INSERT INTO Personne VALUES(NULL,'bourse','jean-baptiste',32)")
db.Exec("INSERT INTO Personne VALUES(NULL,'jaures','jean',21)")
db.Exec("INSERT INTO Personne VALUES(NULL,'zola','emile',23)")

$result = db.Exec("SELECT * FROM Personne")

GridView1.Columns.Count = 3
GridView1.Rows.Count = $result.Count
GridView1.Columns[0].Width = 150
GridView1.Columns[0].Title = "Nom"
GridView1.Columns[1].Width = 150
GridView1.Columns[1].Title = "Prénom"
GridView1.Columns[2].Width = 100
GridView1.Columns[2].Title = "Age"

$tab = NEW STRING[$result.Count, 3]

FOR i = 0 TO $result.Count - 1
$tab[i, 0] = $result!nom
$tab[i, 1] = $result!prenom
$tab[i, 2] = $result!age
$result.MoveNext
NEXT

ME.Caption = "Nombre d'entrées dans la BDD : " $result.Count

$connexion.Close

END

PUBLIC SUB GridView1_Data(Row AS INTEGER, Column AS INTEGER)

GridView1.Data.Text = $tab[row, Column]

END

Commentaires

Commentaire de linuxos, Le 5/3/2012 à 21:49:23
Merci pour ce tutoriel, je pense qu'il intéressera plein de personnes.

Bon boulot.

Olivier
Commentaire de manu, Le 6/3/2012 à 22:10:58
oui c'est intéressant.
Pour répondre à une question sur le Forum, j'avais fait ce petit tutos/exemple que j'avais mis sur le Wiki : http://gambasforge.org/wiki/exemplebdd
Commentaire de jeanyvon, Le 7/3/2012 à 07:32:18
Merci, Juste pour corser l'affaire rajoute un champ "date" je ne suis toujours pas arrivé à obtenir ce que je veux avec ce type de champ!
merci encore
Commentaire de manu, Le 7/3/2012 à 08:11:50
Pour les champs date, la réponse est dans ce Topic: http://gambasforge.org/sujet-33-resolu-requete-sur-champ-date-page-1.html#m1.
J'avais également un problème avec les dates dans les requetes, mais le pb ne viens pas de gambas, mais de SQL. Suivez le lien vers la mailing list, pour avoir l'échange avec Fabien et Benoit qui explique tout.
Commentaire de roudaille, Le 23/3/2012 à 13:54:40
Bonjour,

comment connaître le nom des variables créées (type Connexion et Result) lorsque l'on utilise le wizard "Nouvelle connexion" ?