Fichier de rejeu Close

Indication Close

A propos de... Close

Commentaire Close

Systèmes d'Information

  • Notions mathématiques
  • Calcul relationnel
  • Algèbre relationnelle
  • Langage de requêtes
  • Arbre de requêtes
  • Exercices
  • Introduction
  • Commandes de bases
  • Langage de définition de données (LDD)
  • Langage de manipulation de données (LMD)
  • Types de données
  • Exercice
    • Modèle de données
    • Arbres de requêtes
    • Requêtes SQL
  • Présentation
  • Calcul relationnel
  • Algèbre relationnelle
  • Division relationnelle
  • Relation
  • Fonction
  • Application
  • Injection
  • Surjection
  • Bijection
  • Association
  • Exemples
  • Dépendances fonctionnelles
  • Décomposition de relations
  • Inférence logique
  • Normalisation
  • Aux pays des bières
  • Modélisation
  • Exercices
  • Liste des projets
  • Aux pays des bières
    • Modèle de données
    • Arbres de requêtes
    • Requêtes SQL
  • Au Tournoi des six nations
  • Salles de concerts
  • Généralités
  • Langage SQL
  • Modèle relationnel
  • Généralités
  • SQL
  • Algèbre relationnelle
  • Synthèse
Index

Archives

  • Site Web
  • Sources reStructuredText
  • EniBook 1.618033988
logo

Crédits

© Your Copyright

Aide

En-tête

MenuContenu
Sommaire,
Téléchargements
Aide sur les outils

Pied de page

ChevronAction
Aller en haut de la page courante
Aller en bas de la page courante
Passer à la page précédente
Passer à la page suivante

Aux pays des bières

On propose dans cet exercice de travailler sur une base de données en formulant la recherche d’information :
  • sous forme d’arbre de requêtes
  • en langage SQL

à partir de questions exprimées en langage naturel (français).

Le modèle de données sur lequel on travaillera représentera très schématiquement :

  • les bars qui servent des bières

Cette phrase (sujet-verbe-complément) permet d’identifier deux entités (bars,bières) reliées par un verbe représentant une association entre ces deux entités.

Nous verrons plus en détail dans le chapitre « Modélisation » ces notions d’Entité-Association très utiles pour proposer une structuration de bases de données.

Modèle de données

En partant de cette simple phrase représentant le « monde » à modéliser :

  • les bars qui servent des bières

On peut émettre les hypothèses suivantes :

  • un bar peut servir plusieurs bières
  • une bière peut-être servie dans plusieurs bars

Ces hypothèses signifient que l’on a à faire à une association plusieurs à plusieurs entre les deux entités (bars,bières).

Cette situation nécessite de « réifier » le verbe (le transformer en une entité) afin de transformer l’association plusieurs à plusieurs en deux associations un à plusieurs.

On peut donc se baser sur le modèle de données :

  • un bar propose plusieurs services
  • une bière peut être proposée dans plusieurs services

qui fait apparaître l’entité services (sujet-verbe-complément)

On peut également conjuguer différemment les phrases :

  • chaque service est proposé dans un bar
  • chaque service concerne une bière

A partir de ces phrases on peut représenter ce modèle de données en utilisant le formalisme UML :

Modèle de données en UML

_images/bars_UML.png

A partir de ce modèle de données on peut créer les tables qui correspondent aux entités de ce modèle.

Création des tables

Représentation, en SQL, du modèle de données à étudier.

A partir du modèle de données UML on peut structurer la base de données en trois tables :

  • bars(bar_id,bar,pays,continent)
  • services(bar_id,bar,biere_id,stock)
  • bieres(biere_id,biere,couleur,origine)

où les associations sont mises en oeuvre par des clés étrangères qui apparaissent sur les entités de cardinalité supérieure à 1 (du côté plusieurs de l’association).

CREATE TABLE bars (
                   bar_id INTEGER NOT NULL PRIMARY KEY,
--                   bar_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
                   bar        TEXT,
                   pays       TEXT,
                   continent TEXT
);

CREATE TABLE bieres (
                     biere_id INTEGER NOT NULL PRIMARY KEY,
--                     biere_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
                     biere      TEXT,
                     couleur    TEXT,
                     origine    TEXT
);

CREATE TABLE services  (
                        bar_id   INTEGER NOT NULL,
                        biere_id INTEGER NOT NULL,
                        stock    SMALLINT,
                        PRIMARY KEY (bar_id,biere_id),
                        FOREIGN KEY (bar_id)   REFERENCES bars(bar_id)   ON DELETE CASCADE,
                        FOREIGN KEY (biere_id) REFERENCES bieres(biere_id) ON DELETE CASCADE
);

On pourra vérifier l’état de la base de données en formulant les requêtes pour retrouver toutes les informations des trois tables :

sql : bars.sql

    
>
Output

                

Interpréteur

MenuAction
Ré-initialiser les sorties
Faire apparaître le menu d'aide
Interpréter le programme

Editeur

MenuRaccouciAction
Ctrl+N Initialiser l'éditeur
Ctrl+O Charger le contenu d'un fichier dans l'éditeur
Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
Ctrl+P Imprimer le contenu de l'éditeur
Ctrl+Z Annuler la dernière modification
Maj+Ctrl+Z Rétablir la modification précedente
Ctrl+F Chercher une expression dans l'éditeur
Maj+Ctrl+F Chercher et remplacer une expression par une autre
F10 Ouvrir une documentation du langage

RaccourciAction
F1 Afficher cette aide
Tab Indenter la sélection
Maj+Tab Désindenter la sélection
Ctrl+A Sélectionner le contenu de l'éditeur
Ctrl+C Copier la sélection dans le presse-papier
Ctrl+V Remplacer la sélection par le contenu du presse-papier
Ctrl+X Supprimer la sélection et la copier dans le presse-papier
Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur

Arbres de requêtes

L’objectif de ces exercices est de savoir représenter sous forme d’arbre de requêtes, la recherche d’informations à partir :

  • d’une seule table (projection et restriction)
  • de plusieurs tables (jointures)
  • des opérations ensemblistes (union,intersection,différence)
  • de formulation de division relationnelle
  • des fonctions d’agrégats
  • des regroupements dans un ensemble avec restriction sur les groupements
6/6 Requêtes sur une table

Savoir formuler, sous forme d’arbre, une requête sur une table en appliquant des :

  1. Vérification du contenu des tables de la base de données
    • Question
    • Solution

    Construire les arbres de requêtes répondant aux questions :

    • \(Q_1\) : « quel est le contenu de la table bars
    • \(Q_2\) : « quel est le contenu de la table services
    • \(Q_3\) : « quel est le contenu de la table bieres
    Votre réponse :
    Arbre de requêtes : graph6.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Récupérer les éléments (b) de l’ensemble (bars) : \(\displaystyle Q_1 = bars(b)\)

    Récupérer les éléments (s) de l’ensemble (services) : \(\displaystyle Q_2 = services(s)\)

    Récupérer les éléments (b) de l’ensemble (bieres) : \(\displaystyle Q_3 = bieres(b)\)

    _images/bars-0-123.png
  2. Projection
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom et la couleur des bières ».
    Votre réponse :
    Arbre de requêtes : graph10.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \Pi_{(biere,couleur)}(bieres)\)

    On applique une projection (\(\Pi\)) sur les colonnes (biere,couleur) de la table bieres.

    Arbre de requêtes :

    _images/bars-1.png
  3. Restriction
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher les bières d’origine française ».
    Votre réponse :
    Arbre de requêtes : graph14.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \sigma_{[origine = 'France']}(bieres)\)

    On applique une restriction (\(\sigma\)) avec la condition [origine = 'France'] sur la table bieres.

    Arbre de requêtes :

    _images/bars-2.png
  4. Projection et restriction
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bières françaises ».
    Votre réponse :
    Arbre de requêtes : graph18.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \Pi_{(biere)}(\sigma_{[origine='France']}(bieres))\)

    On applique une projection (\(\Pi\)) sur la colonne biere et une restriction (\(\sigma\)) sur la condition [origine='France'] de la table bieres.

    Arbre de requêtes :

    _images/bars-3.png
  5. Connecteur logique
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher les bières blondes françaises ».
    Votre réponse :
    Arbre de requêtes : graph22.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \sigma_{[origine='France' \land couleur='Blonde']}(bieres)\).

    On vérifie (\(\sigma\)) que les bières sont d’origine française (origine='France') et (\(\land\)) qu’elles sont de couleur blonde (couleur='Blonde')

    Arbre de requêtes :

    _images/bars-4.png
  6. Connecteurs logiques
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom et la couleur des bières françaises blondes et les bières brunes ».
    Votre réponse :
    Arbre de requêtes : graph26.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \sigma_{[origine='France' \land couleur='Blonde' \lor couleur='Brune']}(bieres)\)

    On vérifie (\(\sigma\)) sur la table bieres qu’elles sont d’origine française et (\(\land\) : et logique) de couleur blonde ou (\(\lor\): ou logique) que la couleur des bières est brune.

    Arbre de requêtes :

    _images/bars-5.png

    Attention à la priorité du connecteur logique \(\land\) sur le \(\lor\) (de même que la multiplication l’est sur l’addition).

    La requête :
    • \(Q_1 = \sigma_{[origine='France' \lor couleur='Blonde' \land couleur='Brune']}(bieres)\)

    donnerai comme résultat … les bières françaises (il ne peut exister des bières blonde et brune à la fois).

    Remarque : on peut modifier la priorité en parenthésant des parties de la restriction :
    • \(Q_1 = \sigma_{[origine='France' \land (couleur='Blonde' \lor couleur='Brune')]}(bieres)\)

    donnera comme résultat les bières françaises et les bières de couleur blonde ou brune.

2/2 Requêtes sur plusieurs tables

Savoir représenter, sous forme d’arbre, une requête sur plusieurs tables de la base de données « Aux pays des bières ».

  1. Produit cartésien et restriction
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher les bars qui servent de la bière ».
    Votre réponse :
    Arbre de requêtes : graph31.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ_1 = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(IJ_2 = \Join_{[IJ_1.biere\_id=bieres.biere\_id]}(IJ_1,bieres)\)
    • \(Q_1 = IJ_2\)

    On réalise ici deux jointures (\(\Join\)) entre les tables bars,services puis une jointure entre le résultat obtenu (\(IJ_1\)) et la table bieres.

    L’ordre d’éxecution des jointures (\(IJ_1\) avant ou après \(IJ_2\)) dépendra de l’état de la base de données (nombre d’enregistrements dans les tables, utilisation d’index sur colonnes …) et sera déterminé par l’optimiseur de requêtes du SGBD Relationnel utilisé.

    Remarque :

    une jointure est une combinaison de produit cartésien et de restriction, on peut les représenter à l’aide de ces opérateurs :

    • \(IJ_1 = \sigma_{[bars.bar\_id=services.bar\_id]}(\times(bars,services))\)
    • \(IJ_2 = \sigma_{[IJ_1.biere\_id=bieres.biere\_id]}(\times(IJ_1,bieres))\)

    Arbre de requêtes :

    _images/bars-6.png

    Le lecteur pourra vérifier qu’on obtient le même résultat en modifiant l’ordre d’éxecution des jointures dans l’arbre de requêtes.

  2. Création de vue
    • Question
    • Solution

    Construire un arbre de requêtes pour créer une vue barsdumonde sur les informations “métier” (sans les clés bar_id,biere_id) des « bars qui servent de la bière ».

    Votre réponse :
    Arbre de requêtes : graph35.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ_1 = \Join_{[bars.bar_id=services.bar_id]}(bars,services)\)
    • \(IJ_2 = \Join_{[NJ_1.biere_id=bieres.biere_id]}(IJ_1,bieres)\)
    • \(P = \Pi_{(bar,pays,stock,biere,couleur,origine)}(IJ_2)\)
    • \(barsdumonde=P\)

    Arbre de requêtes :

    _images/bars-7.png
3/3 Opérations ensemblistes

Savoir formuler, sous forme d’arbre, des opérations ensemblistes (\(\cup,\cap,\setminus\)) sur le modèle de données « Aux pays des bières ».

  1. Union
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « récupérer les noms des pays ou se trouvent des bars et ceux des origines de fabrication des bières ».
    Votre réponse :
    Arbre de requêtes : graph40.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(pays)}(bars)\)
    • \(P_2 = \Pi_{(origine)}(bieres)\)
    • \(U_1 = \cup(P_1,P_2)\)
    • \(Q_1 = U_1\)

    Arbre de requêtes :

    _images/bars-8.png

    On applique d’abord une projection (\(\Pi\)) sur les colonnes pays de table bars et origine de la table bieres pour pouvoir mettre en oeuvre l’opération ensembliste d’union (\(\cup\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

  2. Intersection
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher les noms des pays qui produisent de la bière et qui ont des bars ».
    Votre réponse :
    Arbre de requêtes : graph44.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(origine)}(bieres)\)
    • \(P_2 = \Pi_{(pays)}(bars)\)
    • \(I_1 = \cap(P_1,P_2)\)
    • \(Q_1 = I_1\)

    Arbre de requêtes :

    _images/bars-9.png

    On applique d’abord une projection (\(\Pi\)) sur les colonnes origine de table bieres et pays de la table bars pour pouvoir appliquer l’opération ensembliste d’intersection (\(\cap\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

  3. Différence
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « récupérer les noms des pays fabriquant de la bière mais n’ayant pas de bars ».
    Votre réponse :
    Arbre de requêtes : graph48.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(origine)}(bieres)\)
    • \(P_2 = \Pi_{(pays)}(bars)\)
    • \(E_1 = \setminus(P_1,P_2)\)
    • \(Q_1 = E_1\)

    Arbre de requêtes :

    _images/bars-10.png

    On applique d’abord une projection (\(\Pi\)) sur les colonnes pays de table bars et origine de la table bieres pour pouvoir appliquer l’opération ensembliste de différence (\(\displaystyle {\setminus}\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

    Contrairement aux opérations ensemblistes d’union et d’intersection, la différence n’est pas commutative.

5/5 Division relationnelle

Savoir répondre « Aux pays des bières » à des questions du type :

  • “trouve-moi les \(x\) qui sont associés à tous (\(\forall\)) les \(y\)“

Dans notre cas savoir, par exemple, représenter sous forme d’arbre de requêtes la question :

  • “trouver les bars qui servent toutes les bières
  1. DOUBLE NEGATION (1/2)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « quels sont les identifiants des bars qui servent toutes les bières ? ».
    Votre réponse :
    Arbre de requêtes : graph53.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(Q = D\)

    Arbre de requêtes :

    _images/bars-11-1.png

    On peut représenter le symbole de division relationnelle dans un arbre de requête. Cependant il faut garder à l’esprit que cet opérateur n’existe pas en SQL, mais qu’on pourra le mettre en œuvre, par exemple à l’aide d’une double négation (NOT EXISTS imbriqués).

    De manière générique on peut formuler la division relationnelle pour récupérer dans l’ensemble S (S[X,Y]) les éléments qui sont liés à tous ceux de l’ensemble T (T[Y]) par l’information (Y) par l’écriture de l’expression algèbrique :

    • \(\div(\Pi_{(X,Y)}(S),\Pi_{(Y)}(T))\)
  2. DOUBLE NEGATION (2/2)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « quels sont les noms des bars qui servent toutes les bières ? ».
    Votre réponse :
    Arbre de requêtes : graph57.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ_1 = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P_3 = \Pi_{(bar)}(IJ_1)\)
    • \(Q_1 = P_3\)

    Arbre de requêtes :

    _images/bars-11-2.png

    On peut représenter le symbole de division relationnelle dans un arbre de requête. Cependant il faut garder à l’esprit que cet opérateur n’existe pas en SQL, mais qu’on pourra le mettre en œuvre, par exemple à l’aide d’une double négation (NOT EXISTS imbriqués).

    De manière générique on peut formuler la division relationnelle pour récupérer dans l’ensemble S (S[X,Y]) les éléments qui sont liés à tous ceux de l’ensemble T (T[Y]) par l’information (Y) par l’écriture de l’expression algèbrique :

    • \(\div(\Pi_{(X,Y)}(S),\Pi_{(Y)}(T))\)
  3. GROUP BY, HAVING, COUNT (1/3)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « quels sont les identifiants des bars qui servent toutes les bières ? ».
    Votre réponse :
    Arbre de requêtes : graph61.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :
    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(Q_1 = \Pi_{(bar\_id)}(D)\).

    Arbre de requêtes :

    _images/bars-11-3.png

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar\_id)}(services)\).
    • \(Q_1 = \Pi_{(bar\_id)}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette expression algébrique suppose qu’on élimine les doublons.

  4. GROUP BY, HAVING, COUNT (2/3)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « quels sont les noms des bars qui servent toutes les bières ? ».
    Votre réponse :
    Arbre de requêtes : graph65.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    bar
    Bar du Coin
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P = \Pi_{(bar)}(IJ_1)\)
    _images/bars-11-4.png

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(IJ = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar)}(IJ)\).
    • \(Q_1 = \Pi_{(bar)}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette écriture supposant qu’on élimine les doublons.

    Arbre de requêtes :

  5. GROUP BY, HAVING, COUNT (3/3)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « nom des bars qui servent toutes les bières et somme de leur stock de bières ».
    Votre réponse :
    Arbre de requêtes : graph70.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P = \Pi_{(bar,sum(stock))}(IJ_1)\)

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(IJ = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar)}(IJ_1)\).
    • \(Q_1 = \Pi_{(bar,sum(stock))}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette écriture supposant qu’on élimine les doublons.

    Arbre de requêtes :

    _images/bars-11-5.png
3/3 Fonctions d'agrégat

Savoir appliquer, sous forme d’arbre, des fonctions d’agrégat (COUNT, SUM, MAX, MIN, AVG) sur les recherches « Aux pays des bières ».

  1. Sur une requête simple
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Quelle est la quantité de bières en stock au “Corners Pub” ? ».
    Votre réponse :
    Arbre de requêtes : graph75.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R = \sigma_{[bar='Corner`s \; Pub]}(bars)\)
    • \(IJ = \Join_{[R.bar\_id=services.bar\_id]}(R,services)\)
    • \(P = \Pi_{(sum(stock))}(IJ)\)
    • \(Q_1 = P\)

    Arbre de requêtes :

    _images/bars-13.png
  2. Sur une requête imbriquée (1/2)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bières servies au “Bar du Coin” en quantité supérieure à la moyenne de tous les stocks ».
    Votre réponse :
    Arbre de requêtes : graph79.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    biere
    Kronenbourg
    Une solution possible :
    Ecriture en algèbre relationnelle :
    • \(R_1 = \sigma_{[bar='Bar \; du \; Coin']}(bars)\)
    • \(IJ_1 = \Join_{[R_1.bar\_id=services.bar\_id]}(R_1,services)\)
    • \(IJ_2 = \Join_{[IJ_1.biere\_id=bieres.biere\_id]}(IJ_1,bieres)\)
    • \(average=\Pi_{(avg(stock))]}(services)\)
    • \(R_2 = \sigma_{[stock < average]}(IJ_2)\)
    • \(P = \Pi_{(biere)}(R_2)\)
    • \(Q_1 = P\)

    Arbre de requêtes :

    _images/bars-14.png
  3. Sur une requête imbriquée (2/2)
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bars servant de la “Spaten” en quantité supérieure au maximum des stocks de bières du “Bar du Coin” ».
    Votre réponse :
    Arbre de requêtes : graph84.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R_1 = \sigma_{[bar='Bar \; du \; Coin']}(bars)\)
    • \(IJ_1 = \Join_{[R_1.bar\_id=services.bar\_id]}(bars,services)\)
    • \(max\_bdc=\Pi_{(max(stock))}(IJ_1)\)
    • \(IJ_2 = \Join_{[services.biere\_id=bieres.biere\_id]}(services,bieres)\)
    • \(R_2 = \sigma_{[biere='Spaten']}(IJ_2)\)
    • \(R_3 = \sigma_{[stock > max\_bdc]}(R_2)\)
    • \(IJ_3 = \Join_{[R_3.bar\_id=bars.bar\_id]}(R_3,bars)\)
    • \(P = \Pi_{(bar)}(R_3)\)
    • \(Q_1 = P\)

    Arbre de requêtes :

    _images/bars-15.png
4/4 Groupements

Savoir regrouper, sous forme d’arbre, (GROUP BY) les informations, définir des conditions sur les regroupements (HAVING) et appliquer des fonctions d’agrégat sur ces regroupements.

  1. GROUP BY
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom, la couleur des bières et leur quantité en stock dans la base de données ».
    Votre réponse :
    Arbre de requêtes : graph89.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.biere\_id=bieres.biere\_id]}(services,bieres)\).
    • \(G = G_{[]}^{(biere,couleur)}(NJ)\).
    • \(Q_1 = \Pi_{(biere,couleur,sum(stock))}(G)\).

    Arbre de requêtes :

    _images/bars-16.png
  2. GROUP BY HAVING
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bars, le nombre de bières qu’ils servent et la somme de leur stocks pour les bars qui servent au moins deux bières ».
    Votre réponse :
    Arbre de requêtes : graph93.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.bar\_id=bars.bar\_id]}(services,bars)\).
    • \(G = G_{[count(biere\_id) > 1]}^{(bar)}(IJ)\).
    • \(Q_1 = \Pi_{(bar,count(biere\_id),sum(stock))}(G)\).

    Arbre de requêtes :

    _images/bars-17.png
  3. GROUP BY HAVING, requête imbriquée
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des pays, le nombre de toutes les bières servies dans ces pays et la somme de leurs stocks, pour les pays dont la quantité de bières est supérieure à la moyenne des stocks mondiaux ».
    Votre réponse :
    Arbre de requêtes : graph97.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.bar\_id=bars.bar\_id]}(services,bars)\).
    • \(average=\Pi_{(avg(stock))]}(services)\)
    • \(G = G_{[sum(stock)> average]}^{(pays)}(IJ)\).
    • \(Q_1 = \Pi_{(pays,count(biere\_id),sum(stock))}(G)\).

    Arbre de requêtes :

    _images/bars-18.png
  4. WHERE, GROUP BY HAVING
    • Question
    • Solution

    Construire un arbre de requêtes répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bars, le nombre de toutes les bières servies dans ces bars et la somme de leurs stocks, pour les bars de “France” ou des “USA” servant plus d’une bière ».
    Votre réponse :
    Arbre de requêtes : graph101.json

    Tables

    Opérateurs unaires

    Opérateurs binaires

    Vue d'ensemble
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R = \sigma_{[pays ='France' \; \lor \; pays='USA']}(bars)\)
    • \(IJ = \Join_{[services.bar\_id=R.bar\_id]}(services,R)\)
    • \(G = G_{[count(biere\_id) > 1)]}^{(bar)}(IJ)\).
    • \(Q_1 = \Pi_{(bar,count(biere\_id),sum(stock))}(G)\).
    _images/bars-19.png

Requêtes SQL

L’objectif des ces exercices est de savoir formuler des requêtes SQL sous la forme :

SELECT ...
FROM  ...
WHERE ...
GROUP BY  ...
HAVING ...

pour savoir rechercher les informations à partir :

  • d’une seule table (projection et restriction)
  • de plusieurs tables (jointures)
  • des opérations ensemblistes (union,intersection,différence)
  • de formulation de division relationnelle
  • des fonctions d’agrégats
  • des regroupements dans un ensemble avec restriction sur les groupements
5/5 Requêtes sur une table

Savoir formuler les requêtes sur une table en appliquant des :

  • projections (\(\Pi\))
  • restrictions (\(\sigma\))

en écrivant des expressions logiques dans les clauses de restriction.

  1. Projection
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher le nom et la couleur des bières ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \Pi_{(biere,couleur)}(bieres)\)

    On applique une projection (\(\Pi\)) sur les colonnes (biere,couleur) de la table bieres.

    Ecriture en langage SQL :

    SELECT biere,couleur FROM bieres;
    
  2. Restriction
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher les bières d’origine française ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \sigma_{[origine='France']}(bieres)\)

    On applique une restriction (\(\sigma\)) sur la table bieres avec la condition [origine='France'] .

    Ecriture en langage SQL :

    SELECT *
    FROM bieres
    WHERE origine='France';
    
  3. Projection et Restriction
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bières françaises ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \Pi_{(biere)}(\sigma_{[origine='France']}(bieres))\).

    On applique une projection (\(\Pi\)) sur la colonne biere et une restriction (\(\sigma\)) sur la condition [origine='France'] de la table bieres.

    Ecriture en langage SQL :

    SELECT biere
    FROM bieres
    WHERE origine='France';
    
  4. Connecteur logique
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher les bières blondes françaises ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \sigma_{[origine='France' \land couleur='Blonde']}(bieres)\).

    On vérifie (\(\sigma\)) que les bières sont d’origine française (origine='France') et (\(\land\)) qu’elles sont de couleur blonde (couleur='Blonde')

    Ecriture en langage SQL :

    SELECT *
    FROM bieres
    WHERE origine='France' AND couleur='Blonde';
    
  5. connecteurs logiques
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher le nom et la couleur des bières françaises blondes et les bières brunes ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(Q_1 = \Pi_{(biere,couleur)}(\sigma_{[origine='France' \land couleur='Blonde' \lor couleur='Brune']}(bieres))\)

    On vérifie (\(\sigma\)) sur la table bieres qu’elles sont d’origine française et (\(\land\) : et logique) de couleur blonde ou (\(\lor\): ou logique) que la couleur des bières est brune.

    Ecriture en langage SQL :

    SELECT biere,couleur
    FROM bieres
    WHERE origine='France' AND couleur='Blonde'
      OR couleur='Brune';
    

    Attention à la priorité du connecteur logique \(\land\) sur le \(\lor\) (de même que la multiplication l’est sur l’addition).

    La requête :
    • \(Q_1 = \sigma_{[origine='France' \lor couleur='Blonde' \land couleur='Brune']}(bieres)\)

    donnerait comme résultat … les bières françaises (il ne peut exister des bières blonde et brune à la fois).

    Remarque : on peut modifier la priorité en parenthésant des parties de la restriction :
    • \(Q_1 = \sigma_{[origine='France' \land (couleur='Blonde' \lor couleur='Brune')]}(bieres)\)

    donnera comme résultat les bières françaises et les bières de couleur blonde ou brune.

2/2 Requêtes sur plusieurs tables

Savoir formuler une requête sur plusieurs tables en faisant:

  • produits cartésiens (\(\times\))
  • jointures (\(\Join\))

Sachant qu’une jointure est une combinaison de produit cartésien (\(\times\)) et de restriction (\(\sigma\))

Savoir créer des vues qui contiennent les informations « métier » sur le modèle de données « Aux pays des bières ».

  1. Produit cartésien et restriction
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher les bars qui servent de la bière ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ_1 = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(IJ_2 = \Join_{[IJ_1.biere\_id=bieres.biere\_id]}(IJ_1,bieres)\)
    • \(Q_1 = IJ_2\)

    On réalise ici deux jointures (\(\Join\)) entre les tables bars,services puis une jointure entre le résultat obtenu (\(IJ_1\)) et la table bieres.

    L’ordre d’éxecution des jointures (\(IJ_1\) avant ou après \(IJ_2\)) dépendra de l’état de la base de données (nombre d’enregistrements dans les tables, utilisation d’index sur colonnes …) et sera déterminé par l’optimiseur de requêtes du SGBD Relationnel utilisé.

    Remarque :

    une jointure est une combinaison de produit cartésien et de restriction, on peut les représenter à l’aide de ces opérateurs :

    • \(IJ_1 = \sigma_{[bars.bar\_id=services.bar\_id]}(\times(bars,services))\)
    • \(IJ_2 = \sigma_{[IJ_1.biere\_id=bieres.biere\_id]}(\times(IJ_1,bieres))\)

    Ecriture en langage SQL :

    SELECT *
    FROM bars, services s, bieres
    WHERE bars.bar_id = services.bar_id AND services.biere_id=bieres.biere_id;
    

    On réalise, dans cette requête SQL, un produit cartésien (\(\times\)) entre les tables bars,services,bieres puis on applique une restriction (\(\sigma\)) pour vérifier que chaque bar de l’ensemble des bars est bien lié aux bieres qu’il sert par l’ensemble des services :

    \([bars.bar\_id = services.bar\_id \land services.biere\_id=bieres.biere\_id]\)

    Le produit cartésien (CROSS JOIN) suivi d’une restriction (WHERE) peut aussi être mis en oeuvre en utilisant l’opérateur de jointure interne (INNER JOIN) avec une condition (ON) sur les colonnes de jointure.

    SELECT "" AS "Jointure interne";
    SELECT *
    FROM  bars INNER JOIN services INNER JOIN bieres ON (bars.bar_id=services.bar_id AND services.biere_id=bieres.biere_id);
    

    Les colonnes de jointures ayant même nom (bar\_id,biere\_id) et étant définies sur les même domaines (integer) nous pourrions aussi formuler cette requête par une jointure naturelle (\(\Join_{[]}\))

    SELECT *
    FROM bars  NATURAL JOIN services NATURAL JOIN bieres;
    

    Cependant les jointures naturelles sont à manipuler avec précaution. Il faut être sûr qu’il n’existe pas d’autres colonnes dans les tables qui pourraient être utilisés « naturellement » sans que nous le sachions.

  2. Création de vue
    • Question
    • Solution

    Créer une vue barsdumonde sur les informations “métier” (sans les clés bar_id,biere_id) des « bars qui servent de la bière ».

    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ_1 = \Join_{[bars.bar_id=services.bar_id]}(bars,services)\)
    • \(IJ_2 = \Join_{[NJ_1.biere_id=bieres.biere_id]}(IJ_1,bieres)\)
    • \(barsdumonde = \Pi_{(bar,pays,stock,biere,couleur,origine)}(IJ_2)\)

    Ecriture en langage SQL :

    CREATE VIEW  barsdumonde AS
    SELECT bar,pays,continent,biere,couleur,origine,stock
    FROM bars, services, bieres
    WHERE bars.bar_id = services.bar_id AND services.biere_id=bieres.biere_id;
    
    SELECT "" AS "Informations sur les Bars du Monde";
    SELECT * FROM barsdumonde;
    

    On “encapsule” dans une vue (CREATE VIEW barsdumonde AS) une requête SQL pour consulter plus simplement les informations “métier” (sans les clés primaires et étrangères). (bar,pays,stock,biere,couleur,origine).

3/3 Opérations ensemblistes

Savoir formuler des opérations ensemblistes (\(\cup,\cap,\setminus\)) sur le modèle de données « Aux pays des bières ».

  • Union (\(\cup\))
  • Intersection (\(\cap\))
  • Différence (\(\setminus\))
  1. Union
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « récupérer les noms des pays ou se trouvent des bars et ceux des origines de fabrication des bières ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(pays)}(bars)\)
    • \(P_2 = \Pi_{(origine)}(bieres)\)
    • \(U_1 = \cup(P_1,P_2)\)

    Ecriture en langage SQL :

    SELECT pays FROM bars
    UNION
    SELECT origine FROM bieres;
    

    On applique d’abord une projection (\(\Pi\)) sur les colonnes pays de table bars et origine de la table bieres pour pouvoir mettre en oeuvre l’opération ensembliste d’union (\(\cup\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

    Pour obtenir d’abord le nom des pays où se trouvent les bars suivi de celui d’origine de fabrication des bières on pourra faire en SQL un UNION ALL qui concatène le résultat des deux requêtes.

    SELECT pays FROM bars
    UNION ALL
    SELECT origine FROM bieres;
    

    Pour éliminer les doublons dans les deux requêtes concaténées on peut appliquer un distinct sur chcune des requêtes

    SELECT DISTINCT pays FROM bars
    UNION ALL
    SELECT DISTINCT origine FROM bieres;
    

    Il pourra cependant subsister des doublons dans le résultat final de la requête. Le résultat de cette requête ne sera donc pas nécessairement un ensemble.

  2. Intersection
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question

    • \(Q_1\) : « Rechercher les noms des pays qui produisent de la bière et qui ont des bars ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(origine)}(bieres)\)
    • \(P_2 = \Pi_{(pays)}(bars)\)
    • \(I_1 = \cap(P_1,P_2)\)

    Ecriture en langage SQL :

    SELECT origine FROM bieres;
    INTERSECT
    SELECT pays FROM bars
    

    On applique d’abord une projection (\(\Pi\)) sur les colonnes origine de table bieres et pays de la table bars pour pouvoir appliquer l’opération ensembliste d’intersection (\(\cap\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

    On pourra aussi formuler cette recherche par une requête imbriquée avec un IN (\(\in\)).

    SELECT origine
    FROM bieres
    WHERE origine IN (
                      SELECT pays
                      FROM bars
    );
    

    Dans ce type de requête on parcourt tous les élementd de l’ensemble de la requête externe et on vérifie qu’il sont (appartiennent à) dans l’ensemble retourné par la requête imbriquée.

    De même on pourra exprimer cette recherche par une requête imbriquée avec un EXISTS (\(\exists\)). On vérifie la condition d’existence de chaque élément de la requête externe dans la requête imbriquée.

    SELECT origine
    FROM bieres
    WHERE EXISTS (
                  SELECT *
                  FROM bars
                  WHERE origine=pays
    );
    

    Enfin, dans le cas de l’intersection, on peut tout aussi bien faire un produit cartésien et une restriction avec un test d’égalité entre le nom d’origine de fabrication des bières et celui des pays où se trouvent les bars.

    SELECT  origine
    FROM bieres, bars
    WHERE origine = pays;
    
  3. Différence
    • Question
    • Solution
    Ecrire une requête SQL répondant à la question
    • \(Q_1\) : « Rechercher les noms des pays qui produisent de la bière et qui n’ont pas de bars ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(origine)}(bieres)\)
    • \(P_2 = \Pi_{(pays)}(bars)\)
    • \(E_1 = \setminus(P_1,P_2)\)

    Ecriture en langage SQL :

    SELECT  origine FROM bieres
    EXCEPT
    SELECT  pays FROM bars;
    

    On applique d’abord une projection (\(\Pi\)) sur les colonnes pays de table bars et origine de la table bieres pour pouvoir appliquer l’opération ensembliste de différence (\(\displaystyle {\setminus}\)).

    Les opérations ensemblistes sont des opérateurs binaires qui doivent avoir pour chaque entrée (opérande) le même nombre d’attributs, chacun étant défini sur le même domaine.

    Contrairement aux opérations ensemblistes d’union et d’intersection, la différence n’est pas commutative.

    On pourra aussi formuler cette recherche par une requête imbriquée avec un NOT IN (\(\notin\)).

    SELECT origine
    FROM bieres
    WHERE origine IN (
                      SELECT pays
                      FROM bars
    );
    

    Dans ce type de requête on parcourt tous les élements de l’ensemble de la requête externe et on vérifie qu’il ne sont pas (n’appartiennent pas à) dans l’ensemble retournée par la requête imbriquée.

    De même on pourra exprimer cette recherche par une requête imbriquée avec un NOT EXISTS (\(\nexists\)). On vérifie la condition de non-existence de chaque élément de la requête externe dans la requête imbriquée.

    SELECT origine
    FROM bieres
    WHERE EXISTS (
                  SELECT *
                  FROM bars
                  WHERE origine=pays
    );
    

    Contrairement à l’opération d’intersection on ne pourra pas faire un produit cartésien et une restriction avec un test de non-égalité (différence) entre le nom des pays où se trouvent des bars et celui de l’origine de fabrication des bières.

    SELECT  origine
    FROM bieres, bars
    WHERE origine <> pays;
    

    Cette requête ne donnerait pas les éléments recherchés mais tous les éléments issus du produit cartésien qui vérifient que l’origine de fabrication est différente du nom des pays où se trouvent les bars… on obtiendrait donc toutes les origine de fabrications des bières puisque toutes les combinaisons possibles ont été générés par le produit cartésien.

5/5 Division relationnelle

Savoir répondre « Aux pays des bières » à des questions du type :

  • “trouve-moi les \(x\) qui sont associés à tous (\(\forall\)) les \(y\)“

Dans notres cas, par exemple :

  • “trouver les bars qui servent toutes les bières
  1. DOUBLE NEGATION (1/2)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question \(Q_1\) :

    • \(Q_1\) : « quels sont les identifiants des bars qui servent toutes les bières ? ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre à l’aide d’une double négation (NOT EXISTS imbriqués).

    On reformulerait la question :
    • « trouver les identifiants des bars tel qu’il n’existe pas de bières pour lesquelles il n’existe pas de service associant le bar en question avec cette bière ».

    Ecriture en langage SQL :

    SELECT DISTINCT bar_id
    FROM services s1
    WHERE NOT EXISTS (
                      SELECT *
                      FROM bieres bi
                      WHERE NOT EXISTS (
                                        SELECT *
                                        FROM services s2
                                        WHERE s1.bar_id = s2.bar_id
                                          AND s2.biere_id = bi.biere_id
                                      )
                     );
    

    De manière générique on peut formuler la division relationnelle pour récupérer dans l’ensemble S (S[X,Y]) les éléments qui sont liés à tous ceux de l’ensemble T (T[Y]) par l’information (Y) par l’écriture de l’expression algèbrique :

    • \(\div(\Pi_{(X,Y)}(S),\Pi_{(Y)}(T))\)

    que l’on peut traduire en SQL par :

    SELECT se.X
    FROM S s1
    WHERE NOT EXISTS (
                      SELECT *
                      FROM T
                      WHERE NOT EXISTS (
                                        SELECT *
                                        FROM S s2
                                        WHERE s1.X = s2.X
                                          AND s2.Y = T.Y
                                       )
                     );
    
  2. DOUBLE NEGATION (2/2)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question \(Q_1\) :

    • \(Q_1\) : « quels sont les noms des bars qui servent toutes les bières ? ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ_1 = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P_3 = \Pi_{(bar)}(IJ_1)\)

    On pourra met en œuvre l’opération de division relationnelle en reformulant la question :

    • trouver le nom des bars tel qu’il n’existe pas de bières pour lesquelles il n’existe pas de service associant le bar en question à cette bière.

    Ecriture en langage SQL :

    SELECT bar
    FROM bars ba
    WHERE NOT EXISTS (
                      SELECT *
                      FROM bieres bi
                      WHERE NOT EXISTS (
                                        SELECT *
                                        FROM services s
                                        WHERE ba.bar_id = s.bar_id AND s.biere_id = bi.biere_id
                                       )
                     );
    

    La jointure interne (\(IJ_1\)) se faisant dans la requête la plus imbriquée.

    On pourra aussi formuler cette requête par l’utilisation d’une opération ensembliste de différence :

    SELECT bar
    FROM bars ba
    WHERE NOT EXISTS (
                      SELECT biere_id FROM bieres
                      EXCEPT
                      SELECT biere_id FROM services
                      WHERE bar_id = ba.bar_id
    );
    

    Cette formulation est très proche de la précédente, la comparaison sur les identifiants de bières se faisant sur les éléments récupérés par les deux requêtes mises en jeu dans l’opération ensembliste.

  3. GROUP BY, COUNT (1/3)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question \(Q_1\) :

    • \(Q_1\) : « quels sont les identifiants des bars qui servent toutes les bières ? ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(Q_1 = \Pi_{(bar\_id)}(D)\).

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar\_id)}(services)\).
    • \(Q_1 = \Pi_{(bar\_id)}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette écriture supposant qu’on élimine les doublons.

    Ecriture en langage SQL :

    SELECT DISTINCT bar_id
    FROM services s
    GROUP BY bar_id
    HAVING COUNT(DISTINCT biere_id) = (SELECT COUNT(biere_id) FROM bieres);
    
  4. GROUP BY, COUNT (2/3)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question \(Q_1\) :

    • \(Q_1\) : « quels sont les noms des bars qui servent toutes les bières ? ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P = \Pi_{(bar)}(IJ_1)\)

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(IJ = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar)}(IJ_1)\).
    • \(Q_1 = \Pi_{(bar)}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette écriture supposant qu’on élimine les doublons.

    Ecriture en langage SQL :

    SELECT bar
    FROM bars INNER JOIN services ON (services.bar_id=bars.bar_id)
    GROUP BY bar
    HAVING COUNT(DISTINCT biere_id) = (SELECT COUNT(biere_id) FROM bieres);
    
  5. GROUP BY, COUNT (3/3)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question \(Q_1\) :

    • \(Q_1\) : « nom des bars qui servent toutes les bières et somme de leur stock de bières ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(P_1 = \Pi_{(bar\_id,biere\_id)}(services)\)
    • \(P_2 = \Pi_{(biere\_id)}(bieres)\)
    • \(D = \div(P_1,P_2)\)
    • \(IJ = \Join_{[D.bar\_id=bars.bar\_id]}(D,bars)\)
    • \(P = \Pi_{(bar,sum(stock))}(IJ_1)\)

    L’opération de division relationnelle n’existe pas en SQL, mais on peut le mettre en œuvre en appliquant des fonctions d’agrégats sur des regroupements.

    En effet on peut compter le nombre de bières différentes servies par bar (GROUP BY) et ne retenir (condition HAVING) que ceux pour lesquels le nombre de bières est égal au nombre total de bières existantes dans la base de données. On peut donc reformuler la question :
    • trouver les identifiants des bars qui servent un nombre de bières différentes qui soit égal au nombre total de bières de la base de données.

    Dans ce cas, on peut reformuler la division relationnelle par l’expression algébrique :

    • \(IJ = \Join_{[bars.bar\_id=services.bar\_id]}(bars,services)\)
    • \(nb\_bieres=\Pi_{count(biere\_id)}(bieres)\)
    • \(G = G_{[count(biere\_id)=nb\_bieres]}^{(bar)}(IJ_1)\).
    • \(Q_1 = \Pi_{(bar,sum(stock))}(G)\).

    Le symbole \(G\) représente l’opérateur de regroupement appliqué sur la table services avec :

    • en exposant : attributs de groupement (GROUP BY)
    • en indice : critère de restriction (HAVING) sur les groupements.

    Cette écriture supposant qu’on élimine les doublons.

    Ecriture en langage SQL :

    SELECT bar,SUM(stock)
    FROM bars INNER JOIN services ON (services.bar_id=bars.bar_id)
    GROUP BY bars.bar_id,bar
    HAVING COUNT(DISTINCT biere_id) = (SELECT COUNT(biere_id) FROM bieres);
    

    Remarque : on regroupe suivant les attributs (bar_id,bar) car il peut arriver que deux bars aient le même nom mais soient différents.

3/3 Fonctions d'agrégat

Savoir appliquer des fonctions d’agrégat (COUNT, SUM, MAX, MIN, AVG) sur les recherches « Aux pays des bières ».

  1. Sur une requête simple
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Quelle est la quantité de bières en stock au “Corners Pub” ? ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R = \sigma_{[bar='Corner`s \; Pub]}(bars)\)
    • \(IJ = \Join_{[R.bar\_id=services.bar\_id]}(R,services)\)
    • \(P = \Pi_{(sum(stock))}(IJ)\)

    Ecriture en langage SQL :

    SELECT "" AS "Produit cartésien, restriction";
    SELECT SUM(s.stock) AS "stocks"
    FROM services s, bars b
    WHERE s.bar_id=b.bar_id AND b.bar='Corner`s Pub';
    
    SELECT "" AS "INNER JOIN ";
    SELECT SUM(s.stock) AS "stocks"
    FROM services s INNER JOIN bars b ON (s.bar_id=b.bar_id)
    WHERE bar='Corners Pub';
    
    SELECT "" AS "NATURAL JOIN";
    SELECT SUM(stock) AS "stocks"
    FROM services NATURAL JOIN bars
    WHERE bar='Corner`s Pub';
    
  2. Sur une requête imbriquée (1/2)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bières servies au “Bar du Coin” en quantité inférieure à la moyenne de tous les stocks ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R_1 = \sigma_{[bar='Bar \; du \; Coin']}(bars)\)
    • \(IJ_1 = \Join_{[R_1.bar\_id=services.bar\_id]}(R_1,services)\)
    • \(IJ_2 = \Join_{[IJ_1.biere\_id=bieres.biere\_id]}(IJ_1,bieres)\)
    • \(average=\Pi_{(avg(stock))]}(services)\)
    • \(R_2 = \sigma_{[stock < average]}(IJ_2)\)
    • \(P = \Pi_{(biere)}(R_2)\)

    Ecriture en langage SQL :

    SELECT biere
    FROM bars, services,bieres
    WHERE bars.bar_id=services.bar_id AND services.biere_id=bieres.biere_id
      AND bar='Bar du Coin'
      AND stock < (
                   SELECT AVG(stock) FROM services
                  );
    
  3. Sur une requête imbriquée (2/2)
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question

    • \(Q_1\) : « Rechercher le nom des bars servant de la “Spaten” en quantité supérieure au maximum des stocks de bières du “Bar du Coin” ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R_1 = \sigma_{[bar='Bar \; du \; Coin']}(bars)\)
    • \(IJ_1 = \Join_{[R_1.bar\_id=services.bar\_id]}(bars,services)\)
    • \(max\_bdc=\Pi_{(max(stock))}(IJ_1)\)
    • \(IJ_2 = \Join_{[services.biere\_id=bieres.biere\_id]}(services,bieres)\)
    • \(R_2 = \sigma_{[biere='Spaten']}(IJ_2)\)
    • \(R_3 = \sigma_{[stock > max\_bdc]}(R_2)\)
    • \(IJ_3 = \Join_{[R_3.bar\_id=bars.bar\_id]}(R_3,bars)\)
    • \(P = \Pi_{(bar)}(R_3)\)

    Ecriture en langage SQL :

    SELECT bar
    FROM bars, services,bieres
    WHERE bars.bar_id=services.bar_id AND services.biere_id=bieres.biere_id
      AND biere='Spaten'
      AND stock > (
                   SELECT MAX(stock)
                   FROM   bars INNER JOIN services ON (bars.bar_id=services.bar_id)
                   WHERE  bar='Bar du Coin'
                   );
    
4/4 Groupements

Savoir regrouper (GROUP BY) les informations, définir des conditions sur les regroupements (HAVING) et appliquer des fonctions d’agrégat sur ces regroupements.

  1. Groupement
    • Question
    • Solution
    Ecrire une requête SQL répondant à la question
    • \(Q_1\) : « Rechercher le nom, la couleur des bières et leur quantité en stock dans la base de données ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.biere\_id=bieres.biere\_id]}(services,bieres)\).
    • \(G = G_{[]}^{(biere,couleur)}(NJ)\).
    • \(Q_1 = \Pi_{(biere,couleur,sum(stock))}(G)\).

    Ecriture en langage SQL :

    SELECT biere, couleur,  SUM(stock)
    FROM  services INNER JOIN bieres ON (services.biere_id=bieres.biere_id);
    GROUP BY biere, couleur;
    

    On fait un regroupement (GROUP BY) des bières qui sont servies par nom de bières (biere) et leur couleur

    On récupère dans le résultat final les attribut de groupement (code:nom,couleur) et on calcule sur ces regroupements la somme des quantités servies (code:SUM(stock)).

  2. Groupement et restriction
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question :

    • \(Q_1\) : « Rechercher le nom des bars, le nombre de bières qu’ils servent et la somme de leur stocks pour les bars qui servent au moins deux bières ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.bar\_id=bars.bar\_id]}(services,bars)\).
    • \(G = G_{[count(biere\_id) > 1]}^{(bar)}(IJ)\).
    • \(Q_1 = \Pi_{(bar,count(biere\_id),sum(stock))}(G)\).

    Ecriture en langage SQL :

    SELECT bar, COUNT(biere_id), SUM(stock)
    FROM  bars INNER JOIN services ON (bars.bar_id=services.bar_id);
    GROUP BY bar
    HAVING COUNT (biere_id) > 1;
    

    On fait un regroupement (GROUP BY) par bar servant des bières.

    On ne retient (HAVING) dans ce regroupement que les bars qui servent au moins 2 bières différentes.

    On récupère dans le résultat final le nom des bars, leur nombre de bières et la quantité totale (bar,COUNT(id_biere),SUM(stock)) servie dans ces bars.

  3. Groupement et restriction avec requête imbriquée
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question

    • \(Q_1\) : « Rechercher le nom des pays, le nombre de toutes les bières servies dans ces pays et la somme de leurs stocks, pour les pays dont la quantité de bières est supérieure à la moyenne des stocks mondiaux ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(IJ = \Join_{[services.bar\_id=bars.bar\_id]}(services,bars)\).
    • \(average=\Pi_{(avg(stock))]}(services)\)
    • \(G = G_{[sum(stock)> average]}^{(pays)}(IJ)\).
    • \(Q_1 = \Pi_{(pays,count(biere\_id),sum(stock))}(G)\).

    Ecriture en langage SQL :

    SELECT pays, COUNT(biere_id), SUM(stock)
    FROM  bars INNER JOIN services ON (bars.bar_id=services.bar_id);
    GROUP BY pays
    HAVING SUM(stock)> (
                        SELECT AVG( stock ) FROM services
                       );
    

    On fait un regroupement (GROUP BY) par nom de pays des bars servant des bières. On ne retient dans ces regroupements que les pays dont la somme des stock de bières de leurs bars est supérieure à la moyenne des stocks mondiaux. On obtient dans le résultat final le nom des pays, le nombre de bières et la somme des stock servies dans ces pays.

  4. Restriction, groupement et restriction
    • Question
    • Solution

    Ecrire une requête SQL répondant à la question

    • \(Q_1\) : « Rechercher le nom des bars, le nombre de toutes les bières servies dans ces bars et la somme de leurs stocks, pour les bars de “France” ou des “USA” servant plus d’une bière ».
    Votre réponse :
    sql : bars.sql
    
        
    >
    Output
    
                    

    Interpréteur

    MenuAction
    Ré-initialiser les sorties
    Faire apparaître le menu d'aide
    Interpréter le programme

    Editeur

    MenuRaccouciAction
    Ctrl+N Initialiser l'éditeur
    Ctrl+O Charger le contenu d'un fichier dans l'éditeur
    Ctrl+S Sauvegarder le contenu de l'éditeur dans un fichier
    Ctrl+P Imprimer le contenu de l'éditeur
    Ctrl+Z Annuler la dernière modification
    Maj+Ctrl+Z Rétablir la modification précedente
    Ctrl+F Chercher une expression dans l'éditeur
    Maj+Ctrl+F Chercher et remplacer une expression par une autre
    F10 Ouvrir une documentation du langage

    RaccourciAction
    F1 Afficher cette aide
    Tab Indenter la sélection
    Maj+Tab Désindenter la sélection
    Ctrl+A Sélectionner le contenu de l'éditeur
    Ctrl+C Copier la sélection dans le presse-papier
    Ctrl+V Remplacer la sélection par le contenu du presse-papier
    Ctrl+X Supprimer la sélection et la copier dans le presse-papier
    Maj+Ctrl+R Chercher et remplacer une expression par une autre dans tout l'éditeur
    Une solution possible :

    Ecriture en algèbre relationnelle :

    • \(R = \sigma_{[pays ='France' \; \lor \; pays='USA']}(bars)\)
    • \(IJ = \Join_{[services.bar\_id=R.bar\_id]}(services,R)\)
    • \(G = G_{[count(biere\_id) > 1)]}^{(bar)}(IJ)\).
    • \(Q_1 = \Pi_{(bar,count(biere\_id),sum(stock))}(G)\).

    Ecriture en langage SQL :

    SELECT bar, COUNT( biere_id),SUM(stock)
    FROM  bars INNER JOIN services ON (bars.bar_id=services.bar_id);
    WHERE (pays ='France' OR pays='USA')
    GROUP BY bar
    HAVING COUNT (biere_id) > 1;
    

    On récupère les services des bars des deux pays (pays ='France' OR pays='USA'), puis on les regroupe par nom de bar (GROUP BY bar)

    On ne retient dans ces regroupements que les bar dont le nombre de bières qu’ils servent est supérieur à la moyenne des stocks mondiaux.

    On récupère dans le résultat final le nom des bars,le nombre de bières qu’ils servent et la somme des stocks de bières servies dans ces bars (bar, COUNT( biere_id ),SUM(stock))

 
Systèmes d'Information : Aux pays des bières, 13 avr. 2023.