Sqlite database model

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Sqlite database model

Message par microdevweb »

Bonjour à tous,

Pour un projet perso je me suis fais un petit model de données assez simple d'utilisation.
  • Etape créer la base de donnée Ex: myDb.DB_MODEL::DB = DB_MODEL::newDb("Data","myDb.db")
  • Après cela vous pouvez envoyé une requête update, la base sera ouverte et fermée automatiquement
  • Ou envoyé une requête query,on utilise après cela Ex: myQuery\nextRecord() et puis Ex: myQuery\getString(0)
Télécharger le zip depuis github ICI

Comprenez bien que l'intérêt d'un tel module est de pouvoir par après l'utiliser dans toutes application qui doit utilisé Sqlite et on peut même si le besoins en est créer plusieurs bases avec le même module.

Zip content :
  • DB_Model.pbi
  • Main.pbi
  • README.md
  • Classes
    • DB.pbi
    • Operation.pbi
    • Query.pbi
    • Update.pbi
Voici un code exemple (contenu dans le zip)

Code : Tout sélectionner

XIncludeFile "DB_MODEL.pbi"
myDb.DB_MODEL::DB = DB_MODEL::newDb("Data","myDb.db")
Define req.s
If Not myDb\fileExists()
  myDb\create()
  ; Create countries table
   req = "CREATE TABLE IF NOT EXISTS countries("+
                 "id INTEGER PRIMARY KEY AUTOINCREMENT,"+
                 "name TEXT)"
  If Not myDb\update(req)
    End
  EndIf
  ; Create cities table
  Define req.s = "CREATE TABLE IF NOT EXISTS cities("+
                 "id INTEGER PRIMARY KEY AUTOINCREMENT,"+
                 "name TEXT,"+
                 "postalCode,"+
                 "id_country INTEGER)"
  If Not myDb\update(req)
    End
  EndIf
  ; Create contacts table
  Define req.s = "CREATE TABLE IF NOT EXISTS contacts("+
                 "id INTEGER PRIMARY KEY AUTOINCREMENT,"+
                 "name TEXT,"+
                 "surName TEXT,"+
                 "address TEXT,"+
                 "id_city INTEGER)"
  If Not myDb\update(req)
    End
  EndIf
  ; we add some countries for testing
  req = "INSERT INTO countries ("+
        "name) VALUES ('Belgique')"
  If Not myDb\update(req)
    End
  EndIf 
  req = "INSERT INTO countries ("+
        "name) VALUES ('France')"
  If Not myDb\update(req)
    End
  EndIf
  req = "INSERT INTO countries ("+
        "name) VALUES ('Espagne')"
  If Not myDb\update(req)
    End
  EndIf
  ; we add some cities for testing
  req = "INSERT INTO cities ("+
        "name,"+
        "postalCode,"+
        "id_country"+
        ") VALUES ("+
        "'Waremme',"+
        "'4300',"+
        "1"+
        ")"
  If Not myDb\update(req)
    End
  EndIf
  req = "INSERT INTO cities ("+
        "name,"+
        "postalCode,"+
        "id_country"+
        ") VALUES ("+
        "'Trooz',"+
        "'4870',"+
        "1"+
        ")" 
  If Not myDb\update(req)
    End
  EndIf 
  req = "INSERT INTO cities ("+
        "name,"+
        "postalCode,"+
        "id_country"+
        ") VALUES ("+
        "'Liège',"+
        "'4000',"+
        "1"+
        ")" 
  If Not myDb\update(req)
    End
  EndIf 
  req = "INSERT INTO cities ("+
        "name,"+
        "postalCode,"+
        "id_country"+
        ") VALUES ("+
        "'Paris',"+
        "'75000',"+
        "2"+
        ")" 
  If Not myDb\update(req)
    End
  EndIf 
  req = "INSERT INTO cities ("+
        "name,"+
        "postalCode,"+
        "id_country"+
        ") VALUES ("+
        "'Reims',"+
        "'69000',"+
        "2"+
        ")" 
  If Not myDb\update(req)
    End
  EndIf 
  ; we add some contacts for testing
  req = "INSERT INTO contacts ("+
        "name,"+
        "surName,"+
        "address,"+
        "id_city"+
        ") VALUES ("+
        "'Dupond',"+
        "'Gérard',"+
        "'Rue du Globe, 21',"+
        "1"+
        ")"
  If Not myDb\update(req)
    End
  EndIf
  req = "INSERT INTO contacts ("+
        "name,"+
        "surName,"+
        "address,"+
        "id_city"+
        ") VALUES ("+
        "'Gaumont',"+
        "'ALain',"+
        "'Rue du Palais, 11',"+
        "2"+
        ")"
  If Not myDb\update(req)
    End
  EndIf
  req = "INSERT INTO contacts ("+
        "name,"+
        "surName,"+
        "address,"+
        "id_city"+
        ") VALUES ("+
        "'Dudule',"+
        "'Marcel',"+
        "'Rue de la tarte, 2',"+
        "3"+
        ")"
  If Not myDb\update(req)
    End
  EndIf
  req = "INSERT INTO contacts ("+
        "name,"+
        "surName,"+
        "address,"+
        "id_city"+
        ") VALUES ("+
        "'Pureabasic',"+
        "'Langage',"+
        "'Rue du développement 4,',"+
        "4"+
        ")"
  If Not myDb\update(req)
    End
  EndIf
EndIf
; try to select
Define req.s = "SELECT a.name,b.name,c.name"+
               " FROM contacts AS a,countries AS b,cities AS c"+
               " WHERE c.id = a.id_city AND "+
               " b.id = c.id_country"
myQuery.DB_MODEL::Query = myDb\newQuery(req)
; display to result
If myQuery
  While myQuery\nextRecord()
    Debug myQuery\getString(0)
    Debug myQuery\getString(1)
    Debug myQuery\getString(2)
  Wend 
EndIf
; free object and close database
myQuery\free()
Remarque : vous pouvez normalement effectué plusieurs query même imbriqué et même des update (car une nouvelle instance de la bd sera chaque fois ouverte)

:mrgreen: Ha oui c'est full object, je suis trop vieux que pour changé
Dernière modification par microdevweb le lun. 27/août/2018 17:41, modifié 1 fois.
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Sqlite database model

Message par Kwai chang caine »

Merci du partage 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Sqlite database model

Message par microdevweb »

Voici un exemple plus concret d'utilisation, je ne l'ai réaliser qu'avec une seul table mais il est évident que vous pouvez faire cela avec toutes les tables que vous désirer.

Note : dans mon répertoire racine de travail j'ai créer un répertoire "Models"

Module countries

Code : Tout sélectionner

; ******************************************************************************
; AUTHOR          : MicrodevWeb
; PROJECT NAME    : Sample of model
; PROJECT VERSION : 1.0
; PEOJECT DATE    : 2018/08/27
; MODULE NAME     : countries
; MODULE VERSION  : 1.0
; MODULE DATE     : 2018/08/27
; ******************************************************************************
DeclareModule Countries
  Global Db.DB_MODEL::DB
  
  Declare create()
  Declare load(id = 0)
  Declare nextRecord()
  Declare.s getName()
  Declare getId()
  Declare getLastId()
  Declare add(name.s)
  Declare update(id,name.s)
  Declare delete(id)
EndDeclareModule
Module Countries
  EnableExplicit
  Enumeration 
    #cl_id
    #cl_name
  EndEnumeration
  Global query.DB_MODEL::Query
  Procedure create()
    Protected req.s = "CREATE TABLE IF NOT EXISTS countries ("+
                      "id INTEGER PRIMARY KEY AUTOINCREMENT,"+
                      "name TEXT)"
    If Not DB\update(req)
      MessageRequester("FATAL ERROR","Cannot create countries table",#PB_MessageRequester_Error)
      End
    EndIf
  EndProcedure
  
  Procedure load(id = 0)
    Protected req.s = "SELECT * FROM countries"
    If id
      req + " WHERE id = "+id
    EndIf
    ; we finish the query if it's be definished before
    If query
      query\free()
    EndIf
    query = DB\newQuery(req)
  EndProcedure
  
  Procedure nextRecord()
    ProcedureReturn query\nextRecord()
  EndProcedure
  
  Procedure.s getName()
    ProcedureReturn query\getString(#cl_name)
  EndProcedure
  
  Procedure getId()
    ProcedureReturn query\getLong(#cl_id)
  EndProcedure
  
  Procedure getLastId()
    Protected req.s = "SELECT id FROM countries ORDER BY id desc"
    Protected q.DB_MODEL::Query,returnedValue = 0
    q = DB\newQuery(req)
    If q
      If q\nextRecord()
        returnedValue = q\getLong(0)
      EndIf
    EndIf
    q\free()
    ProcedureReturn returnedValue
  EndProcedure
  
  Procedure add(name.s)
    Protected req.s = "INSERT INTO countries (name) VALUES ('"+name+"')"
    DB\update(req)
    ; we return the last id
    ProcedureReturn getLastId()
  EndProcedure
  
  Procedure update(id,name.s)
    Protected req.s = "UPDATE  countries SET name = '"+name+"'"+
                      " WHERE id = "+id
    DB\update(req)
  EndProcedure
  
  Procedure delete(id)
    Protected req.s = "DELETE FROM countries WHERE id = "+id
    DB\update(req)
  EndProcedure
EndModule
Main

Code : Tout sélectionner

; ******************************************************************************
; AUTHOR          : MicrodevWeb
; PROJECT NAME    : Sample of model
; PROJECT VERSION : 1.0
; PEOJECT DATE    : 2018/08/27
; ******************************************************************************
IncludePath "Models\"
XIncludeFile "DB_MODEL.pbi"
XIncludeFile "Countries.pbi"

Global myDb.DB_MODEL::DB = DB_MODEL::newDb("Data","dbTest.db")
; set db model to Countries module
Countries::Db = myDb
Procedure displayCountries()
  Countries::load()
  While Countries::nextRecord()
    Debug Countries::getName()
  Wend
EndProcedure
; create database and some records if it's not exists
If Not myDb\fileExists()
  myDb\create()
  Countries::create()
  Countries::add("Belqique")
  Countries::add("France")
  Countries::add("Italie")
  Countries::add("Espagne")
  Countries::add("Allemagne")
EndIf
Debug "DEBUG : STARTING CONTENT"
displayCountries()

; Test add
Countries::add("Suisse")
Debug "DEBUG : ADD"
displayCountries()

; Test udpate
Countries::update(2,"France DEBUG")
Debug "DEBUG : UPDATE"
displayCountries()

; Test delete
Countries::delete(3)
Debug "DEBUG : DELETE"
displayCountries()

; Test selective load
Debug "DEBUG : LOAD WITH SELECT"
Countries::load(2) ; FRANCE
If Countries::nextRecord()
  Debug Countries::getName()
EndIf
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
kwandjeen
Messages : 204
Inscription : dim. 16/juil./2006 21:44

Re: Sqlite database model

Message par kwandjeen »

J'avais fait un logiciel pour le boulot avec des bases SQL mais nous avons changé de système car la lib SQL de PB rame un max au boulot.
Vous avez constater le même soucis ?
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Sqlite database model

Message par microdevweb »

Non je n'ai jamais vraiment eu se type de problème, sauf une fois un client qui à eu la base corrompue et irrécupérable. Heureusement que le logiciel avais un système de sauvegarde.
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
kwandjeen
Messages : 204
Inscription : dim. 16/juil./2006 21:44

Re: Sqlite database model

Message par kwandjeen »

microdevweb a écrit :Non je n'ai jamais vraiment eu se type de problème, sauf une fois un client qui à eu la base corrompue et irrécupérable. Heureusement que le logiciel avais un système de sauvegarde.
Même soucis. Des temps d'accès très long et de temps en temps base corrompue donc j'ai arrêté d'utiliser la lib SQL pour des grosses bases et une utilisation réseau.
Avatar de l’utilisateur
falsam
Messages : 7244
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sqlite database model

Message par falsam »

@kwandjeen : Tu évoques des soucis avec des bases de données SQL Server. Microdevweb a donné un code exploitant une base de données SQLite. On est un peu dans le HS:wink:

Toutefois j'attire l'attention sur le fait les codes donnés par Microdevweb ne sont pas 100% fiables quand on saisi des données avec des apostrophes ou des guillements.
Configuration : Windows 11 Famille 64-bit - PB 6.03 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Sqlite database model

Message par microdevweb »

falsam a écrit ::
Toutefois j'attire l'attention sur le fait les codes donnés par Microdevweb ne sont pas 100% fiables quand on saisi des données avec des apostrophes ou des guillements.
Ce problème devra être gérer dans vos propres modules comme ceci

Exemple :

Code : Tout sélectionner

Procedure add(name.s)
    name = ReplaceString(name,"'","''") ; ICI
    Protected req.s = "INSERT INTO countries (name) VALUES ('"+name+"')"
    DB\update(req)
    ; we return the last id
    ProcedureReturn getLastId()
  EndProcedure
Vous devrez effectué cette opération pour tous le champs de type string

Code du module countries modfié

Code : Tout sélectionner

; ******************************************************************************
; AUTHOR          : MicrodevWeb
; PROJECT NAME    : Sample of model
; PROJECT VERSION : 1.0
; PEOJECT DATE    : 2018/08/27
; MODULE NAME     : countries
; MODULE VERSION  : 1.0
; MODULE DATE     : 2018/08/27
; ******************************************************************************
DeclareModule Countries
  Global Db.DB_MODEL::DB
  
  Declare create()
  Declare load(id = 0)
  Declare nextRecord()
  Declare.s getName()
  Declare getId()
  Declare getLastId()
  Declare add(name.s)
  Declare update(id,name.s)
  Declare delete(id)
EndDeclareModule
Module Countries
  EnableExplicit
  Enumeration 
    #cl_id
    #cl_name
  EndEnumeration
  Global query.DB_MODEL::Query
  Procedure create()
    Protected req.s = "CREATE TABLE IF NOT EXISTS countries ("+
                      "id INTEGER PRIMARY KEY AUTOINCREMENT,"+
                      "name TEXT)"
    If Not DB\update(req)
      MessageRequester("FATAL ERROR","Cannot create countries table",#PB_MessageRequester_Error)
      End
    EndIf
  EndProcedure
  
  Procedure load(id = 0)
    Protected req.s = "SELECT * FROM countries"
    If id
      req + " WHERE id = "+id
    EndIf
    ; we finish the query if it's be definished before
    If query
      query\free()
    EndIf
    query = DB\newQuery(req)
  EndProcedure
  
  Procedure nextRecord()
    ProcedureReturn query\nextRecord()
  EndProcedure
  
  Procedure.s getName()
    ProcedureReturn query\getString(#cl_name)
  EndProcedure
  
  Procedure getId()
    ProcedureReturn query\getLong(#cl_id)
  EndProcedure
  
  Procedure getLastId()
    Protected req.s = "SELECT id FROM countries ORDER BY id desc"
    Protected q.DB_MODEL::Query,returnedValue = 0
    q = DB\newQuery(req)
    If q
      If q\nextRecord()
        returnedValue = q\getLong(0)
      EndIf
    EndIf
    q\free()
    ProcedureReturn returnedValue
  EndProcedure
  
  Procedure add(name.s)
    name = ReplaceString(name,"'","''")
    Protected req.s = "INSERT INTO countries (name) VALUES ('"+name+"')"
    DB\update(req)
    ; we return the last id
    ProcedureReturn getLastId()
  EndProcedure
  
  Procedure update(id,name.s)
    name = ReplaceString(name,"'","''")
    Protected req.s = "UPDATE  countries SET name = '"+name+"'"+
                      " WHERE id = "+id
    DB\update(req)
  EndProcedure
  
  Procedure delete(id)
    Protected req.s = "DELETE FROM countries WHERE id = "+id
    DB\update(req)
  EndProcedure
EndModule
Code main avec test de cette modification

Code : Tout sélectionner

; ******************************************************************************
; AUTHOR          : MicrodevWeb
; PROJECT NAME    : Sample of model
; PROJECT VERSION : 1.0
; PEOJECT DATE    : 2018/08/27
; ******************************************************************************
IncludePath "Models\"
XIncludeFile "DB_MODEL.pbi"
XIncludeFile "Countries.pbi"

Global myDb.DB_MODEL::DB = DB_MODEL::newDb("Data","dbTest.db")
; set db model to Countries module
Countries::Db = myDb
Procedure displayCountries()
  Countries::load()
  While Countries::nextRecord()
    Debug Countries::getName()
  Wend
EndProcedure
; create database and some records if it's not exists
If Not myDb\fileExists()
  myDb\create()
  Countries::create()
  Countries::add("Belqique")
  Countries::add("France")
  Countries::add("Italie")
  Countries::add("Espagne")
  Countries::add("Allemagne")
EndIf
Debug "DEBUG : STARTING CONTENT"
displayCountries()

Test add
Countries::add("Suisse")
displayCountries()

; Test udpate
Countries::update(2,"France DEBUG")
Debug "DEBUG : UPDATE"
displayCountries()

; Test delete
Countries::delete(3)
Debug "DEBUG : DELETE"
displayCountries()

; Test selective load
Debug "DEBUG : LOAD WITH SELECT"
Countries::load(2) ; FRANCE
If Countries::nextRecord()
  Debug Countries::getName()
EndIf
Countries::add("L'Algérie")
displayCountries()

Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Marc56
Messages : 2147
Inscription : sam. 08/févr./2014 15:19

Re: Sqlite database model

Message par Marc56 »

Toutefois j'attire l'attention sur le fait les codes donnés par Microdevweb ne sont pas 100% fiables quand on saisi des données avec des apostrophes ou des guillements.
Ce problème devra être gérer dans vos propres modules comme ceci
Ce que falsam essaye de suggérer c'est que ce "problème" (guillemets, apostrophes) peut-être réglé directement et très simplement avec la technique des "variable de liaison" :arrow: SetDataBaseString()
C'est la méthode moderne et on évite en plus l'injection de code.
Tuto du même auteur: https://www.purebasic.fr/french/viewtop ... =6&t=16597

PS.
  1. Cette technique utilise une syntaxe différente pour les bases SQLite (?) et PostgreSQL ($1)
  2. SetDataBaseString traite tout le contenu comme une chaine et n'interprète pas son contenu (c'est le but) on ne peut donc pas y mettre une commande SQL (ex: IN() voir discussion récente sur le forum us et réponse de Freak)
  3. SQLite et PostgreSQL sont rapides en PB car elles sont en accès direct et ne nécessitent pas un pilote ODBC qui est un technique lente et peu fiable, mais nécessaire pour toutes les autres bases (ex: SQL Server, Oracle etc). (C'est valable pour tous les langages de programmation: accès par ODBC = lent)
:wink:
Avatar de l’utilisateur
microdevweb
Messages : 1800
Inscription : mer. 29/juin/2011 14:11
Localisation : Belgique

Re: Sqlite database model

Message par microdevweb »

Comme quoi on en apprend tous les jours, je ne connaissais pas cette commande.
Windows 10 64 bits PB: 5.70 ; 5.72 LST
Work at Centre Spatial de Liège
Répondre