Tdid-IPS-39-Python et SQLite

Procédure39 - Intégrer des requêtes SQL dans un programme python

Prérequis

Avoir suivi les procédures :

Sources de données : fichiers bases de données

Procédure
  1. Le fichier Base de données bdnotes.db

    Gestion de votre IDE

    Dans le dossier 0800, vous devez uploader le fichier bdnotes.db dans un dossier app/notes de votre espace pythonanywhere.

    Si vous travaillez avec Visual Studio Code, mettez le dans un dossier bdd de votre projet notes par exemple, ou dans un dossier bdd/notes si vous gérez plusieurs thématiques dans votre projet.

    Organisation des fichiers

    Pour simplifier, on peut mettre ici les modules (extension .py) et les fichiers ressources (csv, db, sql, etc ...) dans le même dossier, mais cette pratique n'est pas pérenne dans le temps.

  2. Interaction de Python et la base de données

    Exemple

    1
    # fonctions python pour travailler avec une base de données SQLite
    2
    import sqlite3 
    3
    4
    # l'objet db sera utilisé pour se connecter à la base de données
    5
    db = sqlite3.connect('bdnotes.db')
    6
    7
    # définir l'objet curseur mat qui permet de mémoriser les actions (requêtes) sur la base de données (objet db)
    8
    mat = db.cursor() #nommer ce curseur avec le nom mat est censé nous aider à affecter les actions sur la base qui concernent les matièrs
    9

    Ces 3 instructions permettent :

    • de préparer des requêtes SQL à faire exécuter à l'intérieur d'un programme python.
    • d'ouvrir la base de données (bdnotes.db) et de lui affecter un objet nommé db ici.
    • de disposer d'un objet (mat ici) pour travailler avec l'objet db sur la table matière et surtout récupérer les données.
  3. Afficher le contenu des tuples d'une requête 1 par 1

    Truc & astuceMéthode execute et fetchone

    • execute va permettre d'exécuter une requête SQL et de transmettre les données au curseur (ici mat).
    • fetchone va transférer le premier tuple à une liste nommée mat1.
    1
    # exécuter une requête simple
    2
    print("-------lecture séquentielle des tuples")
    3
    mat.execute("SELECT * FROM tbMat")
    4
    # lire la premier tuple
    5
    mat1 = mat.fetchone()
    6
    # lire le suivant
    7
    mat2 = mat.fetchone()
    8
    # lire le suivant
    9
    mat3 = mat.fetchone()
    10
    print(mat1,mat2,mat3)
  4. Utiliser une boucle while

    La solution précédente extrait les données en mémoire tuple par tuple, ce qui optimise la gestion de la mémoire vive dans le cas d'une requête contenant de nombreux attributs et tuples.

    On ne procède jamais ainsi pour lire les tuples d'une requête puisque par principe, on ne connaît pas le nombre de tuples à lire, sauf si on écrit une requête dont les conditions testées font que l'on est assuré qu'il y a un nombre fixe de tuples résultants.

    Lorsque l'on tente de lire un tuple qui n'existe pas, la fonction fetchone() retourne None.

    ExempleA tester à la suite du code de l'étape précédente

    1
    mat4 = mat.fetchone()
    2
    if (mat4 == None) :
    3
        print("Plus d'enregistrements")
    4
    else:
    5
        print (mat4)

    On va donc intégrer la méthode fetchone() dans une boucle while qui se poursuivra tant que le résultat est différent du mot-clé None.

    Exemple

    1
    # Utiliser une boucle while pour lire le contenu des tuples de la requête
    2
    print("-------lecture avec une boucle while")
    3
    mat.execute("SELECT * FROM tbMat")
    4
    while True:
    5
        tuple = mat.fetchone()
    6
        if (tuple == None):
    7
            print("Plus d'enregistrements")
    8
            break
    9
        else:
    10
            print (tuple)
  5. Utiliser l'itérateur pour parcourir les tuples

    Si le volume de données à extraire dans la requête n'est pas trop important, on a la possibilité de récupérer l'ingralités des tuples avec la méthode fetchall()

    L'itérateur avec sa boucle va permettre de ne pas être obligé de tester l'existence du tuple suivant à chaque itération et de sortir de la boucle while qui boucle de manière infinie.

    Le code à tester est présent ci-dessous

    Exemple

    1
    # Utiliser un itérateur pour lire le contenu des tuples de la requête
    2
    print("-------lecture avec une boucle --> formattage des données")
    3
    4
    mat.execute("SELECT * FROM tbMat")
    5
    tuples = mat.fetchall()
    6
    for row in tuples:
    7
        print('{0} : {1} - {2}'.format(tuple[0], tuple[1], tuple[2]))

    Ici, on en a profité pour extraire les valeurs du tuple et de formater l'affichage d'une manière un peu différente : ce qui revient à lire les colonnes de chaque ligne avec l'indice de la colonne. Vous noterez qu'on se rapproche un peu de la technique que l'on avait utilisé pour lire les fichiers CSV. La différence est qu'avec les fichiers CSV on peut construire le stockage des valeurs en fonction des traitements que l'on va faire ensuite : on pouvait donc construire des listes avec les valeurs de chaque ligne ou des listes avec les valeurs de chaque colonne ou encore des structures 2D.

    Avec SQL, le principe est systématiquement d'extraire des tuples (des lignes vu du tableur) qui vont alimenter une liste de valeurs pour chaque valeur de chaque attribut de la ligne.

    La puissance du langage SQL est de limiter très facilement les colonnes à afficher ainsi que de filtrer les tuples de la requête en construisant des conditions adaptées à ce que l'on veut extraire non pas d'une seule table (ou d'un seul fichier tableur csv), mais de données avec plusieurs tables.

    Une autre version

    1
    # Utiliser un autre curseur pour lire le contenu des tuples de la table tbEt
    2
    print("-------affichage des étudiants -> tuples sous forme de liste")
    3
    4
    etu.execute("SELECT * FROM tbEt")
    5
    6
    for tuple_et in etu:
    7
        print(tuple_et)

    Avec with (code complet à tester de manière indépendante)

    1
    import sqlite3
    2
    3
    # Établir une connexion à la base de données SQLite
    4
    with sqlite3.connect('chemin/vers/la/base_de_donnees.db') as conn:
    5
        # Créer un curseur pour exécuter des requêtes
    6
        mat = conn.cursor()
    7
        
    8
        print("-------lecture avec une boucle --> formattage des données")
    9
        
    10
        # Exécuter la requête SQL
    11
        for row in mat.execute("SELECT * FROM tbMat"):
    12
            # Afficher les données avec le format spécifié
    13
            print('{0} : {1} - {2}'.format(row[0], row[1], row[2]))
    14
    15
        # Le curseur sera fermé automatiquement à la sortie du bloc with
    16
        # La connexion sera également fermée automatiquement