Introduction à SQL

Formation DEV0

Dalibo SCOP

24.09

29 août 2024

Sur ce document

Formation Formation DEV0
Titre Introduction à SQL
Révision 24.09
ISBN N/A
PDF https://dali.bo/dev0_pdf
EPUB https://dali.bo/dev0_epub
HTML https://dali.bo/dev0_html
Slides https://dali.bo/dev0_slides

Licence Creative Commons CC-BY-NC-SA

Cette formation est sous licence CC-BY-NC-SA. Vous êtes libre de la redistribuer et/ou modifier aux conditions suivantes :

  • Paternité
  • Pas d’utilisation commerciale
  • Partage des conditions initiales à l’identique

Marques déposées

PostgreSQL® Postgres® et le logo Slonik sont des marques déposées par PostgreSQL Community Association of Canada.

Versions de PostgreSQL couvertes

Ce document ne couvre que les versions supportées de PostgreSQL au moment de sa rédaction, soit les versions 12 à 16.

Introduction et premiers SELECT

Préambule

  • Qu’est-ce que le standard SQL ?
  • Comment lire des données
  • Quels types de données sont disponibles ?
  • Principes d’une base de données
  • Premières requêtes
  • Connaître les types de données

Objectifs

  • Comprendre les principes
  • Écrire quelques requêtes en lecture
  • Connaître les différents types de données
    • et quelques fonctions très utiles

Principes d’une base de données

  • Base de données
    • ensemble organisé d’informations
  • Système de Gestion de Bases de Données
    • acronyme SGBD (DBMS en anglais)
    • programme assurant la gestion et l’accès à une base de données
    • assure la cohérence des données

Type de bases de données

  • Modèle hiérarchique
  • Modèle réseau
  • Modèle relationnel
  • Modèle objet
  • Modèle relationnel-objet
  • NoSQL

Type de bases de données (1)

  • Modèle hiérarchique
    • structure arborescente
    • redondance des données
  • Modèle réseau
    • structure arborescente, mais permettant des associations
    • ex : Bull IDS2 sur GCOS

Type de bases de données (2)

  • Modèle relationnel
    • basé sur la théorie des ensembles et la logique des prédicats
    • standardisé par la norme SQL
  • Modèle objet
    • structure objet
    • pas de standard
  • Modèle relationnel-objet
    • le standard SQL ajoute des concepts objets

Type de bases de données (3)

  • NoSQL : Not only SQL
    • pas de norme de langage de requête
    • clé-valeur (Redis, Riak)
    • graphe (Neo4J)
    • document (MongoDB, CouchDB)
    • orienté colonne (HBase)
  • Rapprochement relationnel/NoSQL
    • PostgreSQL permet de stocker des documents (JSON, XML)

Modèle relationnel

  • Indépendance entre la vue logique et la vue physique
    • le SGBD gère lui-même le stockage physique
  • Table ou relation
  • Un ensemble de tables représente la vue logique

Caractéristiques du modèle relationnel

  • Théorie des ensembles
  • Logique des prédicats
  • Logique 3 états

ACID

Gestion transactionnelle : la force des bases de données relationnelles :

  • Atomicité (Atomic)
  • Cohérence (Consistent)
  • Isolation (Isolated)
  • Durabilité (Durable)

Langage SQL

  • Norme ISO 9075
    • dernière version stable : 2023
  • Langage déclaratif
    • on décrit le résultat et pas la façon de l’obtenir
    • comme Prolog
  • Traitement ensembliste
    • par opposition au traitement procédural
    • « on effectue des opérations sur des relations pour obtenir des relations »

SQL est un langage

  • Langage
    • règles d’écriture
    • règles de formatage
    • commentaires
  • Améliore la lisibilité d’une requête

Recommandations d’écriture et de formatage

  • Écriture
    • mots clés SQL en MAJUSCULES
    • identifiants de colonnes/tables en minuscule
  • Formatage
    • dissocier les éléments d’une requête
    • un prédicat par ligne
    • indentation

Commentaires

  • Commentaire sur le reste de la ligne
    -- commentaire
  • Commentaire dans un bloc
    /* bloc
     +/

Les 4 types d’ordres SQL

  • DDL
    • Data Definition Language
    • définit les structures de données
  • DML
    • Data Manipulation Language
    • manipule les données
  • DCL
    • Data Control Language
    • contrôle l’accès aux données
  • TCL
    • Transaction Control Language
    • contrôle les transactions
    • implicites si « autocommit »

Lecture de données

  • Ordre SELECT
    • lecture d’une ou plusieurs tables
    • ou appel de fonctions

Syntaxe de SELECT

SELECT expressions_colonnes
 [ FROM elements_from ]
 [ WHERE predicats ]
 [ ORDER BY expressions_orderby ]
 [ LIMIT limite ]
 [ OFFSET offset ];

Liste de sélection

  • Description du résultat de la requête
    • colonnes retournées
    • renommage
    • dédoublonnage

Colonnes retournées

  • Liste des colonnes retournées
    • expression
    • séparées par une virgule
  • Expression
    • constante
    • référence de colonne :
    table.colonne
  • opération sur des colonnes et/ou des constantes

Alias de colonne

  • Renommage
    • ou alias
    • AS :
    expression AS alias
  • le résultat portera le nom de l’alias

Dédoublonnage des résultats

    SELECT DISTINCT expressions_colonnes...
  • Dédoublonnage des résultats avant de les retourner
    • à ne pas utiliser systématiquement

Dérivation

  • SQL permet de dériver les valeurs des colonnes
    • opérations arithmétiques : +, -, /, *
    • concaténation de chaînes : ||
    • appel de fonction

Fonctions utiles

  • Fonctions sur données temporelles :
    • date et heure courante : now()
    • âge : age(timestamp)
    • extraire une partie d’une date : extract( 'year' FROM timestamp)
    • ou date_part('Y',timestamp)
  • Fonctions sur données caractères :
    • longueur d’une chaîne de caractère : char_length(chaine)
  • Compter les lignes : count(*)

Clause FROM

FROM expression_table [, expression_table ...]
  • Description des tables mises en œuvre dans la requête
    • une seule table
    • plusieurs tables jointes
    • sous-requête

Alias de table

  • Mot-clé AS
    • optionnel :
    reference_table alias
  • La table sera ensuite référencée par l’alias
    reference_table [AS] alias
    reference_table AS alias (alias_colonne1, ...)

Nommage des objets

  • Noms d’objets convertis en minuscules
    • Nom_Objet devient nom_objet
    • certains nécessitent l’emploi de majuscules
  • Le guillemet double " conserve la casse
    • "Nom_Objet"

Clause WHERE

  • Permet d’exprimer des conditions de filtrage
    • prédicats
  • Un prédicat est une opération logique
    • renvoie vrai ou faux
  • La ligne est présente dans le résultat
    • si l’expression logique des prédicats est vraie

Expression et opérateurs de prédicats

  • Comparaison
    • =, <, >, <=, >=, <>
  • Négation
    • NOT
expression operateur_comparaison expression

Combiner des prédicats

  • OU logique
    • predicat OR predicat
  • ET logique
    • predicat AND predicat

Correspondance de motif

  • Comparaison de motif
    chaine LIKE motif ESCAPE 'c'
  • % : toute chaîne de 0 à plusieurs caractères
    • _ : un seul caractère
  • Expression régulière POSIX
    chaine ~ motif

Listes et intervalles

  • Liste de valeurs
    expression IN (valeur1 [, ...])
  • Chevauchement d’intervalle de valeurs
    expression BETWEEN expression AND expression
  • Chevauchement d’intervalle de dates
    (date1, date2) OVERLAPS (date3, date4)

Tris

  • SQL ne garantit pas l’ordre des résultats
    • tri explicite requis
  • Tris des lignes selon des expressions
    ORDER BY expression  [ ASC | DESC | USING opérateur ]
                         [ NULLS { FIRST | LAST } ] [, ...]
  • ordre du tri : ASC ou DESC
    • placement des valeurs NULL : NULLS FIRST ou NULLS LAST
    • ordre de tri des caractères : COLLATE collation

Limiter le résultat

  • Obtenir des résultats à partir de la ligne n
    • OFFSET n
  • Limiter le nombre de lignes à n lignes
    • FETCH {FIRST | NEXT} n ROWS ONLY
    • LIMIT n
  • Opérations combinables
    • OFFSET doit apparaitre avant FETCH
  • Peu d’intérêt sur des résultats non triés

Utiliser plusieurs tables

  • Clause FROM
    • liste de tables séparées par ,
  • Une table est combinée avec une autre
    • jointure
    • produit cartésien

Types de données

  • Type de données
    • du standard SQL
    • certains spécifiques PostgreSQL

Qu’est-ce qu’un type de données ?

  • Le système de typage valide les données
  • Un type détermine
    • les valeurs possibles
    • comment les données sont stockées
    • les opérations que l’on peut appliquer

Types de données

  • Types standards SQL
  • Types dérivés
  • Types spécifiques à PostgreSQL
  • Types utilisateurs

Types standards (1)

  • Caractère
    • char, varchar
  • Numérique
    • integer, smallint, bigint
    • real, double precision
    • numeric, decimal
  • Booléen
    • boolean

Types standards (2)

  • Temporel
    • date, time
    • timestamp
    • interval
  • Chaînes de bit
    • bit, bit varying
  • Formats validés
    • JSON
    • XML

Caractères

  • char(n)
    • longueur fixe
    • de n caractères
    • complété à droite par des espaces si nécessaire
  • varchar(n)
    • longueur variable
    • maximum n caractères
    • n optionnel

Représentation données caractères

  • Norme SQL
    • chaîne encadrée par '
    • 'chaîne de caractères'
  • Chaînes avec échappement du style C
    • chaîne précédée par E ou e
    • E'chaîne de caractères'
  • Chaînes avec échappement Unicode
    • chaîne précédée par U&
    • U&'chaîne de caractères'

Numériques

  • Entier
    • smallint, integer, bigint
    • signés
  • Virgule flottante
    • real, double precision
    • valeurs inexactes
  • Précision arbitraire
    • numeric(precision, echelle), decimal(precision, echelle)
    • valeurs exactes

Représentation de données numériques

  • Chiffres décimaux : 0 à 9
  • Séparateur décimal : .
  • chiffres
  • chiffres.[chiffres][e[+-]chiffres]
  • [chiffres].chiffres[e[+-]chiffres]
  • chiffrese[+-]chiffres
  • Conversion
    • TYPE 'chaine'

Booléens

  • boolean
  • 3 valeurs possibles
    • TRUE
    • FALSE
    • NULL (ie valeur absente)

Temporel

  • Date
    • date
  • Heure
    • time
    • avec ou sans fuseau horaire
  • Date et heure
    • timestamp
    • avec ou sans fuseau horaire
  • Intervalle de temps
    • interval

Représentation des données temporelles

  • Conversion explicite
    • TYPE 'chaine'
  • Format d’un timestamp
    • 'YYYY-MM-DD HH24:MI:SS.ssssss'
    • 'YYYY-MM-DD HH24:MI:SS.ssssss+fuseau'
    • 'YYYY-MM-DD HH24:MI:SS.ssssss' AT TIME ZONE 'fuseau'
  • Format d’un intervalle
    • INTERVAL 'durée interval'

Gestion des fuseaux horaires

  • Paramètre timezone
  • Session : SET TIME ZONE
  • Expression d’un fuseau horaire
    • nom complet : 'Europe/Paris'
    • nom abbrégé : 'CEST'
    • décalage : '+02'

Chaînes de bits

  • Chaînes de bits
    • bit(n), bit varying(n)

Représentation des chaînes de bits

  • Représentation binaire
    • chaîne de caractères précédée de la lettre B
    • B'01010101'
  • Représentation hexadécimale
    • chaîne de caractères précédée de la lettre X
    • X'55'

XML

  • Type validé
    • xml
  • Chaîne de caractères
    • validation du document XML

JSON

  • Type json : texte, avec validation du format JSON
  • Préférer le type jsonb (binaire)
  • Fonctions de manipulation

Types dérivés

  • Types spécifiques à PostgreSQL
  • Incrémentés:
    • principe de l’« autoincrement »
    • serial
    • smallserial
    • bigserial
    • équivalent à un type entier associé à une séquence et avec une valeur par défaut
    • (v 10+) préférer un type entier + la propriété IDENTITY
  • Caractères
    • text

Types additionnels non SQL

  • bytea
  • array
  • enum
  • cidr, inet, macaddr
  • uuid
  • json, jsonb, hstore
  • range

Types utilisateurs

  • Types utilisateurs
    • composites
    • énumérés (enum)
    • intervalles (range)
    • scalaires
    • tableau
    CREATE TYPE

Conclusion

  • SQL : traitement d’ensembles d’enregistrements
  • Pour les lectures : SELECT
  • Nom des objets en minuscules
  • Des types de données simples et d’autres plus complexes

Bibliographie

  • Bases de données - de la modélisation au SQL (Laurent Audibert)
  • SQL avancé : programmation et techniques avancées (Joe Celko)
  • SQL : Au coeur des performances (Markus Winand)
  • The Manga Guide to Databases (Takahashi, Mana, Azuma, Shoko)
  • The Art of SQL (Stéphane Faroult)

Questions

N’hésitez pas, c’est le moment !

Travaux pratiques

Travaux pratiques (solutions)

Création d’objet et mises à jour

Introduction

  • DDL, gérer les objets
  • DML, écrire des données
  • Gérer les transactions
  • DDL (Data Definition Language)
  • DML (Data Manipulation Language)
  • TCL (Transaction Control Language)

Objectifs

  • Savoir créer, modifier et supprimer des objets
  • Savoir utiliser les contraintes d’intégrité
  • Savoir mettre à jour les données
  • Savoir utiliser les transactions

DDL

  • DDL
    • Data Definition Language
    • langage de définition de données
  • Permet de créer des objets dans la base de données

Objets d’une base de données

  • Objets définis par la norme SQL :
    • schémas
    • séquences
    • tables
    • contraintes
    • domaines
    • vues
    • fonctions
    • triggers

Créer des objets

  • Ordre CREATE
  • Syntaxe spécifique au type d’objet
  • Exemple :
CREATE SCHEMA s1;

Modifier des objets

  • Ordre ALTER
  • Syntaxe spécifique pour modifier la définition d’un objet, exemple:
  • Renommage
    ALTER type_objet ancien_nom RENAME TO nouveau_nom ;
  • changement de propriétaire
    ALTER type_objet nom_objet OWNER TO proprietaire ;
  • changement de schéma
    ALTER type_objet nom_objet SET SCHEMA nom_schema ;

Supprimer des objets

  • Ordre DROP
  • Exemples :
    • supprimer un objet :
    DROP type_objet nom_objet ;
    • supprimer un objet et ses dépendances :
    DROP type_objet nom_objet CASCADE ;

Schéma

  • Identique à un espace de nommage
  • Permet d’organiser les tables de façon logique
  • Possibilité d’avoir des objets de même nom dans des schémas différents
  • Pas d’imbrication (contrairement à des répertoires par exemple)
  • Schéma public
    • créé par défaut dans une base
    • souvent supprimé pour la sécurité

Gestion d’un schéma

  • CREATE SCHEMA nom_schéma
  • ALTER SCHEMA nom_schéma
    • renommage
    • changement de propriétaire
  • DROP SCHEMA [ IF EXISTS ] nom_schéma [ CASCADE ]

Accès aux objets

  • Nommage explicite
    • nom_schema.nom_objet
  • Chemin de recherche de schéma
    • paramètre search_path
    • SET search_path = schema1,schema2,public;
    • par défaut : $user, public

Séquences

  • Séquence
    • génère une séquence de nombres
  • Paramètres
    • valeur minimale MINVALUE
    • valeur maximale MAXVALUE
    • valeur de départ START
    • incrément INCREMENT
    • cache CACHE
    • cycle autorisé CYCLE

Création d’une séquence

CREATE SEQUENCE nom [ INCREMENT incrément ]
    [ MINVALUE valeurmin | NO MINVALUE ]
    [ MAXVALUE valeurmax | NO MAXVALUE ]
    [ START [ WITH ] début ]
    [ CACHE cache ]
    [ [ NO ] CYCLE ]
    [ OWNED BY { nom_table.nom_colonne | NONE } ]

Modification d’une séquence

ALTER SEQUENCE nom [ INCREMENT increment ]
    [ MINVALUE valeurmin | NO MINVALUE ]
    [ MAXVALUE valeurmax | NO MAXVALUE ]
    [ START [ WITH ] début ]
    [ RESTART [ [ WITH ] nouveau_début ] ]
    [ CACHE cache ] [ [ NO ] CYCLE ]
    [ OWNED BY { nom_table.nom_colonne | NONE } ]
  • Il est aussi possible de modifier
    • le propriétaire
    • le schéma

Suppression d’une séquence

DROP SEQUENCE nom [, ...]

Séquences, utilisation

  • Obtenir la valeur suivante
    • nextval('nom_sequence')
  • Obtenir la valeur courante
    • currval('nom_sequence')
    • mais nextval() doit être appelé avant dans la même session

Type SERIAL

  • Type serial/bigserial/smallserial
    • séquence générée automatiquement
    • valeur par défaut nextval(...)
  • Préférer un entier avec IDENTITY

Domaines

  • Permet d’associer
    • un type standard
    • et une contrainte (optionnelle)

Tables

  • Équivalent ensembliste d’une relation
  • Composé principalement de
    • colonnes ordonnées
    • contraintes

Création d’une table

  • Définition de son nom
  • Définition de ses colonnes
    • nom, type, contraintes éventuelles
  • Clauses de stockage
  • CREATE TABLE

CREATE TABLE

CREATE TABLE nom_table (
  definition_colonnes
  definition_contraintes
) clause_stockage;

Définition des colonnes

nom_colonne type [ COLLATE collation ] [ contrainte ]
[, ...]

Valeur par défaut

  • DEFAULT
    • affectation implicite
  • Utiliser directement par les types sériés

Copie de la définition d’une table

  • Création d’une table à partir d’une autre table
    • CREATE TABLE ... (LIKE table clause_inclusion)
  • Avec les valeurs par défaut des colonnes :
    • INCLUDING DEFAULTS
  • Avec ses autres contraintes :
    • INCLUDING CONSTRAINTS
  • Avec ses index :
    • INCLUDING INDEXES

Modification d’une table

  • ALTER TABLE
  • Définition de la table
    • renommage de la table
    • ajout/modification/suppression d’une colonne
    • déplacement dans un schéma différent
    • changement du propriétaire
  • Définition des colonnes
    • renommage d’une colonne
    • changement de type d’une colonne
  • Définition des contraintes
    • ajout/suppression d’une contrainte

Conséquences des modifications d’une table

  • contention avec les verrous
  • vérification des données
  • performance avec une possible réécriture de la table

Suppression d’une table

  • Supprimer une table :
    DROP TABLE nom_table;
  • Supprimer une table et tous les objets dépendants :
    DROP TABLE nom_table CASCADE;

Contraintes d’intégrité

  • ACID
    • Cohérence
    • une transaction amène la base d’un état stable à un autre
  • Assurent la cohérence des données
    • unicité des enregistrements
    • intégrité référentielle
    • vérification des valeurs
    • identité des enregistrements
    • règles sémantiques

Clé primaire d’une table

  • Identifie une ligne de manière unique
  • Une seule clé primaire par table
  • Une ou plusieurs colonnes
  • À choisir parmi les clés candidates
    • clé naturelle ou artificielle (technique, invisible)
    • les autres clés possibles peuvent être UNIQUE

Déclaration d’une clé primaire

Construction :

[CONSTRAINT nom_contrainte]
PRIMARY KEY ( nom_colonne [, ... ] )
  • Séquence
  • serial
  • GENERATED ALWAYS BY IDENTITY
  • UUID

Contrainte d’unicité

  • Garantit l’unicité des valeurs d’une ou plusieurs colonnes
  • Permet plusieurs valeurs NULL
    • en v15, possibilité de modifier ce comportement
  • Clause UNIQUE
  • Contrainte UNIQUE != index UNIQUE

Déclaration d’une contrainte d’unicité

Construction :

[ CONSTRAINT nom_contrainte]
{ UNIQUE { NULLS NOT DISTINCT } ( nom_colonne [, ... ] )

Intégrité référentielle

  • Contrainte d’intégrité référentielle
    • ou Clé étrangère
  • Référence une clé primaire ou un groupe de colonnes UNIQUE et NOT NULL
  • Garantie l’intégrité des données
  • FOREIGN KEY

Déclaration d’une clé étrangère

[ CONSTRAINT nom_contrainte ] FOREIGN KEY ( nom_colonne [, ...] )
    REFERENCES table_reference [ (colonne_reference [, ... ] ) ]
    [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ]
    [ ON DELETE action ] [ ON UPDATE action ] }

Vérification simple ou complète

  • Vérification complète ou partielle d’une clé étrangère
  • MATCH
    • MATCH FULL (complète)
    • MATCH SIMPLE (partielle)

Clé primaire et colonne identité

  • Identité d’un enregistrement
  • GENERATED … AS IDENTITY
    • ALWAYS
    • BY DEFAULT
  • Préférer à serial
  • Unicité non garantie sans contrainte explicite !

Mise à jour de la clé primaire

  • Que faire en cas de mise à jour d’une clé primaire ?
    • les clés étrangères seront fausses
  • ON UPDATE
  • ON DELETE
  • Définition d’une action au niveau de la clé étrangère
    • interdiction
    • propagation de la mise à jour
    • NULL
    • valeur par défaut

Vérifications

  • Présence d’une valeur
    • NOT NULL
  • Vérification de la valeur d’une colonne
    • CHECK

Vérifications différés

  • Vérifications après chaque ordre SQL
    • problèmes de cohérence
  • Différer les vérifications de contraintes
    • clause DEFERRABLE, NOT DEFERRABLE
    • INITIALLY DEFERED, INITIALLY IMMEDIATE

Vérifications plus complexes

  • Un trigger
    • si une contrainte porte sur plusieurs tables
    • si sa vérification nécessite une sous-requête
  • Préférer les contraintes déclaratives

Colonnes par défaut et générées

CREATE TABLE paquet (
  code       text          PRIMARY KEY,
  reception  timestamptz   DEFAULT now(),
  livraison  timestamptz   DEFAULT now() + interval '3d',
  largeur    int,    longueur int,   profondeur int,
  volume     int
      GENERATED ALWAYS AS ( largeur * longueur * profondeur )
      STORED    CHECK (volume > 0.0)
  ) ;
  • DEFAULT : expressions très simples, modifiables
  • GENERATED
    • fonctions « immutables », ne dépendant que de la ligne
    • difficilement modifiables
    • peuvent porter des contraintes

DML : mise à jour des données

  • SELECT peut lire les données d’une table ou plusieurs tables
    • mais ne peut pas les mettre à jour
  • Ajout de données dans une table
    • INSERT
  • Modification des données d’une table
    • UPDATE
  • Suppression des données d’une table
    • DELETE

Ajout de données : INSERT

  • Ajoute des lignes à partir des données de la requête
  • Ajoute des lignes à partir d’une requête SELECT
  • Syntaxe :
INSERT INTO nom_table [ ( nom_colonne [, ...] ) ]
    { liste_valeurs | requete }

INSERT avec liste d’expressions

INSERT INTO nom_table [ ( nom_colonne [, ...] ) ]
    VALUES ( { expression | DEFAULT } [, ...] ) [, ...]

INSERT à partir d’un SELECT

INSERT INTO nom_table [ ( nom_colonne [, ...] ) ]
    requête

INSERT et colonnes implicites

  • L’ordre physique peut changer dans le temps
    • résultats incohérents
    • requêtes en erreurs

Mise à jour de données : UPDATE

  • Ordre UPDATE
  • Met à jour une ou plusieurs colonnes d’une même ligne
    • à partir des valeurs de la requête
    • à partir des anciennes valeurs
    • à partir d’une requête SELECT
    • à partir de valeurs d’une autre table

Construction d’UPDATE

UPDATE nom_table
    SET
    {
     nom_colonne = { expression | DEFAULT }
    |
     ( nom_colonne [, ...] ) = ( { expression | DEFAULT } [, ...] )
    } [, ...]
    [ FROM liste_from ]
    [ WHERE condition | WHERE CURRENT OF nom_curseur ]

Suppression de données : DELETE

  • Supprime les lignes répondant au prédicat
  • Syntaxe :
DELETE FROM nom_table [ [ AS ] alias ]
    [ WHERE condition

Clause RETURNING

  • Spécifique à PostgreSQL
  • Permet de retourner les lignes complètes ou partielles résultants de INSERT, UPDATE ou DELETE
  • Syntaxe :
requete_sql RETURNING ( * | expression )

Transactions

  • ACID
    • Atomicité
    • un traitement se fait en entier ou pas du tout
  • TCL pour Transaction Control Language
    • valide une transaction
    • annule une transaction
    • points de sauvegarde

Auto-commit et transactions

  • Par défaut, PostgreSQL fonctionne en auto-commit
    • à moins d’ouvrir explicitement une transaction
  • Ouvrir une transaction
    • BEGIN TRANSACTION

Validation ou annulation d’une transaction

  • Valider une transaction
    • COMMIT
  • Annuler une transaction
    • ROLLBACK
  • Sans validation, une transaction est forcément annulée

Programmation

  • Certains langages implémentent des méthodes de gestion des transactions
    • PHP, Java, etc.
  • Utiliser ces méthodes prioritairement

Points de sauvegarde

  • Certains traitements dans une transaction peuvent être annulés
    • mais la transaction est atomique
  • Définir un point de sauvegarde
    • SAVEPOINT nom_savepoint
  • Valider le traitement depuis le dernier point de sauvegarde
    • RELEASE SAVEPOINT nom_savepoint
  • Annuler le traitement depuis le dernier point de sauvegarde
    • ROLLBACK TO SAVEPOINT nom_savepoint

Conclusion

  • SQL : toujours un traitement d’ensembles d’enregistrements
    • c’est le côté relationnel
  • Pour les définitions d’objets
    • CREATE, ALTER, DROP
  • Pour les données
    • INSERT, UPDATE, DELETE

Questions

N’hésitez pas, c’est le moment !

Travaux pratiques

Travaux pratiques (solutions)

Plus loin avec SQL

Préambule

  • Après la définition des objets, leur lecture et leur écriture
  • Aller plus loin dans l’écriture de requêtes avec :
    • les jointures
    • les sous-requêtes
    • les vues
    • les fonctions
  • Valeur NULL
  • Agrégats, GROUP BY, HAVING
  • Sous-requêtes
  • Jointures
  • Expression conditionnelle CASE
  • Opérateurs ensemblistes : UNION, EXCEPT, INTERSECT
  • Fonctions de base
  • Vues
  • Requêtes préparées

Objectifs

  • Comprendre l’intérêt du NULL
  • Savoir écrire des requêtes complexes

Valeur NULL

  • Comment représenter une valeur que l’on ne connaît pas ?
    • valeur NULL
  • Trois sens possibles pour NULL :
    • valeur inconnue
    • valeur inapplicable
    • absence de valeur
  • Logique 3 états

Avertissement

  • Chris J. Date a écrit :
    • La valeur NULL telle qu’elle est implémentée dans SQL peut poser plus de problèmes qu’elle n’en résout. Son comportement est parfois étrange et est source de nombreuses erreurs et de confusions.
  • Éviter d’utiliser NULL le plus possible
    • utiliser NULL correctement lorsqu’il le faut

Assignation de NULL

  • Assignation de NULL pour INSERT et UPDATE
  • Explicitement :
    • NULL est indiqué explicitement dans les assignations
  • Implicitement :
    • la colonne n’est pas affectée par INSERT
    • et n’a pas de valeur par défaut
  • Empêcher la valeur NULL
    • contrainte NOT NULL

Calculs avec NULL

  • Utilisation dans un calcul
    • propagation de NULL
  • NULL est inapplicable
    • le résultat vaut NULL

NULL et les prédicats

  • Dans un prédicat du WHERE :
    • opérateur IS NULL ou IS NOT NULL
  • AND :
    • vaut false si NULL AND false
    • vaut NULL si NULL AND true ou NULL AND NULL
  • OR :
    • vaut true si NULL OR true
    • vaut NULL si NULL OR false ou NULL OR NULL

NULL et les agrégats

  • Opérateurs d’agrégats
    • ignorent NULL
    • sauf count(*)

COALESCE

  • Remplacer NULL par une autre valeur
    • COALESCE(attribut, ...);

Agrégats

  • Regroupement de données
  • Calculs d’agrégats

Regroupement de données

  • Regroupement de données : sql GROUP BY expression [, ...]
  • Chaque groupe de données est ensuite représenté sur une seule ligne
  • Permet d’appliquer des calculs sur les ensembles regroupés
    • comptage, somme, moyenne, etc.

Calculs d’agrégats

  • Effectuent un calcul sur un ensemble de valeurs
    • somme, moyenne, etc.
  • Retournent NULL si l’ensemble est vide
    • sauf count()

Agrégats simples

  • Comptage : sql count(expression)
  • compte les lignes : count(*)
    • compte les valeurs renseignées : count(colonne)
  • Valeur minimale : sql min(expression)
  • Valeur maximale : sql max(expression)

Calculs d’agrégats

  • Moyenne : sql avg(expression)
  • Somme : sql sum(expression)
  • Écart-type : sql stddev(expression)
  • Variance : sql variance(expression)

Agrégats sur plusieurs colonnes

  • Possible d’avoir plusieurs paramètres sur la même fonction d’agrégat
  • Quelques exemples
    • pente : regr_slope(Y,X)
    • intersection avec l’axe des ordonnées : regr_intercept(Y,X)
    • indice de corrélation : corr (Y,X)

Clause HAVING

  • Filtrer sur des regroupements
    • HAVING
  • WHERE s’applique sur les lignes lues
  • HAVING s’applique sur les lignes groupées

Sous-requêtes

  • Corrélation requête/sous-requête
  • Sous-requêtes retournant une seule ligne
  • Sous-requêtes retournant une liste de valeur
  • Sous-requêtes retournant un ensemble
  • Sous-requêtes retournant un ensemble vide ou non-vide

Corrélation requête/sous-requête

  • Fait référence à la requête principale
  • Peut utiliser une valeur issue de la requête principale

Qu’est-ce qu’une sous-requête ?

  • Une requête imbriquée dans une autre requête
  • Le résultat de la requête principale dépend du résultat de la sous-requête
  • Encadrée par des parenthèses : ( et )

Utiliser une seule ligne

  • La sous-requête ne retourne qu’une seule ligne
    • sinon une erreur est levée
  • Positionnée
    • au niveau de la liste des expressions retournées par SELECT
    • au niveau de la clause WHERE
    • au niveau d’une clause HAVING

Utiliser une liste de valeurs

  • La sous-requête retourne
    • plusieurs lignes
    • sur une seule colonne
  • Positionnée
    • avec une clause IN
    • avec une clause ANY
    • avec une clause ALL

Clause IN

expression IN (sous-requete)
  • L’expression de gauche est évaluée et vérifiée avec la liste de valeurs de droite
  • IN vaut true
    • si l’expression de gauche correspond à un élément de la liste de droite
  • IN vaut false
    • si aucune correspondance n’est trouvée et la liste ne contient pas NULL
  • IN vaut NULL
    • si l’expression de gauche vaut NULL
    • si aucune valeur ne correspond et la liste contient NULL

Clause NOT IN

expression NOT IN (sous-requete)
  • L’expression de droite est évaluée et vérifiée avec la liste de valeurs de gauche
  • NOT IN vaut true
    • si aucune correspondance n’est trouvée et la liste ne contient pas NULL
  • NOT IN vaut false
    • si l’expression de gauche correspond à un élément de la liste de droite
  • NOT IN vaut NULL
    • si l’expression de gauche vaut NULL
    • si aucune valeur ne correspond et la liste contient NULL

Clause ANY

expression operateur ANY (sous-requete)
  • L’expression de gauche est comparée au résultat de la sous-requête avec l’opérateur donné
  • La ligne de gauche est retournée
    • si le résultat d’au moins une comparaison est vraie
  • La ligne de gauche n’est pas retournée
    • si aucun résultat de la comparaison n’est vrai
    • si l’expression de gauche vaut NULL
    • si la sous-requête ramène un ensemble vide

Clause ALL

expression operateur ALL (sous-requete)
  • L’expression de gauche est comparée à tous les résultats de la sous-requête avec l’opérateur donné
  • La ligne de gauche est retournée
    • si tous les résultats des comparaisons sont vrais
    • si la sous-requête retourne un ensemble vide
  • La ligne de gauche n’est pas retournée
    • si au moins une comparaison est fausse
    • si au moins une comparaison est NULL

Utiliser un ensemble

  • La sous-requête retourne
    • plusieurs lignes
    • sur plusieurs colonnes
  • Positionnée au niveau de la clause FROM
  • Nommée avec un alias de table

Clause EXISTS

EXISTS (sous-requete)
  • Intéressant avec une corrélation
  • La clause EXISTS vérifie la présence ou l’absence de résultats
    • vrai si l’ensemble est non vide
    • faux si l’ensemble est vide

Jointures

  • Conditions de jointure dans JOIN ou dans WHERE ?
  • Produit cartésien
  • Jointure interne
  • Jointures externes
  • Jointure ou sous-requête ?

Conditions de jointure dans JOIN ou dans WHERE ?

  • Jointure dans clause JOIN
    • séparation nette jointure et filtrage
    • plus lisible et maintenable
    • jointures externes propres
    • facilite le travail de l’optimiseur
  • Jointure dans clause WHERE
    • uistorique

Produit cartésien

  • Clause CROSS JOIN
  • Réalise toutes les combinaisons entre les lignes d’une table et les lignes d’une autre
  • À éviter dans la mesure du possible
    • peu de cas d’utilisation
    • peu performant

Jointure interne

  • Clause INNER JOIN
    • meilleure lisibilité
    • facilite le travail de l’optimiseur
  • Joint deux tables entre elles
    • Selon une condition de jointure
Schéma de jointure interne

Syntaxe d’une jointure interne

  • Condition de jointure par prédicats : sql table1 [INNER] JOIN table2 ON prédicat [...]
  • Condition de jointure implicite par liste des colonnes impliquées : sql table1 [INNER] JOIN table2 USING (colonne [, ...])
  • Liste des colonnes de même nom (dangereux) : sql table1 NATURAL [INNER] JOIN table2

Jointure externe

  • Jointure externe à gauche
    • ramène le résultat de la jointure interne
    • ramène l’ensemble de la table de gauche qui ne peut être joint avec la table de droite
    • les attributs de la table de droite sont alors NULL
Schéma de jointure externe gauche

Jointure externe - 2

  • Jointure externe à droite
    • ramène le résultat de la jointure interne
    • ramène l’ensemble de la table de droite qui ne peut être joint avec la table de gauche
    • les attributs de la table de gauche sont alors NULL
Schéma de jointure externe droite

Jointure externe complète

  • Ramène le résultat de la jointure interne
  • Ramène l’ensemble de la table de gauche qui ne peut être joint avec la table de droite
    • les attributs de la table de droite sont alors NULL
  • Ramène l’ensemble de la table de droite qui ne peut être joint avec la table de gauche
    • les attributs de la table de gauche sont alors NULL

Syntaxe d’une jointure externe à gauche

  • Condition de jointure par prédicats : sql table1 LEFT [OUTER] JOIN table2 ON prédicat [...]
  • Condition de jointure implicite par liste des colonnes impliquées : sql table1 LEFT [OUTER] JOIN table2 USING (colonne [, ...])
  • Liste des colonnes implicites : sql table1 NATURAL LEFT [OUTER] JOIN table2

Syntaxe d’une jointure externe à droite

  • Condition de jointure par prédicats : sql table1 RIGHT [OUTER] JOIN table2 ON prédicat [...]
  • Condition de jointure implicite par liste des colonnes impliquées : sql table1 RIGHT [OUTER] JOIN table2 USING (colonne [, ...])
  • Liste des colonnes implicites : sql table1 NATURAL RIGHT [OUTER] JOIN table2

Syntaxe d’une jointure externe complète

  • Condition de jointure par prédicats : sql table1 FULL OUTER JOIN table2 ON prédicat [...]
  • Condition de jointure implicite par liste des colonnes impliquées : sql table1 FULL OUTER JOIN table2 USING (colonne [, ...])
  • Liste des colonnes implicites : sql table1 NATURAL FULL OUTER JOIN table2

Jointure ou sous-requête ?

  • Jointures
    • algorithmes très efficaces
    • ne gèrent pas tous les cas
  • Sous-requêtes
    • parfois peu performantes
    • répondent à des besoins non couverts par les jointures

Expressions CASE

  • Équivalent à l’instruction switch en C ou Java
  • Emprunté au langage Ada
  • Retourne une valeur en fonction du résultat de tests

CASE simple

CASE expression
     WHEN valeur THEN expression
     WHEN valeur THEN expression
     (...)
     ELSE expression
 END

CASE sur expressions

CASE WHEN expression THEN expression
     WHEN expression THEN expression
     (...)
     ELSE expression
 END

Spécificités de CASE

  • Comportement procédural
    • les expressions sont évaluées dans l’ordre d’apparition
  • Transtypage
    • le type du retour de l’expression dépend du type de rang le plus élevé de toute l’expression
  • Imbrication
    • des expressions CASE à l’intérieur d’autres expressions CASE
  • Clause ELSE
    • recommandé

Opérateurs ensemblistes

  • UNION
  • INTERSECT
  • EXCEPT

Regroupement de deux ensembles

  • Regroupement avec dédoublonnage :
requete_select1 UNION requete_select2
  • Regroupement sans dédoublonnage :
requete_select1 UNION ALL requete_select2

Intersection de deux ensembles

  • Intersection de deux ensembles avec dédoublonnage :
requete_select1 INTERSECT requete_select2
  • Intersection de deux ensembles sans dédoublonnage :
requete_select1 INTERSECT ALL requete_select2

Différence entre deux ensembles

  • Différence entre deux ensembles avec dédoublonnage :
requete_select1 EXCEPT requete_select2
  • Différence entre deux ensembles sans dédoublonnage :
requete_select1 EXCEPT ALL requete_select2

Fonctions de base

  • Transtypage
  • Manipulation de chaines
  • Manipulation de types numériques
  • Manipulation de dates
  • Génération de jeu de données

Transtypage

  • Conversion d’un type de données vers un autre type de données
  • CAST (expression AS type)
  • expression::type

Opérations simples sur les chaînes

  • Concaténation : chaîne1 || chaîne2
  • Longueur de la chaîne : char_length(chaîne)
  • Conversion en minuscules : lower(chaîne)
  • Conversion en majuscules : upper(chaîne)

Manipulations de chaînes

  • Extrait une chaîne à partir d’une autre : substring(chaîne [from int] [for int])
  • Emplacement d’une sous-chaîne : position(sous-chaîne in chaîne)

Manipulation de types numériques

  • Opérations arithmétiques
  • Manipulation de types numériques
  • Génération de données

Opérations arithmétiques

  • Addition : +
  • Soustraction : -
  • Multiplication : *
  • Division : /
    • entière si implique des entiers !
  • Reste (modulo) : %

Fonctions numériques courantes

  • Arrondi : round(numeric)

  • Troncature : trunc(numeric [, precision])

  • Entier le plus petit : floor(numeric)

  • Entier le plus grand : ceil(numeric)

Génération de données

  • Générer une suite d’entiers : generate_series(borne_debut, borne_fin, intervalle)

  • Générer un nombre aléatoire : random()

Manipulation de dates

  • Obtenir la date et l’heure courante
  • Manipuler des dates
  • Opérations arithmétiques
  • Formatage de données

Date et heure courante

  • Retourne la date courante : current_date
  • Retourne l’heure courante : current_time
  • Retourne la date et l’heure courante : current_timestamp / now()

Manipulation des données

  • Âge
    • Par rapport à la date courante : age(timestamp)
    • Par rapport à une date de référence : age(timestamp, timestamp)

Tronquer et extraire

  • Troncature d’une date : date_trunc(text, timestamp)
  • Exemple : date_trunc('month' from date_naissance)
  • Extrait une composante de la date : extract(text, timestamp)
  • Exemple : extract('year' from date_naissance)

Arithmétique sur les dates

  • Opérations arithmétiques sur timestamp, time ou date
    • date/time - date/time = interval
    • date/time + time = date/time
    • date/time + interval = date/time
  • Opérations arithmétiques sur interval
    • interval * numeric = interval
    • interval / numeric = interval
    • interval + interval = interval

Date vers chaîne

  • Conversion d’une date en chaîne de caractères : to_char(timestamp, text)
  • Exemple : to_char(current_timestamp, 'DD/MM/YYYY HH24:MI:SS')

Chaîne vers date

  • Conversion d’une chaîne de caractères en date : to_date(text, text) to_date('05/12/2000', 'DD/MM/YYYY')
  • Conversion d’une chaîne de caractères en timestamp : to_timestamp(text, text) to_timestamp('05/12/2000 12:00:00', 'DD/MM/YYYY HH24:MI:SS')
  • Paramètre datestyle

Génération de données

  • Générer une suite de timestamp :
    • generate_series (timestamp_debut, timestamp_fin, intervalle)

Vues

  • Tables virtuelles
    • définies par une requête SELECT
    • définition stockée dans le catalogue de la base de données
  • Objectifs
    • masquer la complexité d’une requête
    • masquer certaines données à l’utilisateur
  • Vues ≠ vues matérialisées

Création d’une vue

  • Une vue porte un nom au même titre qu’une table
    • elle sera nommée avec les mêmes règles
  • Ordre de création d’une vue : CREATE VIEW vue (colonne ...) AS SELECT ...

Lecture d’une vue

  • Une vue est lue comme une table
    • SELECT * FROM vue;

Sécurisation d’une vue

  • Sécuriser une vue
    • droits avec GRANT et REVOKE
  • Utiliser les vues comme moyen de filtrer les lignes est dangereux
    • option security_barrier

Mise à jour des vues

  • Updatable view
  • WITH CHECK OPTION
  • Mises à jour non triviales : trigger INSTEAD OF

Mauvaises utilisations des vues

  • Prolifération des vues
    • créer une vue doit se justifier
    • ne pas créer une vue par table
  • Vues trop complexes utilisées comme interface
  • Vues empilées

Requêtes préparées

  • Exécution en deux temps
    • préparation du plan d’exécution de la requête
    • exécution de la requête en utilisant le plan préparé
  • Objectif :
    • éviter simplement les injections SQL
    • améliorer les performances

Utilisation

  • PREPARE, préparation du plan d’exécution d’une requête
  • EXECUTE, passage des paramètres de la requête et exécution réelle
  • L’implémentation dépend beaucoup du langage de programmation utilisé
    • le connecteur JDBC supporte les requêtes préparées
    • le connecteur PHP/PDO également

Conclusion

  • Possibilité d’écrire des requêtes complexes
  • C’est là où PostgreSQL est le plus performant

Questions

N’hésitez pas, c’est le moment !

Travaux pratiques

TP 1

TP 2

Travaux pratiques (solutions)

TP 1

TP 2

SQL avancé pour le transactionnel

Préambule

  • SQL et PostgreSQL proposent de nombreuses possibilités avancées
    • normes SQL:99, 2003, 2008 et 2011
    • parfois, extensions propres à PostgreSQL
  • LIMIT/OFFSET
  • Jointures LATERAL
  • UPSERT : INSERT ou UPDATE
  • Common Table Expressions
  • Serializable Snapshot Isolation

Objectifs

  • Aller au-delà de SQL:92
  • Concevoir des requêtes simples pour résoudre des problèmes complexes

LIMIT

  • Clause LIMIT
  • ou syntaxe en norme SQL : FETCH FIRST xx ROWS
  • Utilisation :
    • limite le nombre de lignes du résultat

LIMIT : exemple

SELECT *
  FROM employes
LIMIT 2;
 matricule |   nom    | service  | salaire
-----------+----------+----------+----------
 00000001  | Dupuis   |          | 10000.00
 00000004  | Fantasio | Courrier |  4500.00
(2 lignes)

OFFSET

  • Clause OFFSET
    • à utiliser avec LIMIT
  • Utilité :
    • pagination de résultat
    • sauter les n premières lignes avant d’afficher le résultat

OFFSET : exemple (1/2)

  • Sans offset :
SELECT *
  FROM employes
 LIMIT 2
 ORDER BY matricule;
 matricule |   nom    | service  | salaire
-----------+----------+----------+----------
 00000001  | Dupuis   |          | 10000.00
 00000004  | Fantasio | Courrier |  4500.00

OFFSET : exemple (2/2)

  • En sautant les deux premières lignes :
SELECT *
  FROM employes
 ORDER BY matricule
 LIMIT 2
 OFFSET 2;
 matricule |   nom    |   service   | salaire
-----------+----------+-------------+---------
 00000006  | Prunelle | Publication | 4000.00
 00000020  | Lagaffe  | Courrier    | 3000.00

OFFSET : problèmes

  • OFFSET est problématique
    • beaucoup de données lues
    • temps de réponse dégradés
  • Alternative possible
    • utilisation d’un index sur le critère de tri
    • critère de filtrage sur la page précédente
  • Article sur le sujet

RETURNING

  • Clause RETURNING
  • Utilité :
    • récupérer les enregistrements modifiés
    • avec INSERT
    • avec UPDATE
    • avec DELETE

RETURNING : exemple

CREATE TABLE test_returning (id serial primary key, val integer);

INSERT INTO test_returning (val)
  VALUES (10)
RETURNING id, val;

 id | val
----+-----
  1 |  10
(1 ligne)

UPSERT

  • INSERT ou UPDATE ?
    • INSERT ... ON CONFLICT DO { NOTHING | UPDATE }
    • à partir de la version 9.5
  • Utilité :
    • mettre à jour en cas de conflit sur un INSERT
    • ne rien faire en cas de conflit sur un INSERT

UPSERT : problème à résoudre

  • Insérer une ligne déjà existante provoque une erreur :
INSERT INTO employes (matricule, nom, service, salaire)
 VALUES ('00000001', 'Marsupilami', 'Direction', 50000.00);
ERROR:  duplicate key value violates unique constraint
        "employes_pkey"
DETAIL:  Key (matricule)=(00000001) already exists.

ON CONFLICT DO NOTHING

  • la clause ON CONFLICT DO NOTHING évite d’insérer une ligne existante :
INSERT INTO employes (matricule, nom, service, salaire)
   VALUES ('00000001', 'Marsupilami', 'Direction', 50000.00)
   ON CONFLICT DO NOTHING;
INSERT 0 0

ON CONFLICT DO NOTHING : syntaxe

INSERT ....
ON CONFLICT
  DO NOTHING;

ON CONFLICT DO UPDATE

INSERT INTO employes (matricule, nom, service, salaire)
VALUES ('00000001', 'M. Pirate', 'Direction', 0.00)
ON CONFLICT (matricule)
   DO UPDATE SET salaire = employes.salaire,
                 nom = excluded.nom
RETURNING *;
 matricule |    nom    |   service   | salaire
-----------+-----------+-------------+----------
 00000001  | M. Pirate | Direction   | 50000.00

ON CONFLICT DO UPDATE

  • Avec plusieurs lignes insérées :
INSERT INTO employes (matricule, nom, service, salaire)
VALUES ('00000002', 'Moizelle Jeanne', 'Publication', 3000.00),
       ('00000040', 'Lebrac', 'Publication', 3100.00)
ON CONFLICT (matricule)
   DO UPDATE SET salaire = employes.salaire,
                 nom = excluded.nom
RETURNING *;
 matricule |       nom       |   service   | salaire
-----------+-----------------+-------------+----------
 00000002  | Moizelle Jeanne | Publication |  3000.00
 00000040  | Lebrac          | Publication |  3000.00

ON CONFLICT DO UPDATE : syntaxe

  • Colonne(s) portant(s) une contrainte d’unicité
  • Pseudo-table excluded
INSERT ....
ON CONFLICT (<colonne clé>)
  DO UPDATE
        SET colonne_a_modifier = excluded.colonne,
            autre_colonne_a_modifier = excluded.autre_colonne,
            ...;

LATERAL

  • Jointures LATERAL
    • SQL:99
    • PostgreSQL 9.3
    • équivalent d’une boucle foreach
  • Utilisations
    • top-N à partir de plusieurs tables
    • jointure avec une fonction retournant un ensemble

LATERAL : avec une sous-requête

  • Jointure LATERAL
    • équivalent de foreach
  • Utilité :
    • Top-N à partir de plusieurs tables
    • exemple : afficher les 5 derniers messages des 5 derniers sujets actifs d’un forum

LATERAL : exemple

SELECT titre,
       top_5_messages.date_publication,
       top_5_messages.extrait
  FROM sujets,
  LATERAL(SELECT date_publication,
                 substr(message, 0, 100) AS extrait
          FROM messages
         WHERE sujets.sujet_id = messages.sujet_id
         ORDER BY date_publication DESC
         LIMIT 5) top_5_messages
 ORDER BY sujets.date_modification DESC,
          top_5_messages.date_publication DESC
 LIMIT 25;

LATERAL : principe

Principe LATERAL

LATERAL : avec une fonction

  • Utilisation avec une fonction retournant un ensemble
    • clause LATERAL optionnelle
  • Utilité :
    • extraire les données d’un tableau ou d’une structure JSON sous la forme tabulaire
    • utiliser une fonction métier qui retourne un ensemble X selon un ensemble Y fourni

LATERAL : exemple avec une fonction

SELECT titre,
       top_5_messages.date_publication,
       top_5_messages.extrait
  FROM sujets,
       get_top_5_messages(sujet_id) AS top_5_messages
 ORDER BY sujets.date_modification DESC
 LIMIT 25;

Common Table Expressions

  • Common Table Expressions
    • clauses WITH et WITH RECURSIVE
  • Utilité :
    • factoriser des sous-requêtes

CTE et SELECT

  • Utilité
    • factoriser des sous-requêtes
    • améliorer la lisibilité d’une requête

CTE et SELECT : exemple

WITH resultat AS (
   /* requête complexe */
)
SELECT *
  FROM resultat
 WHERE nb < 5;

CTE et SELECT : syntaxe

WITH nom_vue1 AS [ [ NOT ] MATERIALIZED ] (
 <requête pour générer la vue 1>
)
SELECT *
  FROM nom_vue1;

CTE et barrière d’optimisation

  • Attention, une CTE est une barrière d’optimisation !
    • pas de transformations
    • pas de propagation des prédicats
  • Sauf à partir de la version 12
    • clause MATERIALIZED pour obtenir cette barrière

CTE en écriture

  • CTE avec des requêtes en modification
    • avec INSERT/UPDATE/DELETE
    • et éventuellement RETURNING
    • obligatoirement exécuté sur PostgreSQL
  • Exemple d’utilisation :
    • archiver des données
    • partitionner les données d’une table
    • débugger une requête complexe

CTE en écriture : exemple

WITH donnees_a_archiver AS (
DELETE FROM donnes_courantes
 WHERE date < '2015-01-01'
 RETURNING *
)
INSERT INTO donnes_archivees
SELECT * FROM donnees_a_archiver;

CTE récursive

  • SQL permet d’exprimer des récursions
    • WITH RECURSIVE
  • Utilité :
    • récupérer une arborescence de menu hiérarchique
    • parcourir des graphes (réseaux sociaux, etc.)

CTE récursive : exemple (1/2)

WITH RECURSIVE suite AS (
SELECT 1 AS valeur
UNION ALL
SELECT valeur + 1
  FROM suite
 WHERE valeur < 10
)
SELECT * FROM suite;

CTE récursive : principe

  • 1ère étape : initialisation de la récursion

Principe CTE recursive - 1

CTE récursive : principe

  • récursion : la requête s’appelle elle-même

Principe CTE recursive - 2

CTE récursive : exemple (2/2)

WITH RECURSIVE parcours_menu AS (
SELECT menu_id, libelle, parent_id,
       libelle AS arborescence
  FROM entrees_menu
 WHERE libelle = 'Terminal'
   AND parent_id IS NULL
UNION ALL
SELECT menu.menu_id, menu.libelle, menu.parent_id,
       arborescence || '/' || menu.libelle
  FROM entrees_menu menu
  JOIN parcours_menu parent
    ON (menu.parent_id = parent.menu_id)
)
SELECT * FROM parcours_menu;

Concurrence d’accès

  • Problèmes pouvant se poser :
    • UPDATE perdu
    • lecture non répétable
  • Plusieurs solutions possibles
    • versionnement des lignes
    • SELECT FOR UPDATE
    • SERIALIZABLE

SELECT FOR UPDATE

  • SELECT FOR UPDATE
  • Utilité :
    • « réserver » des lignes en vue de leur mise à jour
    • éviter les problèmes de concurrence d’accès

SKIP LOCKED

  • SELECT FOR UPDATE SKIP LOCKED
    • PostgreSQL 9.5
  • Utilité :
    • implémente des files d’attentes parallélisables

Serializable Snapshot Isolation

SSI : Serializable Snapshot Isolation (9.1+)

  • Chaque transaction est seule sur la base
  • Si on ne peut maintenir l’illusion
    • une des transactions en cours est annulée
  • Sans blocage
  • On doit être capable de rejouer la transaction
  • Toutes les transactions impliquées doivent être serializable
  • default_transaction_isolation=serializable dans la configuration

Conclusion

  • SQL est un langage très riche
  • Connaître les nouveautés des versions de la norme depuis 20 ans permet de
    • gagner énormément de temps de développemment
    • mais aussi de performance

Travaux pratiques

Travaux pratiques (solutions)

Types de base

  • PostgreSQL offre un système de typage complet
    • types standards
    • types avancés propres à PostgreSQL

Préambule

  • SQL possède un typage fort
    • le type utilisé décrit la donnée manipulée
    • garantit l’intégrité des données
    • primordial au niveau fonctionnel
    • garantit les performances
  • Qu’est-ce qu’un type ?
  • Les types SQL standards
    • numériques
    • temporels
    • textuels et binaires
  • Les types avancés de PostgreSQL

Objectifs

  • Comprendre le système de typage de PostgreSQL
  • Savoir choisir le type adapté à une donnée
  • Être capable d’utiliser les types avancés à bon escient

Les types de données

  • Qu’est-ce qu’un type ?
  • Représentation physique
  • Impacts sur l’intégrité
  • Impacts fonctionnels

Qu’est-ce qu’un type ?

  • Un type définit :
    • les valeurs que peut prendre une donnée
    • les opérateurs applicables à cette donnée

Impact sur les performances

  • Choisir le bon type pour :
    • optimiser les performances
    • optimiser le stockage

Impacts sur l’intégrité

  • Le bon type de données garantit l’intégrité des données :
    • la bonne représentation
    • le bon intervalle de valeur

Impacts fonctionnels

  • Un type de données offre des opérateurs spécifiques :
    • comparaison
    • manipulation
  • Exemple: une date est-elle comprise entre deux dates données ?

Types numériques

  • Entiers
  • Flottants
  • Précision fixée

Types numériques : entiers

  • 3 types entiers :
    • smallint : 2 octets
    • integer : 4 octets
    • bigint : 8 octets
  • Valeur exacte
  • Signé
  • Utilisation :
    • véritable entier
    • clé technique

Types numériques : flottants

  • 2 types flottants :
    • real/float4
    • double precision/float8
  • Données numériques « floues »
    • valeurs non exactes
  • Utilisation :
    • stockage des données issues de capteurs

Types numériques : numeric

  • 1 type
    • numeric(.., ..)
  • Type exact
    • mais calcul lent
  • Précision choisie : totale, partie décimale
  • Utilisation :
    • données financières
    • calculs exacts
  • Déconseillé pour :
    • clés primaires
    • données non exactes (ex : résultats de capteurs)

Opérations sur les numériques

  • Indexable : >, >=, =, <=,<
  • +, -, /, *, modulo (%), puissance (^)
  • Pour les entiers :
    • AND, OR, XOR (&, |, #)
    • décalage de bits (shifting): >>, <<
  • Attention aux conversions (casts) / promotions !

Choix d’un type numérique

  • integer ou biginteger :
    • identifiants (clés primaires et autre)
    • nombres entiers
  • numeric :
    • valeurs décimales exactes
    • performance non critique
  • float, real :
    • valeurs flottantes, non exactes
    • performance demandée : SUM(), AVG(), etc.

Types temporels

  • Date
  • Date & heure
    • …avec ou sans fuseau

Types temporels : date

  • date
    • représente une date, sans heure
    • affichage format ISO : YYYY-MM-DD
  • Utilisation :
    • stockage d’une date lorsque la composante heure n’est pas utilisée
  • Cas déconseillés :
    • stockage d’une date lorsque la composante heure est utilisée

Types temporels : time

  • time
    • représente une heure sans date
    • affichage format ISO HH24:MI:SS
  • Peu de cas d’utilisation
  • À éviter :
    • stockage d’une date et de la composante heure dans deux colonnes

Types temporels : timestamp

  • timestamp (without time zone !)
    • représente une date et une heure
    • fuseau horaire non précisé
  • Utilisation :
    • stockage d’une date et d’une heure

Types temporels : timestamp with time zone

  • timestamp with time zone = timestamptz
    • représente une date et une heure
    • fuseau horaire inclus
    • affichage : 2019-11-13 15:33:00.824096+01
  • Utilisation :
    • stockage d’une date et d’une heure, cadre mondial
    • à préférer à timestamp without time zone

Types temporels : interval

  • interval
    • représente une durée
  • Utilisation :
    • exprimer une durée
    • dans une requête, pour modifier une date/heure existante

Choix d’un type temporel

  • Préférer les types avec timezone
    • toujours plus simple à gérer au début qu’à la fin
  • Considérer les types range pour tout couple « début / fin »
  • Utiliser interval /generate_series

Types chaînes

  • Texte à longueur variable
  • Binaires

Types chaînes : caractères

  • varchar(_n_), text
  • Représentent une chaîne de caractères
  • Valident l’encodage
  • Valident la longueur maximale de la chaîne (contrainte !)
  • Utilisation :
    • stocker des chaînes de caractères non binaires

Types chaînes : binaires

  • bytea
  • Stockage de données binaires
    • encodage en hexadécimal ou séquence d’échappement
  • Utilisation :
    • stockage de courtes données binaires
  • Cas déconseillés :
    • stockage de fichiers binaires

Quel type choisir ?

  • varchar (sans limite) ou text (non standard)
  • Implémenter la limite avec une contrainte
    • plus simple à modifier
CREATE TABLE t1 (c1 varchar CHECK (length(c1) < 10))

Collation

  • L’ordre de tri dépend des langues & de conventions variables
  • Collation par colonne / index / requête
  • SELECT * FROM mots ORDER BY t COLLATE "C" ;
  • CREATE TABLE messages ( id int, fr TEXT COLLATE "fr_FR.utf8", de TEXT COLLATE "de_DE.utf8" );

Collation & sources

Source des collations :

  • le système : installations séparées nécessaires, différences entre OS
  • (>= v 10) : librairie externe ICU

CREATE COLLATION danois (provider = icu, locale = 'da-x-icu') ;

Types avancés

  • PostgreSQL propose des types plus avancés
  • De nombreuses extensions !
    • faiblement structurés (JSON…)
    • intervalle
    • géométriques
    • tableaux

Types faiblement structurés

  • PostgreSQL propose plusieurs types faiblement structurés :
    • hstore (clé/valeur historique)
    • json
    • xml

json

  • json
    • stockage sous forme d’une chaîne de caractère
    • valide un document JSON sans modification
  • jsonb (PG > 9.4)
    • stockage binaire optimisé
    • beaucoup plus de fonctions (dont jsonpath en v12)
    • à préférer

xml

  • xml
    • stocke un document XML
    • valide sa structure
  • Quelques opérateurs disponibles

Types intervalle de valeurs

  • Représentation d’intervalle
    • utilisable avec plusieurs types : entiers, dates, timestamps, etc.
    • contrainte d’exclusion

range

  • représente un intervalle de valeurs continues
    • entre deux bornes
    • incluses ou non
  • plusieurs types natifs
    • int4range, int8range, numrange
    • daterange, tsrange, tstzrange

Manipulation

  • opérateurs spécifiques *, &&, <@ ou @>
  • indexation avec GiST ou SP-GiST
  • types personnalisés

Contraintes d’exclusion

  • Utilisation :
    • éviter le chevauchement de deux intervalles (range)
  • Performance :
    • s’appuie sur un index
CREATE TABLE vendeurs (
  nickname varchar NOT NULL,
  plage_horaire timerange NOT NULL,
  EXCLUDE USING GIST (plage_horaire WITH &&)
);

Types géométriques

  • Plusieurs types natifs 2D :
    • point, ligne, segment, polygone, cercle
  • Utilisation :
    • stockage de géométries simples, sans référentiel de projection
  • Pour la géographie :
    • extension PostGIS

Types utilisateurs

  • Plusieurs types définissables par l’utilisateur
    • types composites
    • domaines
    • enums

Types composites

  • Regroupe plusieurs attributs
    • la création d’une table implique la création d’un type composite associé
  • Utilisation :
    • déclarer un tableau de données composites
    • en PL/pgSQL, déclarer une variable de type enregistrement

Type énumération

  • Ensemble fini de valeurs possibles
    • uniquement des chaînes de caractères
    • 63 caractères maximum
  • Équivalent des énumérations des autres langages
  • Utilisation :
    • listes courtes figées (statuts…)
    • évite des jointures

SQL pour l’analyse de données

Préambule

  • Analyser des données est facile avec PostgreSQL
    • opérations d’agrégation disponibles
    • fonctions OLAP avancées
  • Agrégation de données
  • Clause FILTER
  • Fonctions WINDOW
  • GROUPING SETS, ROLLUP, CUBE
  • WITHIN GROUPS

Objectifs

  • Écrire des requêtes encore plus complexes
  • Analyser les données en amont
    • pour ne récupérer que le résultat

Agrégats

  • SQL dispose de fonctions de calcul d’agrégats
  • Utilité :
    • calcul de sommes, moyennes, valeur minimale et maximale
    • nombreuses fonctions statistiques disponibles

Agrégats avec GROUP BY

  • agrégat + GROUP BY
  • Utilité
    • effectue des calculs sur des regroupements : moyenne, somme, comptage, etc.
    • regroupement selon un critère défini par la clause GROUP BY
    • exemple : calcul du salaire moyen de chaque service

GROUP BY : principe

Résultat du GROUP BY

GROUP BY : exemples

SELECT service,
       sum(salaire) AS salaires_par_service
  FROM employes
 GROUP BY service;
   service   | salaires_par_service
-------------+----------------------
 Courrier    |              7500.00
 Direction   |             10000.00
 Publication |              7000.00
(3 lignes)

Agrégats et ORDER BY

  • Extension propriétaire de PostgreSQL
    • ORDER BY dans la fonction d’agrégat
  • Utilité :
    • ordonner les données agrégées
    • surtout utile avec array_agg, string_agg et xmlagg

Utiliser ORDER BY avec un agrégat

SELECT service,
       string_agg(nom, ', ' ORDER BY nom) AS liste_employes
  FROM employes
 GROUP BY service;
   service   |  liste_employes
-------------+-------------------
 Courrier    | Fantasio, Lagaffe
 Direction   | Dupuis
 Publication | Lebrac, Prunelle
(3 lignes)

Clause FILTER

  • Clause FILTER
  • Utilité :
    • filtrer les données sur les agrégats
    • évite les expressions CASE complexes
  • SQL:2003

Filtrer avec CASE

  • La syntaxe suivante était utilisée :
SELECT count(*) AS compte_pays,
       count(CASE WHEN r.nom_region='Europe' THEN 1
                  ELSE NULL
              END) AS compte_pays_europeens
  FROM pays p
  JOIN regions r
    ON (p.region_id = r.region_id);

Filtrer avec FILTER

  • La même requête écrite avec la clause FILTER :
SELECT count(*) AS compte_pays,
       count(*) FILTER (WHERE r.nom_region='Europe')
                AS compte_pays_europeens
  FROM pays p
  JOIN regions r
    ON (p.region_id = r.region_id);

Fonctions de fenêtrage

  • Fonctions WINDOW
    • travaille sur des ensembles de données regroupés et triés indépendamment de la requête principale
  • Utilisation :
    • utiliser plusieurs critères d’agrégation dans la même requête
    • utiliser des fonctions de classement
    • faire référence à d’autres lignes de l’ensemble de données

Regroupement

  • Regroupement
    • clause OVER (PARTITION BY …)
  • Utilité :
    • plusieurs critères de regroupement différents
    • avec des fonctions de calcul d’agrégats

Regroupement : exemple

SELECT matricule, salaire, service,
       SUM(salaire) OVER (PARTITION BY service)
                 AS total_salaire_service
  FROM employes;
 matricule | salaire  |   service   | total_salaire_service
-----------+----------+-------------+-----------------------
 00000004  |  4500.00 | Courrier    |               7500.00
 00000020  |  3000.00 | Courrier    |               7500.00
 00000001  | 10000.00 | Direction   |              10000.00
 00000006  |  4000.00 | Publication |               7000.00
 00000040  |  3000.00 | Publication |               7000.00

Regroupement : principe

SUM(salaire) OVER (PARTITION BY service)

Fonction de fenêtrage

Regroupement : syntaxe

SELECT
 agregation OVER (PARTITION BY <colonnes>)
  FROM <liste_tables>
 WHERE <predicats>

Tri

  • Tri
    • OVER (ORDER BY …)
  • Utilité :
    • numéroter les lignes : row_number()
    • classer des résultats : rank(), dense_rank()
    • faire appel à d’autres lignes du résultat : lead(), lag()

Tri : exemple

  • Pour numéroter des lignes :
SELECT row_number() OVER (ORDER BY matricule),
       matricule, nom
  FROM employes;
 row_number | matricule |   nom
------------+-----------+----------
          1 | 00000001  | Dupuis
          2 | 00000004  | Fantasio
          3 | 00000006  | Prunelle
          4 | 00000020  | Lagaffe
          5 | 00000040  | Lebrac
(5 lignes)

Tri : exemple avec une somme

  • Calcul d’une somme glissante :
SELECT matricule, salaire,
       SUM(salaire) OVER (ORDER BY matricule)
  FROM employes;
 matricule | salaire  |   sum
-----------+----------+----------
 00000001  | 10000.00 | 10000.00
 00000004  |  4500.00 | 14500.00
 00000006  |  4000.00 | 18500.00
 00000020  |  3000.00 | 21500.00
 00000040  |  3000.00 | 24500.00

Tri : principe

SUM(salaire) OVER (ORDER BY matricule)

Fonction de fenêtrage - tri

Tri : syntaxe

SELECT
 agregation OVER (ORDER BY <colonnes>)
  FROM <liste_tables>
 WHERE <predicats>

Regroupement et tri

  • On peut combiner les deux
    • OVER (PARTITION BY .. ORDER BY ..)
  • Utilité :
    • travailler sur des jeux de données ordonnés et isolés les uns des autres

Regroupement et tri : exemple

SELECT continent, pays, population,
       rank() OVER (PARTITION BY continent
                    ORDER BY population DESC)
              AS rang
  FROM population;
    continent     |       pays         | population | rang
------------------+--------------------+------------+------
 Afrique          | Nigéria            |      173.6 |    1
 Afrique          | Éthiopie           |       94.1 |    2
 Afrique          | Égypte             |       82.1 |    3
 Afrique          | Rép. dém. du Congo |       67.5 |    4
()
 Amérique du Nord | États-Unis         |      320.1 |    1
 Amérique du Nord | Canada             |       35.2 |    2
()

Regroupement et tri : principe

OVER (PARTITION BY continent
      ORDER BY population DESC)

Fonction de fenêtrage - partition et tri

Regroupement et tri : syntaxe

SELECT
 <agregation> OVER (PARTITION BY <colonnes>
                  ORDER BY <colonnes>)
  FROM <liste_tables>
 WHERE <predicats>

Fonctions analytiques

  • PostgreSQL dispose d’un certain nombre de fonctions analytiques
  • Utilité :
    • faire référence à d’autres lignes du même ensemble
    • évite les auto-jointures complexes et lentes

lead() et lag()

  • lead(colonne, n)
    • retourne la valeur d’une colonne, n lignes après la ligne courante
  • lag(colonne, n)
    • retourne la valeur d’une colonne, n lignes avant la ligne courante

lead() et lag() : exemple

SELECT pays, continent, population,
       lag(population) OVER (PARTITION BY continent
                             ORDER BY population DESC)
  FROM population;
         pays          | continent | population |  lag
-----------------------+-----------+------------+--------
 Chine                 | Asie      |     1385.6 |
 Iraq                  | Asie      |       33.8 | 1385.6
 Ouzbékistan           | Asie      |       28.9 |   33.8
 Arabie Saoudite       | Asie      |       28.8 |   28.9
 France métropolitaine | Europe    |       64.3 |
 Finlande              | Europe    |        5.4 |   64.3
 Lettonie              | Europe    |        2.1 |    5.4

lead() et lag() : principe

lag(population) OVER (PARTITION BY continent
                      ORDER BY population DESC)

Fonction lag()

first/last/nth_value

  • first_value(colonne)
    • retourne la première valeur pour la colonne
  • last_value(colonne)
    • retourne la dernière valeur pour la colonne
  • nth_value(colonne, n)
    • retourne la n-ème valeur (en comptant à partir de 1) pour la colonne

first/last/nth_value : exemple

SELECT pays, continent, population,
       first_value(population)
           OVER (PARTITION BY continent
                 ORDER BY population DESC)
  FROM population;
       pays      | continent | population | first_value
-----------------+-----------+------------+-------------
 Chine           | Asie      |     1385.6 |      1385.6
 Iraq            | Asie      |       33.8 |      1385.6
 Ouzbékistan     | Asie      |       28.9 |      1385.6
 Arabie Saoudite | Asie      |       28.8 |      1385.6
 France          | Europe    |       64.3 |        64.3
 Finlande        | Europe    |        5.4 |        64.3
 Lettonie        | Europe    |        2.1 |        64.3

Clause WINDOW

  • Pour factoriser la définition d’une fenêtre :
SELECT matricule, nom, salaire, service,
       rank() OVER w,
       dense_rank() OVER w
  FROM employes
 WINDOW w AS (ORDER BY salaire);

Clause WINDOW : syntaxe

SELECT fonction_agregat OVER nom,
       fonction_agregat_2 OVER nom …

  FROM <liste_tables>
 WHERE <predicats>
 WINDOW nom AS (PARTITION BYORDER BY …)

Définition de la fenêtre

  • La fenêtre de travail par défaut est :
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
  • Trois modes possibles :
    • RANGE
    • ROWS
    • GROUPS (v11+)
  • Nécessite une clause ORDER BY

Définition de la fenêtre : RANGE

  • Indique un intervalle à bornes flou
  • Borne de départ :
    • UNBOUNDED PRECEDING: depuis le début de la partition
    • CURRENT ROW : depuis la ligne courante
  • Borne de fin :
    • UNBOUNDED FOLLOWING : jusqu’à la fin de la partition
    • CURRENT ROW : jusqu’à la ligne courante
    OVER (PARTITION BY
         ORDER BY
         RANGE BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING

Définition de la fenêtre : ROWS

  • Indique un intervalle borné par un nombre de ligne défini avant et après la ligne courante
  • Borne de départ :
    • xxx PRECEDING : depuis les xxx valeurs devant la ligne courante
    • CURRENT ROW : depuis la ligne courante
  • Borne de fin :
    • xxx FOLLOWING : depuis les xxx valeurs derrière la ligne courante
    • CURRENT ROW : jusqu’à la ligne courante
    OVER (PARTITION BY
         ORDER BY
         ROWS BETWEEN 2 PRECEDING AND 1 FOLLOWING

Définition de la fenêtre : GROUPS

  • Indique un intervalle borné par un groupe de lignes de valeurs identiques défini avant et après la ligne courante
  • Borne de départ :
    • xxx PRECEDING : depuis les xxx groupes de valeurs identiques devant la ligne courante
    • CURRENT ROW : depuis la ligne courante ou le premier élément identique dans le tri réalisé par ORDER BY
  • Borne de fin :
    • xxx FOLLOWING : depuis les xxx groupes de valeurs identiques derrière la ligne courante
    • CURRENT ROW : jusqu’à la ligne courante ou le dernier élément identique dans le tri réalisé par ORDER BY
   OVER (PARTITION BY
         ORDER BY
         GROUPS BETWEEN 2 PRECEDING AND 1 FOLLOWING

Définition de la fenêtre : EXCLUDE

  • Indique des lignes à exclure de la fenêtre de données (v11+)
  • EXCLUDE CURRENT ROW : exclut la ligne courante
  • EXCLUDE GROUP : exclut la ligne courante et le groupe de valeurs identiques dans l’ordre
  • EXCLUDE TIES exclut et le groupe de valeurs identiques à la ligne courante dans l’ordre mais pas la ligne courante
  • EXCLUDE NO OTHERS : pas d’exclusion (valeur par défaut)

Définition de la fenêtre : exemple

SELECT pays, continent, population,
       last_value(population)
        OVER (PARTITION BY continent ORDER BY population
              RANGE BETWEEN UNBOUNDED PRECEDING
                        AND UNBOUNDED FOLLOWING)
  FROM population;
         pays          | continent | population | last_value
-----------------------+-----------+------------+------------
 Arabie Saoudite       | Asie      |       28.8 |     1385.6
 Ouzbékistan           | Asie      |       28.9 |     1385.6
 Iraq                  | Asie      |       33.8 |     1385.6
 Chine (4)             | Asie      |     1385.6 |     1385.6
 Lettonie              | Europe    |        2.1 |       64.3
 Finlande              | Europe    |        5.4 |       64.3
 France métropolitaine | Europe    |       64.3 |       64.3

WITHIN GROUP

  • WITHIN GROUP
  • Utilité :
    • calcul de médianes, centiles

WITHIN GROUP : exemple

SELECT continent,
  percentile_disc(0.5)
    WITHIN GROUP (ORDER BY population) AS "mediane",
  percentile_disc(0.95)
    WITHIN GROUP (ORDER BY population) AS "95pct",
  ROUND(AVG(population), 1) AS moyenne
FROM population
 GROUP BY continent;
         continent         | mediane | 95pct  | moyenne
---------------------------+---------+--------+---------
 Afrique                   |    33.0 |  173.6 |    44.3
 Amérique du Nord          |    35.2 |  320.1 |   177.7
 Amérique latine. Caraïbes |    30.4 |  200.4 |    53.3
 Asie                      |    53.3 | 1252.1 |   179.9
 Europe                    |     9.4 |   82.7 |    21.8

Grouping Sets

  • GROUPING SETS/ROLLUP/CUBE
  • Extension de GROUP BY
  • Utilité :
    • présente le résultat de plusieurs agrégations différentes
    • réaliser plusieurs agrégations différentes dans la même requête

GROUPING SETS : jeu de données

Opérateur GROUP BY | Opérateur GROUP BY   |   |

GROUPING SETS : exemple visuel

Opérateur GROUP BY

GROUPING SETS : exemple ordre sql

SELECT piece,region,sum(quantite)
FROM stock GROUP BY GROUPING SETS (piece,region);
 piece  | region | sum
--------+--------+-----
 clous  |        |  70
 ecrous |        |  90
 vis    |        | 160
        | est    | 120
        | nord   |  60
        | ouest  |  50
        | sud    |  90

GROUPING SETS : équivalent

  • On peut se passer de la clause GROUPING SETS
    • mais la requête sera plus lente
SELECT piece,NULL as region,sum(quantite)
  FROM stock
  GROUP BY piece
UNION ALL
SELECT NULL, region,sum(quantite)
  FROM STOCK
  GROUP BY region;

ROLLUP

  • ROLLUP
  • Utilité :
    • calcul de totaux dans la même requête

ROLLUP : exemple visuel

Opérateur GROUP BY

ROLLUP : exemple ordre sql

SELECT piece,region,sum(quantite)
FROM stock GROUP BY ROLLUP (piece,region);

Cette requête est équivalente à la requête suivante utilisant GROUPING SETS :

SELECT piece,region,sum(quantite)
FROM stock
GROUP BY GROUPING SETS ((),(piece),(piece,region));

CUBE

  • CUBE
  • Utilité :
    • calcul de totaux dans la même requête
    • sur toutes les clauses de regroupement

CUBE : exemple visuel

Opérateur GROUP BY

CUBE : exemple ordre sql

SELECT piece,region,sum(quantite)
FROM stock GROUP BY CUBE (piece,region);

Cette requête est équivalente à la requête suivante utilisant GROUPING SETS :

SELECT piece,region,sum(quantite)
FROM stock
GROUP BY GROUPING SETS (
  (),
  (piece),
  (region),
  (piece,region)
  );

Travaux pratiques

Travaux pratiques (solutions)


  1. La solution actuelle semble techniquement meilleure et la solution actuelle a donc été choisie. Le wiki du projet PostgreSQL montre que l’ordre MERGE a été étudié et qu’un certain nombre d’aspects cruciaux n’ont pas été spécifiés, amenant le projet PostgreSQL à utiliser sa propre version. Voir la documentation : https://wiki.postgresql.org/wiki/UPSERT#MERGE_disadvantages.↩︎