Aller au contenu
Développement medium

Syntaxe SQL de base : SELECT, WHERE, ORDER BY et LIMIT

33 min de lecture

Un serveur de production génère des alertes critiques depuis 3 heures. Vous voulez savoir lesquelles, sur quel serveur, depuis quand. L’information est dans la base de données — il suffit d’un SELECT pour l’extraire.

SQL (Structured Query Language) est un langage déclaratif : vous décrivez ce que vous voulez obtenir, pas comment le calculer. Le moteur de la base de données se charge de trouver le chemin optimal pour y arriver. Cette approche le rend beaucoup plus accessible qu’un langage de programmation classique.

Ce guide vous apprend à écrire vos premières requêtes de lecture : sélectionner des colonnes, filtrer avec des conditions, trier les résultats et limiter le nombre de lignes renvoyées. Vous pratiquerez sur une base SQLite fil rouge qui simule la gestion d’une plateforme d’infrastructure — la même base sera utilisée tout au long des 5 guides de cette section.

  • Préparer votre environnement SQLite avec la base fil rouge
  • Sélectionner des colonnes spécifiques d’une table avec SELECT
  • Filtrer les résultats avec WHERE et les opérateurs de comparaison
  • Combiner des conditions avec AND, OR, NOT, IN, BETWEEN et LIKE
  • Trier les résultats avec ORDER BY (ascendant et descendant)
  • Limiter le nombre de lignes renvoyées avec LIMIT et OFFSET
  • Éliminer les doublons avec DISTINCT et renommer les colonnes avec AS

SQL est le langage que vous utilisez chaque fois que vous interagissez avec une base relationnelle. En administration système et DevOps, les situations sont fréquentes :

  • Vérifier qu’un utilisateur applicatif existe dans la table des comptes après un déploiement
  • Compter le nombre de connexions actives dans pg_stat_activity (PostgreSQL) ou information_schema.processlist (MySQL)
  • Chercher les alertes critiques non acquittées
  • Extraire la liste des serveurs d’un environnement donné
  • Valider qu’une migration de données s’est bien déroulée en comparant des comptages
  • SQLite installé (disponible par défaut sur la plupart des distributions Linux : sqlite3 --version)
  • Un terminal

Tous les guides SQL de cette section utilisent la même base fil rouge : une plateforme de gestion d’infrastructure avec 6 tables.

  1. Créez votre répertoire de travail.

    Fenêtre de terminal
    mkdir -p ~/Projets/cours-sql && cd ~/Projets/cours-sql
  2. Créez le fichier init-db.sql avec le contenu suivant (copiez-collez l’intégralité) :

    -- init-db.sql — Base fil rouge pour les guides SQL
    -- Plateforme d'infrastructure DevSecOps
    --
    -- Utilisation :
    -- cd ~/Projets/cours-sql
    -- sqlite3 infra.db < init-db.sql
    PRAGMA foreign_keys = ON;
    -- ── Serveurs gérés par l'équipe ──────────────────────
    CREATE TABLE IF NOT EXISTS servers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    hostname TEXT NOT NULL UNIQUE,
    ip_address TEXT NOT NULL,
    os TEXT NOT NULL,
    os_version TEXT,
    environment TEXT NOT NULL CHECK (environment IN ('production', 'staging', 'development')),
    datacenter TEXT NOT NULL,
    cpu_cores INTEGER NOT NULL,
    ram_gb INTEGER NOT NULL,
    disk_gb INTEGER NOT NULL,
    active INTEGER NOT NULL DEFAULT 1,
    created_at TEXT NOT NULL DEFAULT (datetime('now')),
    notes TEXT
    );
    -- ── Membres de l'équipe ─────────────────────────────
    CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    username TEXT NOT NULL UNIQUE,
    email TEXT,
    full_name TEXT NOT NULL,
    role TEXT NOT NULL CHECK (role IN ('admin', 'operator', 'viewer')),
    team TEXT NOT NULL,
    active INTEGER NOT NULL DEFAULT 1,
    created_at TEXT NOT NULL DEFAULT (datetime('now')),
    last_login TEXT
    );
    -- ── Services applicatifs ────────────────────────────
    CREATE TABLE IF NOT EXISTS services (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    server_id INTEGER NOT NULL REFERENCES servers(id),
    port INTEGER,
    protocol TEXT CHECK (protocol IN ('http', 'https', 'tcp', 'udp')),
    status TEXT NOT NULL CHECK (status IN ('running', 'stopped', 'failed', 'maintenance')),
    started_at TEXT,
    config_path TEXT
    );
    -- ── Historique des déploiements ─────────────────────
    CREATE TABLE IF NOT EXISTS deployments (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    service_id INTEGER NOT NULL REFERENCES services(id),
    deployed_by INTEGER NOT NULL REFERENCES users(id),
    version TEXT NOT NULL,
    environment TEXT NOT NULL,
    status TEXT NOT NULL CHECK (status IN ('success', 'failed', 'rollback', 'in_progress')),
    duration_seconds INTEGER,
    deployed_at TEXT NOT NULL DEFAULT (datetime('now')),
    notes TEXT
    );
    -- ── Alertes de supervision ──────────────────────────
    CREATE TABLE IF NOT EXISTS alerts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    server_id INTEGER NOT NULL REFERENCES servers(id),
    severity TEXT NOT NULL CHECK (severity IN ('critical', 'warning', 'info')),
    message TEXT NOT NULL,
    acknowledged INTEGER NOT NULL DEFAULT 0,
    created_at TEXT NOT NULL DEFAULT (datetime('now')),
    acknowledged_at TEXT,
    acknowledged_by INTEGER REFERENCES users(id)
    );
    -- ── Catégories d'infrastructure (pour CTE récursifs) ──
    CREATE TABLE IF NOT EXISTS categories (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    parent_id INTEGER REFERENCES categories(id)
    );
    -- ════════════════════════════════════════════════════════
    -- DONNÉES
    -- ════════════════════════════════════════════════════════
    INSERT INTO servers (hostname, ip_address, os, os_version, environment, datacenter, cpu_cores, ram_gb, disk_gb, active, created_at, notes) VALUES
    ('web-prod-01', '10.1.1.10', 'Debian', '12', 'production', 'paris-dc1', 4, 8, 100, 1, '2025-03-15 09:00:00', NULL),
    ('web-prod-02', '10.1.1.11', 'Debian', '12', 'production', 'paris-dc1', 4, 8, 100, 1, '2025-03-15 09:30:00', NULL),
    ('db-prod-01', '10.1.2.10', 'Ubuntu', '24.04', 'production', 'paris-dc1', 8, 32, 500, 1, '2025-01-10 14:00:00', 'PostgreSQL principal'),
    ('db-prod-02', '10.1.2.11', 'Ubuntu', '24.04', 'production', 'paris-dc1', 8, 32, 500, 1, '2025-01-10 14:30:00', 'PostgreSQL replica'),
    ('app-staging-01', '10.2.1.10', 'Debian', '12', 'staging', 'paris-dc2', 2, 4, 50, 1, '2025-06-01 10:00:00', NULL),
    ('db-staging-01', '10.2.2.10', 'Ubuntu', '24.04', 'staging', 'paris-dc2', 4, 16, 200, 1, '2025-06-01 10:30:00', NULL),
    ('monitoring-01', '10.1.3.10', 'Rocky Linux', '9', 'production', 'paris-dc1', 4, 16, 200, 1, '2025-02-20 11:00:00', 'Prometheus + Grafana'),
    ('ci-runner-01', '10.3.1.10', 'Ubuntu', '24.04', 'development', 'lyon-dc1', 8, 16, 200, 1, '2025-04-10 08:00:00', 'GitLab Runner'),
    ('ci-runner-02', '10.3.1.11', 'Ubuntu', '24.04', 'development', 'lyon-dc1', 8, 16, 200, 1, '2025-04-10 08:30:00', 'GitLab Runner'),
    ('backup-01', '10.1.4.10', 'Debian', '11', 'production', 'paris-dc1', 2, 8, 2000, 1, '2024-11-05 16:00:00', 'Serveur de sauvegarde'),
    ('legacy-web-01', '10.1.1.50', 'CentOS', '7', 'production', 'paris-dc1', 2, 4, 50, 0, '2023-06-15 09:00:00', 'Décommissionné'),
    ('dev-sandbox-01', '10.3.2.10', 'Fedora', '40', 'development', 'lyon-dc1', 4, 8, 100, 1, '2026-01-15 13:00:00', NULL);
    INSERT INTO users (username, email, full_name, role, team, active, created_at, last_login) VALUES
    ('jdupont', 'jean.dupont@infra.local', 'Jean Dupont', 'admin', 'infrastructure', 1, '2024-06-15 09:00:00', '2026-04-12 17:45:00'),
    ('mmartin', 'marie.martin@infra.local', 'Marie Martin', 'admin', 'infrastructure', 1, '2024-06-15 09:30:00', '2026-04-13 08:30:00'),
    ('pbernard', 'paul.bernard@infra.local', 'Paul Bernard', 'operator', 'deploiement', 1, '2024-09-01 10:00:00', '2026-04-11 16:00:00'),
    ('agarcia', 'alice.garcia@infra.local', 'Alice Garcia', 'operator', 'deploiement', 1, '2025-01-10 08:00:00', '2026-04-13 09:15:00'),
    ('lmoreau', NULL, 'Lucas Moreau', 'operator', 'securite', 1, '2025-03-20 14:00:00', '2026-04-10 12:00:00'),
    ('cbenoit', 'claire.benoit@infra.local', 'Claire Benoit', 'viewer', 'direction', 1, '2025-06-01 11:00:00', '2026-03-28 10:00:00'),
    ('trousseau', 'thomas.rousseau@infra.local','Thomas Rousseau', 'operator', 'infrastructure', 1, '2025-09-15 09:00:00', NULL),
    ('nleroy', 'nadia.leroy@infra.local', 'Nadia Leroy', 'viewer', 'deploiement', 1, '2025-11-01 10:00:00', '2026-04-05 14:00:00'),
    ('fduval', 'fabien.duval@infra.local', 'Fabien Duval', 'admin', 'securite', 1, '2024-03-01 08:00:00', '2026-04-13 07:00:00'),
    ('sperrin', 'sylvie.perrin@infra.local', 'Sylvie Perrin', 'operator', 'infrastructure', 0, '2024-01-15 09:00:00', '2025-08-30 17:00:00');
    INSERT INTO services (name, server_id, port, protocol, status, started_at, config_path) VALUES
    ('nginx', 1, 443, 'https', 'running', '2026-04-01 06:00:00', '/etc/nginx/nginx.conf'),
    ('nginx', 2, 443, 'https', 'running', '2026-04-01 06:00:00', '/etc/nginx/nginx.conf'),
    ('api-backend', 1, 8080, 'http', 'running', '2026-04-01 06:05:00', '/opt/api/config.yaml'),
    ('api-backend', 2, 8080, 'http', 'running', '2026-04-01 06:05:00', '/opt/api/config.yaml'),
    ('postgresql', 3, 5432, 'tcp', 'running', '2025-01-10 15:00:00', '/etc/postgresql/16/main/postgresql.conf'),
    ('postgresql', 4, 5432, 'tcp', 'running', '2025-01-10 15:30:00', '/etc/postgresql/16/main/postgresql.conf'),
    ('postgresql', 6, 5432, 'tcp', 'running', '2025-06-01 11:00:00', '/etc/postgresql/16/main/postgresql.conf'),
    ('prometheus', 7, 9090, 'http', 'running', '2025-02-20 12:00:00', '/etc/prometheus/prometheus.yml'),
    ('grafana', 7, 3000, 'http', 'running', '2025-02-20 12:30:00', '/etc/grafana/grafana.ini'),
    ('alertmanager', 7, 9093, 'http', 'running', '2025-02-20 12:15:00', '/etc/alertmanager/alertmanager.yml'),
    ('gitlab-runner', 8, NULL, NULL, 'running', '2025-04-10 09:00:00', '/etc/gitlab-runner/config.toml'),
    ('gitlab-runner', 9, NULL, NULL, 'stopped', '2025-04-10 09:00:00', '/etc/gitlab-runner/config.toml'),
    ('nginx', 5, 443, 'https', 'running', '2025-06-01 10:15:00', '/etc/nginx/nginx.conf'),
    ('api-backend', 5, 8080, 'http', 'failed', '2026-04-13 02:00:00', '/opt/api/config.yaml'),
    ('restic', 10, NULL, NULL, 'running', '2024-11-05 17:00:00', '/etc/restic/config.json');
    INSERT INTO deployments (service_id, deployed_by, version, environment, status, duration_seconds, deployed_at, notes) VALUES
    (3, 4, '2.1.0', 'production', 'success', 45, '2026-04-12 14:00:00', NULL),
    (4, 4, '2.1.0', 'production', 'success', 42, '2026-04-12 14:02:00', NULL),
    (14, 4, '2.1.0', 'staging', 'success', 38, '2026-04-11 10:00:00', 'Déploiement staging avant prod'),
    (3, 3, '2.0.9', 'production', 'success', 50, '2026-04-05 11:00:00', NULL),
    (4, 3, '2.0.9', 'production', 'success', 48, '2026-04-05 11:03:00', NULL),
    (14, 3, '2.0.9', 'staging', 'failed', 120, '2026-04-04 16:00:00', 'Erreur de migration BDD'),
    (14, 3, '2.0.9', 'staging', 'success', 55, '2026-04-04 17:00:00', 'Retry après correction'),
    (1, 1, '1.24.0', 'production', 'success', 15, '2026-04-01 06:00:00', 'Mise à jour nginx'),
    (2, 1, '1.24.0', 'production', 'success', 14, '2026-04-01 06:01:00', NULL),
    (13, 1, '1.24.0', 'staging', 'success', 12, '2026-03-30 09:00:00', NULL),
    (5, 2, '16.3', 'production', 'success', 300, '2026-03-15 22:00:00', 'Mise à jour PostgreSQL'),
    (6, 2, '16.3', 'production', 'success', 280, '2026-03-15 22:10:00', NULL),
    (7, 2, '16.3', 'staging', 'success', 250, '2026-03-14 14:00:00', NULL),
    (8, 9, '2.51.0', 'production', 'success', 30, '2026-03-01 10:00:00', NULL),
    (9, 9, '10.4.0', 'production', 'success', 25, '2026-03-01 10:30:00', NULL),
    (10, 9, '0.27.0', 'production', 'success', 20, '2026-03-01 10:15:00', NULL),
    (3, 4, '2.0.8', 'production', 'rollback', 90, '2026-02-20 15:00:00', 'Rollback après erreur 500'),
    (4, 4, '2.0.8', 'production', 'rollback', 88, '2026-02-20 15:05:00', NULL),
    (3, 3, '2.0.7', 'production', 'success', 52, '2026-02-10 11:00:00', NULL),
    (4, 3, '2.0.7', 'production', 'success', 50, '2026-02-10 11:03:00', NULL),
    (14, 4, '2.1.1', 'staging', 'failed', 200, '2026-04-13 01:30:00', 'Service API en erreur'),
    (14, 4, '2.1.0', 'staging', 'success', 40, '2026-04-13 02:30:00', 'Rollback vers version stable'),
    (11, 1, '17.1.0', 'development', 'success', 10, '2026-04-10 08:00:00', NULL),
    (15, 9, '0.16.0', 'production', 'success', 5, '2026-01-15 09:00:00', NULL),
    (3, 4, '2.0.6', 'production', 'success', 55, '2026-01-20 14:00:00', NULL);
    INSERT INTO alerts (server_id, severity, message, acknowledged, created_at, acknowledged_at, acknowledged_by) VALUES
    (3, 'critical', 'Espace disque > 90% sur /var/lib/postgresql', 1, '2026-04-13 03:00:00', '2026-04-13 03:15:00', 2),
    (1, 'warning', 'Charge CPU > 80% pendant 10 min', 1, '2026-04-12 14:30:00', '2026-04-12 14:45:00', 1),
    (2, 'warning', 'Charge CPU > 80% pendant 10 min', 1, '2026-04-12 14:31:00', '2026-04-12 14:45:00', 1),
    (5, 'critical', 'Service api-backend en état failed', 0, '2026-04-13 02:05:00', NULL, NULL),
    (7, 'info', 'Redémarrage planifié de Prometheus effectué', 1, '2026-04-10 06:00:00', '2026-04-10 06:05:00', 9),
    (10, 'warning', 'Backup quotidien : durée > 4h (seuil : 2h)', 0, '2026-04-12 04:30:00', NULL, NULL),
    (8, 'info', 'GitLab Runner : nouveau runner enregistré', 1, '2026-04-10 08:10:00', '2026-04-10 08:15:00', 1),
    (4, 'warning', 'Réplication PostgreSQL : lag > 30s', 1, '2026-04-11 22:00:00', '2026-04-11 22:30:00', 2),
    (11, 'critical', 'Serveur injoignable depuis 5 min', 1, '2025-09-01 14:00:00', '2025-09-01 14:05:00', 1),
    (3, 'warning', 'Connexions PostgreSQL > 80% du max', 0, '2026-04-13 08:00:00', NULL, NULL),
    (1, 'info', 'Certificat TLS expire dans 30 jours', 0, '2026-04-10 09:00:00', NULL, NULL),
    (2, 'info', 'Certificat TLS expire dans 30 jours', 0, '2026-04-10 09:01:00', NULL, NULL),
    (12, 'warning', 'Espace disque > 85% sur /home', 1, '2026-04-08 11:00:00', '2026-04-08 11:30:00', 1),
    (6, 'info', 'Mise à jour de sécurité disponible pour postgresql', 0, '2026-04-12 07:00:00', NULL, NULL),
    (9, 'info', 'GitLab Runner 02 : job échoué 3 fois', 0, '2026-04-11 15:00:00', NULL, NULL),
    (7, 'warning', 'Espace disque > 75% sur /var/lib/prometheus', 1, '2026-04-06 08:00:00', '2026-04-06 09:00:00', 9),
    (3, 'critical', 'PostgreSQL : requête bloquée depuis 30 min', 1, '2026-04-09 16:00:00', '2026-04-09 16:10:00', 2),
    (5, 'warning', 'Latence réseau > 100ms vers paris-dc1', 0, '2026-04-13 07:00:00', NULL, NULL),
    (1, 'critical', 'OOM Killer activé — processus nginx tué', 1, '2026-03-25 03:00:00', '2026-03-25 03:20:00', 1),
    (10, 'info', 'Backup hebdomadaire terminé avec succès', 1, '2026-04-07 06:00:00', '2026-04-07 06:01:00', 9);
    INSERT INTO categories (id, name, parent_id) VALUES
    (1, 'Infrastructure', NULL),
    (2, 'Compute', 1),
    (3, 'Réseau', 1),
    (4, 'Stockage', 1),
    (5, 'Machines virtuelles', 2),
    (6, 'Conteneurs', 2),
    (7, 'Load Balancers', 3),
    (8, 'Firewalls', 3),
    (9, 'Bloc', 4),
    (10, 'Objet', 4),
    (11, 'Sauvegarde', 4);
  3. Chargez la base.

    Fenêtre de terminal
    sqlite3 infra.db < init-db.sql
  4. Vérifiez que tout est en place en ouvrant la base et en lançant quelques requêtes :

    Fenêtre de terminal
    sqlite3 infra.db
    .tables
    -- Résultat : alerts categories deployments servers services users
    SELECT count(*) FROM servers; -- 12
    SELECT count(*) FROM users; -- 10
    SELECT count(*) FROM services; -- 15
    SELECT count(*) FROM deployments;-- 25
    SELECT count(*) FROM alerts; -- 20

Votre base est prête. Gardez le terminal sqlite3 infra.db ouvert pour pratiquer les requêtes de ce guide.

TableLignesContenu
servers12Serveurs gérés (hostname, OS, environnement, datacenter, RAM…)
users10Membres de l’équipe (rôle, équipe, dernier login)
services15Applications déployées sur les serveurs (port, protocole, statut)
deployments25Historique des déploiements (version, durée, statut, qui)
alerts20Alertes de supervision (sévérité, message, acquittement)
categories11Arborescence d’infrastructure (pour les CTE récursifs, guide 5)

Les données sont réalistes : serveurs décommissionnés (active = 0), utilisateur sans email (NULL), services en erreur, déploiements échoués, alertes non acquittées.

Toute requête de lecture en SQL suit le même schéma fondamental :

SELECT colonnes
FROM table
WHERE conditions
ORDER BY colonnes
LIMIT nombre;

Seuls SELECT et FROM sont obligatoires. Les autres clauses sont optionnelles et s’ajoutent dans cet ordre précis.

SELECT définit quelles colonnes vous voulez voir dans le résultat.

-- Sélectionner deux colonnes spécifiques
SELECT hostname, ip_address
FROM servers;

Pour récupérer toutes les colonnes, utilisez * :

SELECT *
FROM servers;

FROM identifie la table (ou les tables) à interroger :

SELECT username, full_name, role
FROM users;

La plus simple requête SQL possible :

SELECT 1;

Elle ne lit aucune table — elle renvoie simplement la valeur 1. C’est un test rapide pour vérifier que votre connexion fonctionne.

WHERE restreint les lignes renvoyées à celles qui respectent une condition.

SELECT hostname, environment
FROM servers
WHERE active = 1;

Sans WHERE, la requête renvoie toutes les lignes de la table.

OpérateurSignificationExemple
=ÉgalWHERE environment = 'production'
<> ou !=DifférentWHERE role <> 'viewer'
<InférieurWHERE cpu_cores < 4
>SupérieurWHERE created_at > '2026-01-01'
<=Inférieur ou égalWHERE ram_gb <= 8
>=Supérieur ou égalWHERE disk_gb >= 200

Combinez plusieurs conditions :

-- Les deux conditions doivent être vraies
SELECT hostname, os
FROM servers
WHERE active = 1 AND environment = 'production';
-- Au moins une condition doit être vraie
SELECT username, role
FROM users
WHERE role = 'admin' OR role = 'operator';
-- Inverser une condition
SELECT hostname
FROM servers
WHERE NOT active;

Ces opérateurs simplifient les conditions courantes :

-- IN : appartenance à une liste (remplace plusieurs OR)
SELECT hostname, environment
FROM servers
WHERE environment IN ('production', 'staging');
-- BETWEEN : intervalle inclusif
SELECT hostname, created_at
FROM servers
WHERE created_at BETWEEN '2025-01-01' AND '2025-06-30';
-- LIKE : correspondance de motif (% = n'importe quoi, _ = un caractère)
SELECT hostname
FROM servers
WHERE hostname LIKE 'web-%';

LIKE est insensible à la casse pour les caractères ASCII en SQLite (et en MySQL avec les collations par défaut). En PostgreSQL, utilisez ILIKE pour ce comportement.

NULL signifie « absence de valeur ». Ce n’est ni zéro, ni une chaîne vide — c’est inconnu. On ne peut pas comparer avec =, il faut utiliser IS NULL ou IS NOT NULL :

-- Trouver le membre de l'équipe sans email
SELECT username, full_name
FROM users
WHERE email IS NULL;
-- Trouver les serveurs qui ont une note
SELECT hostname, notes
FROM servers
WHERE notes IS NOT NULL;

ORDER BY contrôle l’ordre des lignes dans le résultat.

-- Tri ascendant (par défaut)
SELECT hostname, created_at
FROM servers
ORDER BY created_at ASC;
-- Tri descendant (les plus récents d'abord)
SELECT hostname, created_at
FROM servers
ORDER BY created_at DESC;

Les colonnes de tri sont évaluées de gauche à droite. Le deuxième critère ne départage que les lignes à égalité sur le premier :

SELECT environment, hostname
FROM servers
ORDER BY environment ASC, hostname ASC;

Sur une table de millions de lignes, vous ne voulez pas tout récupérer. LIMIT restreint le nombre de lignes renvoyées.

-- Les 5 serveurs les plus récents
SELECT hostname, os, created_at
FROM servers
ORDER BY created_at DESC
LIMIT 5;
-- Serveurs 6 à 10 (pagination)
SELECT hostname, os, created_at
FROM servers
ORDER BY created_at DESC
LIMIT 5 OFFSET 5;

LIMIT et OFFSET fonctionnent avec SQLite, PostgreSQL et MySQL. C’est la syntaxe la plus courante.

Le standard SQL utilise une syntaxe différente, supportée par PostgreSQL et SQLite (mais pas MySQL) :

SELECT hostname, os
FROM servers
ORDER BY created_at DESC
FETCH FIRST 5 ROWS ONLY;

En pratique, LIMIT est quasi universel et plus simple — préférez-le.

Les alias renomment une colonne ou une table dans le résultat. C’est utile pour la lisibilité, surtout avec des expressions calculées.

-- Alias de colonne
SELECT hostname AS serveur, ip_address AS adresse_ip
FROM servers;
-- Alias de table (utile avec les jointures — guide 3)
SELECT s.hostname, s.os
FROM servers AS s
WHERE s.active = 1;

Le mot-clé AS est optionnel (on peut écrire FROM servers s), mais le garder rend le code plus explicite.

DISTINCT supprime les lignes identiques du résultat :

-- Liste des systèmes d'exploitation distincts
SELECT DISTINCT os
FROM servers;
-- Combinaison de colonnes distinctes
SELECT DISTINCT os, environment
FROM servers;

Les commentaires documentent vos requêtes — très utile dans les scripts :

-- Commentaire sur une ligne
/* Commentaire
sur plusieurs
lignes */
SELECT hostname -- on sélectionne le nom d'hôte
FROM servers;

Vous avez maintenant toutes les bases. Pratiquez sur la base infra.db :

  1. Listez tous les serveurs de production actifs, triés par date de création (les plus récents d’abord).

    SELECT hostname, os, datacenter, created_at
    FROM servers
    WHERE environment = 'production' AND active = 1
    ORDER BY created_at DESC;
  2. Trouvez le membre de l’équipe qui ne s’est jamais connecté (colonne last_login à NULL).

    SELECT username, full_name, created_at
    FROM users
    WHERE last_login IS NULL;
  3. Listez les 3 derniers serveurs ajoutés à l’inventaire.

    SELECT hostname, os, environment, created_at
    FROM servers
    ORDER BY created_at DESC
    LIMIT 3;
  4. Cherchez les serveurs dont le hostname commence par db- parmi les serveurs actifs.

    SELECT hostname, ip_address, environment
    FROM servers
    WHERE active = 1 AND hostname LIKE 'db-%'
    ORDER BY hostname;
  5. Listez les systèmes d’exploitation distincts utilisés dans l’infrastructure.

    SELECT DISTINCT os, os_version
    FROM servers
    WHERE active = 1
    ORDER BY os;
  6. Trouvez les serveurs avec plus de 16 Go de RAM dans le datacenter paris-dc1.

    SELECT hostname, ram_gb, disk_gb
    FROM servers
    WHERE ram_gb > 16 AND datacenter = 'paris-dc1'
    ORDER BY ram_gb DESC;
SymptômeCause probableSolution
Résultat vide inattenduCondition WHERE trop restrictiveRetirez les filtres un par un pour identifier le coupable
WHERE email = NULL ne renvoie rienNULL ne se compare pas avec =Utilisez IS NULL
Résultat dans un ordre différent à chaque exécutionPas de ORDER BYAjoutez un ORDER BY explicite
SELECT * très lent sur une grosse tableToutes les colonnes + toutes les lignesListez les colonnes et ajoutez LIMIT ou WHERE
Erreur no such columnNom de colonne mal orthographiéVérifiez avec .schema table dans sqlite3, \d table dans psql
  • SELECT + FROM forment la requête minimale — tout le reste est optionnel
  • WHERE filtre les lignes avant qu’elles ne soient renvoyées — c’est votre outil principal
  • NULL n’est pas une valeur — on le teste toujours avec IS NULL / IS NOT NULL
  • AND est évalué avant OR — utilisez des parenthèses pour clarifier
  • ORDER BY est le seul moyen de garantir l’ordre du résultat
  • LIMIT empêche de ramener des millions de lignes par accident
  • Préférez les colonnes explicites à SELECT * dans les scripts et en production
  • La base fil rouge infra.db vous accompagnera tout au long des 5 guides

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn