<jupyter_start><jupyter_text>Le Modèle Relationnel **Utiliser la table des matières pour naviguer dans le document** Inventé dans les années 1970, le **modèle relationnel** propose une approche structurée au problème du «déferlement des **données**».En effet, de nombreux produits informatiques servent à gérer les **systèmes d'informations** d'entreprises: *commerce, banque, assurance, compagnies aérienne, établissement scolaire*, *service en ligne* (Amazone, Facebook, ...) etc.  Description rapide Dans les grandes lignes, ce modèle consiste à **décomposer** les données d'un système d'information en **tableaux** de «`n-uplets` nommés» (séquence de valeurs associées à des descripteurs), chaque `n-uplet` représentant un objet (ou **entité**) du système.Pour ces **tableaux**:- les descripteurs (ou **champs** ou **attributs**) correspondent à ses *colonnes*,- les objets (ou **entités**) correspondent à ses *lignes*. Ces tableaux sont souvent en **relation les uns avec les autres** par la présence de descripteurs ayant des valeurs *comparables*.  Système de gestion de base de données - SQL Une fois le modèle relationnel définit, on l'**implémente** en utilisant un *Système de Gestion de Base de Données Relationnelle* (*SGBDR*) ou, en anglais, un *Relational DataBase Management System* (*RDBMS*).Le plus souvent, il s'agit d'un **logiciel de type client-serveur** comme *postgresql* (celui que nous utiliserons), *mysql* (ou son fork *mariaDB*), *Oracle*, *SQL Server*, ... (voir ici pour [plus d'informations](https://emploi.developpez.com/actu/300458/Emploi-developpeur-2019-les-bases-de-donnees-les-plus-demandees-et-les-mieux-payees/)) Tous ces RDBMS s'appuient sur un langage normalisé nommé *Structured Query Language* abrégé en **SQL** (même si, *hélas*, ils définissent tous des sortes de dialectes de ce langage). Tout cela est plutôt abstrait ... alors regardons un cas particulier.  Exemple d'un club de «détente» Pour fixer les idées, prenons l'exemple d'un **club qui propose différentes activités**: tennis, squash, badminton, massage, ping pong, billards... Elle permet à ses membres de réserver (en ligne ou sur place) une activité gratuitement ou à un tarif préférentiel. elle propose aussi l'accès à ces mêmes activités à des personnes invités. L'activité du club doit faire l'objet d'un suivi de façon notamment à pouvoir calculer les coûts, les recettes etc. Autrement dit, il «lui» faut mettre en place un **système d'information**.  Modélisation des données Pour cela, on procède à une **modélisation des données** qui, dans le modèle relationnel, consiste à:  1 - Découvrir les objets (on parle aussi d'**entités**) du «domaine» ciblePour notre club, nous en retiendrons trois:- les **membres**,- les **activités**,- les **réservations**.  2 - Modéliser les objets On cherche des **descripteurs** *pertinents* par rapport à l'«application»; on parle aussi de **champs** \[*fields*\]:Par exemple, pour un membre du club, on peut (en première analyse) retenir les **champs**: > *prénom*, *nom*, *téléphone*, *date d'inscription*, ... Chaque membre peut alors être représenté par un *n-uplet* de valeurs, par exemple:       ('Henri', 'GILLET', '0806721361', '2015-03-04') L'ensemble des membres du club peut alors être représenté comme un ensemble de *n-uplets*:       membres = {           ('Henri', 'GILLET', '0806721361', '2015-03-04'),           ('Renée', 'GUERIN', '0146710764', '2016-08-10'),           ('Pauline', 'GOSSELIN', '0190856281', '2020-07-02'),           ...       } Dans le modèle relationnel, un tel ensemble est appelé une **relation** ou **table**.  3 - Découvrir les domaines de chaque champs. Comme ces **entités** devront être enregistrées sur un support réel, à chaque *champ* doit correspondre un **type** (on parle aussi de **domaine**). Pour notre exemple, les champs: - prénom - `prenom` - et `nom` peuvent être représentées par *une chaîne de caractère de* **taille variable**     - `VARCHAR(taille_max)`,- le numéro de téléphone - `telephone` - par *une chaîne de caractère de* **taille fixe**    - `CHAR(n)`,- et la date d'inscription - `date_entree` - par un type spécifique servant à représenter une date (année-mois-jour).    - `DATE`. Dans le modèle relationnel, la combinaison du *nom d'un champ* et de son *domaine* forme un **attribut** de l'entité modélisée. Pour exprimer tout cela de façon plus concise, on peut écrire (par exemple):       membres(           prenom      VARCHAR(50),           nom         VARCHAR(50),           telephone   CHAR(14),           date_entree DATE       )  4 - Découvrir les contraintes d'intégrités des données. L'objectif ici est de s'assurer de la *cohérence des données*.- *Exemple1 -* **clé primaire**: Chaque membre «effectif» du club doit-être **unique** dans la base de données (on parle de **contrainte d'entité**).  On pourrait, *par exemple*, imposer la contrainte que la combinaison `nom, prenom` soit unique dans la relation membres. Ainsi, un membre serait identifié de manière unique par cette combinaison.  > Un attribut ou une combinaison d'attributs qui permet d'**identifier** une entité d'une relation est appelé **clé primaire** de cette relation. Dans notre exemple, la combinaison `nom, prenom` pourrait-être une **clé primaire** de la relation `membres`. - *Exemple2 -* **contrainte de domaine**: le numéro de téléphone d'un membre ne doit contenir que des chiffres ou des blancs (pas de lettres...). Mais le type CHAR(14) ne le garantit pas; on parle dans ce cas de **contrainte de domaine**. - *Exemple3 -* **clé étrangère**: Pour modéliser une réservation, on pourrait retenir le schéma:     reservations(         prenom      VARCHAR(50),         nom         VARCHAR(50),         act_id      INT,          heure_debut TIMESTAMP,         ...     ) Par exemple, une entité de cette relation pourrait-être:         ('Pauline', 'GOSSELIN', 3, '2018-11-24T10:30:00') En supposant que **3** identifie l'activité «ping-pong», cela signifierait que: > Pauline a réservé une table de ping-pong le 24 novembre 2018 à 10h30. Pour s'assurer que notre base de données est cohérente il est indispensable que le couple '<NAME>' identifie une entité existante (et non «simplement possible») de la relation *membres* (Il y a un membre spécial pour les invités). Autrement dit, que le couple `prenom, nom` de la réservation fasse référence à une entité unique de la relation *membres*. > Un attribut ou une combinaison d'attributs qui *fait référence* à une entité unique d'une relation est appelé **clef étrangère**.  Schéma relationnel Après cette étape de modélisation des données, on obtient un **schéma relationnel**.Pour notre exemple, on pourrait obtenir le schéma (réalisé avec cet [outil en ligne](https://app.diagrams.net/)): ![schema_rel_club.png](attachment:df81736b-cb6a-4923-8a68-15ec229659ee.png) - Les champs qui jouent le rôle de **clés primaires** sont en *gras souligné*, - ceux qui jouent le rôle de **clés étrangères** sont en italiques et préfixés par ,- les flèches indiquent à quels champs ces clés étrangères font *référence*.  Ici, j'ai indiqué les types de chaque champ dans le but de vous habituer à leur désignation dans le langage SQL. *On ne fait pas ordinairement*. Notez - car c'est souvent ce qu'on fait en pratique - que chaque entité est identifiée uniquement par un entier (clé primaire) plutôt que par une combinaison de champs «significatifs» comme dans l'exemple plus haut. Notez encore que `NUMERIC` est un type de *valeur décimale exacte* contrairement au type `float` appelé `REAL` dans le contexte des bases de données et que `TIMESTAMP` consiste en la donnée d'une date et d'une heure (*horodatage*).  Exemples de données Voici à présent quelques entités pour ces relations: **activites**:<jupyter_code>act_id |         nom          | prix_membre | prix_invite | cout_initial | cout_maintenance_mensuel 
--------+----------------------+-------------+-------------+--------------+--------------------------
      0 | tennis 1             |           5 |          25 |        10000 |                      200
      1 | tennis 2             |           5 |          25 |         8000 |                      200
      2 | badminton            |           0 |        15.5 |         4000 |                       50
      3 | tennis de table      |           0 |           5 |          320 |                       10
      4 | massage 1            |          35 |          80 |         4000 |                     3000
      5 | massage 2            |          35 |          80 |         4000 |                     3000
      6 | squash               |         3.5 |        17.5 |         5000 |                       80
      7 | billard type snooker |           0 |           5 |          450 |                       15
      8 | billard simple       |           0 |           5 |          350 |                       15<jupyter_output><empty_output><jupyter_text>Observer l'alignement à gauche des données textuelles et l'alignement à droite des données numériques. **membres**:<jupyter_code>mbr_id |   prenom   |    nom     |           adresse           | code_postal | telephone  | recommende_par | date_entree 
--------+------------+------------+-----------------------------+-------------+------------+----------------+-------------
      0 | invité     | INVITÉ     | 1 rue de perlimpin          | 00000       | 0000000000 |                | 2010-01-08
      1 | Maurice    | HUET       | 9, avenue de Parent         | 94462       | 3458015685 |                | 2010-01-08
      2 | Cécile     | ROUSSET    | 30, chemin <NAME>    | 65782       | 0432555753 |              1 | 2010-01-15
      3 | Honoré     | ROCHE      | 18, chemin de Faure         | 30307       | O421200372 |                | 2010-02-04
      4 | Bernard    | DUPRE      | 13, rue Fischer             | 19396       | 0681058262 |              3 | 2010-02-07
      5 | Antoinette | JOURDAN    | 6, chemin de Faure          | 76483       | 0141316739 |                | 2010-02-14
      6 | Étienne    | FERNANDEZ  | rue de Buisson              | 78334       | 0132071819 |                | 2010-03-06
      7 | Dominique  | CARPENTIER | rue <NAME>          | 10228       | 0582790898 |                | 2010-03-21
      8 | Michelle   | PIRES      | 51, chemin <NAME> | 42676       | O192157300 |                | 2010-03-22
      9 | Constance  | BOUVIER    | 270, avenue Dupre           | 45979       | 0612776539 |                | 2010-03-24
  ...<jupyter_output><empty_output><jupyter_text>On voit par exemple que <NAME> (4) a été recommandé par Honoré ROCHE (2). **reservations**:<jupyter_code>reserv_id | act_id | mbr_id |     heure_debut     | nb_demi_heure 
-----------+--------+--------+---------------------+---------------
         0 |      0 |      0 | 2010-01-21 13:00:00 |             4
         1 |      0 |      0 | 2010-01-22 21:00:00 |             3
         2 |      2 |      0 | 2010-02-01 20:00:00 |             2
         3 |      0 |      1 | 2010-02-02 13:00:00 |             5
         4 |      8 |      1 | 2010-02-04 19:00:00 |             5
         5 |      3 |      0 | 2010-02-05 21:30:00 |             4
         6 |      3 |      3 | 2010-02-05 23:30:00 |             4
         7 |      7 |      2 | 2010-02-06 14:00:00 |             2
         8 |      0 |      0 | 2010-02-07 20:00:00 |             3
         9 |      8 |      1 | 2010-02-07 20:30:00 |             2
   ...<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1195955369595537, 'fraction_numerical': 0.0599721059972106, 'mean_word_length': 2.228193584693303, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 22, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 19, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '527156', 'license': 'CC0-1.0', 'n_tokens_mistral': 3930, 'n_tokens_neox': 3556, 'n_words': 1313, 'path': '3_bases_de_donnees/1_modele_relationnel.ipynb', 'repo_name': 'efloti/cours-nsi-terminale', 'size': '11514'}