🎯 Objectifs de la sĂ©ance

1. SQL Transactionnel vs Analytique

🏩 OLTP (Transactionnel)

  • Objectif : GĂ©rer les transactions quotidiennes
  • OpĂ©rations : INSERT, UPDATE, DELETE frĂ©quents
  • Volume : Petites quantitĂ©s par requĂȘte
  • Exemples : SystĂšme bancaire, e-commerce, rĂ©servations

📊 OLAP (Analytique)

  • Objectif : Analyser de grandes quantitĂ©s de donnĂ©es
  • OpĂ©rations : SELECT complexes, agrĂ©gations
  • Volume : Millions de lignes Ă  traiter
  • Exemples : Rapports, dashboards, analyses

🩆 Pourquoi DuckDB pour l'analytique ?

  • ✅ Traitement par colonnes (columnar storage)
  • ✅ Vectorisation des calculs
  • ✅ ParallĂ©lisation automatique
  • ✅ Compression des donnĂ©es
  • ✅ Pas de surcharge rĂ©seau (embarquĂ©)

2. Jointures Complexes

Types de jointures

-- INNER JOIN : Seulement les correspondances
SELECT c.nom, co.montant, co.date
FROM clients c
INNER JOIN commandes co ON c.id = co.client_id;

-- LEFT JOIN : Tous les clients, mĂȘme sans commande
SELECT c.nom, COUNT(co.id) as nb_commandes
FROM clients c
LEFT JOIN commandes co ON c.id = co.client_id
GROUP BY c.nom;

-- Jointure Ă  3 tables
SELECT 
    c.nom as client,
    p.nom as produit,
    v.quantite,
    v.montant
FROM ventes v
INNER JOIN clients c ON v.client_id = c.id
INNER JOIN produits p ON v.produit_id = p.id
ORDER BY v.date DESC;

3. Agrégations et GROUP BY

-- Agrégation simple
SELECT 
    categorie,
    COUNT(*) as nb_produits,
    AVG(prix) as prix_moyen,
    SUM(stock) as stock_total
FROM produits
GROUP BY categorie;

-- HAVING : Filtrer les groupes
SELECT 
    client_id,
    COUNT(*) as nb_achats,
    SUM(montant) as total_depense
FROM ventes
GROUP BY client_id
HAVING SUM(montant) > 1000
ORDER BY total_depense DESC;

⚠ WHERE vs HAVING

  • WHERE : Filtre les lignes AVANT l'agrĂ©gation
  • HAVING : Filtre les groupes APRÈS l'agrĂ©gation

4. Window Functions (Fonctions de FenĂȘtrage)

📖 Qu'est-ce qu'une Window Function ?

Les window functions permettent de faire des calculs sur un ensemble de lignes sans réduire le nombre de lignes (contrairement à GROUP BY).

Syntaxe générale

fonction() OVER (
    PARTITION BY colonnes     -- Grouper (optionnel)
    ORDER BY colonnes         -- Trier (optionnel)
    ROWS/RANGE dĂ©finition     -- FenĂȘtre (optionnel)
)

🎯 ROW_NUMBER() - NumĂ©rotation

-- Numéroter toutes les lignes
SELECT 
    nom,
    prix,
    ROW_NUMBER() OVER (ORDER BY prix DESC) as rang
FROM produits;

đŸ„‡ RANK() et DENSE_RANK()

SELECT 
    nom,
    score,
    RANK() OVER (ORDER BY score DESC) as rang,
    DENSE_RANK() OVER (ORDER BY score DESC) as rang_dense
FROM etudiants;

Différence RANK vs DENSE_RANK

  • RANK() : Saute des rangs en cas d'Ă©galitĂ© (1, 2, 2, 4)
  • DENSE_RANK() : Pas de saut (1, 2, 2, 3)

📩 PARTITION BY - Groupement

-- Top 3 produits par catégorie
SELECT *
FROM (
    SELECT 
        categorie,
        nom,
        prix,
        ROW_NUMBER() OVER (
            PARTITION BY categorie 
            ORDER BY prix DESC
        ) as rang_categorie
    FROM produits
) WHERE rang_categorie <= 3;

📈 LAG() et LEAD() - Lignes prĂ©cĂ©dentes/suivantes

-- Comparer avec le mois précédent
SELECT 
    mois,
    ca,
    LAG(ca, 1) OVER (ORDER BY mois) as ca_mois_precedent,
    ca - LAG(ca, 1) OVER (ORDER BY mois) as evolution
FROM ventes_mensuelles;

📊 Moyenne mobile (Moving Average)

-- Moyenne mobile sur 3 mois
SELECT 
    mois,
    ca,
    AVG(ca) OVER (
        ORDER BY mois
        ROWS BETWEEN 2 PRECEDING AND CURRENT ROW
    ) as moyenne_mobile_3mois
FROM ventes_mensuelles;

5. CTE (Common Table Expressions)

📖 Qu'est-ce qu'un CTE ?

Un CTE est une requĂȘte temporaire nommĂ©e qui rend le code SQL plus lisible et maintenable.

-- Avec CTE (lisible)
WITH ventes_client AS (
    SELECT client_id, SUM(montant) as total
    FROM ventes
    GROUP BY client_id
),
clients_premium AS (
    SELECT * 
    FROM ventes_client 
    WHERE total > 1000
)
SELECT * 
FROM clients_premium 
WHERE client_id > 100;

Exemple pratique : Segmentation clients

WITH client_stats AS (
    SELECT 
        client_id,
        COUNT(*) as nb_achats,
        SUM(montant) as ca_total,
        AVG(montant) as panier_moyen
    FROM ventes
    GROUP BY client_id
),
client_segments AS (
    SELECT 
        client_id,
        ca_total,
        CASE 
            WHEN ca_total > 2000 THEN "VIP"
            WHEN ca_total > 1000 THEN "Premium"
            ELSE "Standard"
        END as segment
    FROM client_stats
)
SELECT * FROM client_segments
ORDER BY ca_total DESC;

🎯 Quiz de validation des connaissances

Testez vos connaissances sur SQL analytique ! 10 questions pour valider votre compréhension.

🎓 Points clĂ©s Ă  retenir

📚 Ressources complĂ©mentaires