Mirajv1.0
FR

3. Prise en main

Ce chapitre vous guide pas à pas : démarrer un serveur MIRAJ, s'y connecter, créer une base, des tables, y insérer des données, les interroger, les joindre, travailler en transaction, indexer et inspecter le schéma. Le même parcours est fait deux fois : d'abord sur une instance en langage MIRAJ (le langage par défaut, sections 3.1 à 3.10), puis sur une instance en langage PostgreSQL (section 3.11). À la fin, vous saurez faire tourner un cas d'usage complet dans l'un et l'autre langage.

Les exemples utilisent miraj-cli, la console SQL fournie avec MIRAJ, connectée au serveur par le réseau ; tout se transpose sans changement au client SQL ou au pilote de votre choix. Les résultats sont recopiés tels que la console les affiche.

3.1 Démarrer le serveur#

miraj-server.exe --root D:\donnees --log
================================================================================
Compte root@localhost créé avec le mot de passe provisoire : W2nRUci5fQVdcc6PUnuRccig
Il n'est affiché qu'une fois et n'est écrit nulle part : notez-le, puis changez-le :
  ALTER USER root@localhost IDENTIFIED BY 'nouveau mot de passe';
================================================================================
MIRAJ 1.0.0 Entreprise - serveur console sur 127.0.0.1:7007, dossier "D:\donnees", 12 fils, licence MRJ-2026-000123 (Société Exemple SA), valide jusqu'au 2027-10-11.
Configuration : D:\donnees\miraj_config.xml.

Le dossier D:\donnees est créé s'il n'existe pas, avec un compte root local dont le mot de passe, tiré au sort, s'affiche une seule fois : notez-le, il sert à toutes les connexions, puis remplacez-le dès que possible (ALTER USER root@localhost IDENTIFIED BY '...'). Pour le choisir vous-même dès le départ : --initial-root-password <mot de passe> ou la variable d'environnement MIRAJ_INITIAL_ROOT_PASSWORD (voir 2.3). La ligne MIRAJ 1.0.0 … donne l'édition, l'adresse d'écoute, le dossier, le nombre de fils et la licence. Laissez cette fenêtre ouverte : le serveur y reste actif.

Sous macOS et Linux, la commande s'écrit de même (miraj-server --root /chemin/des/donnees --log). Avec l'assistant d'installation de Windows ou le paquet macOS, le serveur est déjà démarré en service : passez directement à 3.2 avec le mot de passe choisi à l'installation.

3.2 Se connecter avec miraj-cli#

Ouvrez une seconde fenêtre et connectez la console au serveur ; --password sans valeur demande le mot de passe sans l'afficher :

miraj-cli.exe --host 127.0.0.1 --port 7007 --user root --password
MIRAJ 1.0.0 - connecté (langage MIRAJ) - tapez \help pour l'aide, \q pour quitter.
miraj>

La console reconnaît d'elle-même le langage de l'instance. Vous êtes maintenant dans le mode interactif (REPL) : chaque instruction SQL se termine par un point-virgule et peut s'écrire sur plusieurs lignes. Pour un script, la variable d'environnement MIRAJ_PASSWORD évite la saisie, et -e "<SQL>" ou un fichier .sql en argument exécutent les instructions puis quittent.

miraj-cli --root D:\donnees ouvre aussi le dossier directement, sans réseau ni compte, mais seulement serveur arrêté : un dossier de données n'est ouvert que par un processus à la fois (Dossier de données « D:\donnees » déjà ouvert par un autre processus MIRAJ sinon).

3.3 Créer une base#

CREATE DATABASE boutique;
USE boutique;
OK, 1 ligne(s) affectée(s)
OK, 0 ligne(s) affectée(s)

L'invite affiche désormais le nom de la base courante :

boutique>

3.4 Créer une table#

Créons une table de clients, avec une clé primaire auto-incrémentée, une contrainte UNIQUE, des colonnes obligatoires et une date de création par défaut :

CREATE TABLE clients (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    nom         VARCHAR(80) NOT NULL,
    email       VARCHAR(120) NOT NULL UNIQUE,
    cree_le     DATETIME DEFAULT CURRENT_TIMESTAMP
);
OK, 0 ligne(s) affectée(s)

Créons également une table de commandes, liée aux clients par une clé étrangère :

CREATE TABLE commandes (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    client_id   INT NOT NULL,
    montant     DECIMAL(10,2) NOT NULL,
    passee_le   DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (client_id) REFERENCES clients(id)
);
OK, 0 ligne(s) affectée(s)

3.5 Insérer des données#

INSERT INTO clients (nom, email) VALUES
    ('Amel Kaci', '[email protected]'),
    ('Youssef Ben Ali', '[email protected]'),
    ('Claire Dupont', '[email protected]');
OK, 3 ligne(s) affectée(s)
INSERT INTO commandes (client_id, montant) VALUES
    (1, 59.90),
    (1, 12.50),
    (2, 249.00);
SELECT LAST_INSERT_ID();
OK, 3 ligne(s) affectée(s)
+------------------+
| LAST_INSERT_ID() |
+------------------+
|                1 |
+------------------+
1 ligne(s)

LAST_INSERT_ID() rend la première valeur AUTO_INCREMENT générée par la dernière instruction INSERT de la session.

Une tentative d'insertion qui viole la contrainte UNIQUE sur email est refusée, avec le code d'erreur et le SQLSTATE :

INSERT INTO clients (nom, email) VALUES ('Doublon', '[email protected]');
ERREUR 1062 (23000) : Duplicate entry '[email protected]' for key 'email'

3.6 Interroger les données : WHERE et ORDER BY#

SELECT id, nom, email FROM clients WHERE nom LIKE '%dupont%' OR nom LIKE 'a%' ORDER BY nom;
+----+---------------+---------------------------+
| id | nom           | email                     |
+----+---------------+---------------------------+
|  1 | Amel Kaci     | [email protected]     |
|  3 | Claire Dupont | [email protected] |
+----+---------------+---------------------------+
2 ligne(s)

Les comparaisons de texte ignorent la casse et les accents (interclassement par défaut utf8mb4_general_ci, voir 13. Interclassements) : '%dupont%' trouve « Dupont », 'a%' trouve « Amel ».

3.7 Faire une jointure#

Listons les commandes avec le nom du client correspondant, triées par montant décroissant :

SELECT c.nom, o.id AS commande, o.montant
FROM commandes o
JOIN clients c ON c.id = o.client_id
ORDER BY o.montant DESC;
+-----------------+----------+---------+
| nom             | commande | montant |
+-----------------+----------+---------+
| Youssef Ben Ali |        3 |  249.00 |
| Amel Kaci       |        1 |   59.90 |
| Amel Kaci       |        2 |   12.50 |
+-----------------+----------+---------+
3 ligne(s)

Un agrégat par client, avec LEFT JOIN pour garder les clients sans commande, et GROUP BY :

SELECT c.nom, COUNT(o.id) AS nb_commandes, SUM(o.montant) AS total
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
GROUP BY c.id
ORDER BY total DESC;
+-----------------+--------------+--------+
| nom             | nb_commandes | total  |
+-----------------+--------------+--------+
| Youssef Ben Ali |            1 | 249.00 |
| Amel Kaci       |            2 |  72.40 |
| Claire Dupont   |            0 |   NULL |
+-----------------+--------------+--------+
3 ligne(s)

COUNT(o.id) ne compte que les commandes trouvées (0 pour Claire Dupont) ; COUNT(*) compterait aussi la ligne complétée par NULL de la jointure externe et rendrait 1. SUM d'aucune valeur vaut NULL.

3.8 Travailler en transaction#

Hors transaction, chaque instruction est validée aussitôt (autocommit). START TRANSACTION regroupe plusieurs instructions, que COMMIT valide ensemble et que ROLLBACK annule :

START TRANSACTION;
UPDATE commandes SET montant = montant * 2 WHERE client_id = 1;
SELECT SUM(montant) FROM commandes WHERE client_id = 1;
ROLLBACK;
SELECT SUM(montant) FROM commandes WHERE client_id = 1;
OK, 0 ligne(s) affectée(s)
OK, 2 ligne(s) affectée(s)
+--------------+
| SUM(montant) |
+--------------+
|       144.80 |
+--------------+
1 ligne(s)
OK, 0 ligne(s) affectée(s)
+--------------+
| SUM(montant) |
+--------------+
|        72.40 |
+--------------+
1 ligne(s)

La transaction voit ses propres modifications ; après ROLLBACK, les montants sont revenus à leur valeur. Le modèle de concurrence (contrôle multiversion, mise à jour différée, conflits à réessayer) est décrit au chapitre 14.

3.9 Créer un index#

Un index accélère les recherches sur une colonne fréquemment filtrée qui n'est ni clé primaire ni UNIQUE :

CREATE INDEX idx_clients_nom ON clients (nom);
SELECT INDEX_NAME, COLUMN_NAME, NON_UNIQUE
FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = 'boutique' AND TABLE_NAME = 'clients'
ORDER BY INDEX_NAME;
OK, 0 ligne(s) affectée(s)
+-----------------+-------------+------------+
| INDEX_NAME      | COLUMN_NAME | NON_UNIQUE |
+-----------------+-------------+------------+
| email           | email       |          0 |
| idx_clients_nom | nom         |          1 |
| PRIMARY         | id          |          0 |
+-----------------+-------------+------------+
3 ligne(s)

La clé primaire (PRIMARY) et la contrainte UNIQUE (index email) ont leur propre index. SHOW INDEX FROM clients donne le détail complet. Un index se retire avec :

DROP INDEX idx_clients_nom ON clients;
OK, 0 ligne(s) affectée(s)

Un index dont une clé étrangère a besoin ne peut pas être retiré (erreur 1553 Cannot drop index '…': needed in a foreign key constraint).

3.10 Voir le schéma#

Lister les tables de la base courante :

SHOW TABLES;
+--------------------+
| Tables_in_boutique |
+--------------------+
| clients            |
| commandes          |
+--------------------+
2 ligne(s)

Décrire une table :

DESCRIBE clients;
+---------+--------------+------+-----+-------------------+----------------+
| Field   | Type         | Null | Key | Default           | Extra          |
+---------+--------------+------+-----+-------------------+----------------+
| id      | int(11)      | NO   | PRI | NULL              | auto_increment |
| nom     | varchar(80)  | NO   |     | NULL              |                |
| email   | varchar(120) | NO   | UNI | NULL              |                |
| cree_le | datetime     | YES  |     | CURRENT_TIMESTAMP |                |
+---------+--------------+------+-----+-------------------+----------------+
4 ligne(s)

Voir la définition complète d'une table, telle qu'elle se rejoue :

SHOW CREATE TABLE commandes;
CREATE TABLE `commandes` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `client_id` int(11) NOT NULL,
  `montant` decimal(10,2) NOT NULL,
  `passee_le` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  CONSTRAINT `commandes_ibfk_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`)
)

(la console encadre ce texte dans un tableau à deux colonnes, Table et Create Table). La clé étrangère sans nom a reçu le nom commandes_ibfk_1.

Dans la console miraj-cli, les raccourcis \d (sans argument : équivalent à SHOW TABLES ; avec un nom de table : équivalent à DESCRIBE) et \l (équivalent à SHOW DATABASES) évitent de retaper ces instructions ; \help liste toutes les commandes de la console.

3.11 Le même parcours en langage PostgreSQL#

Une instance démarrée en langage PostgreSQL parle la grammaire et le protocole de PostgreSQL : psql, psycopg2, pgjdbc, Npgsql et les autres clients PostgreSQL s'y connectent, et miraj-cli aussi. Son manuel complet commence au chapitre 32 ; cette section en reprend l'essentiel sur l'exemple précédent.

3.11.1 Démarrer l'instance#

Le langage se choisit au démarrage, pour toute l'instance, par l'élément POSTGRESQL de sql_mode (ou par la question Langage SQL de l'instance de l'assistant d'installation) :

miraj-server.exe --root D:\donnees-pg --log --sql-mode POSTGRESQL,STRICT_TRANS_TABLES
MIRAJ 1.0.0 Entreprise - serveur console sur 127.0.0.1:7007, langage PostgreSQL, dossier "D:\donnees-pg", 12 fils, licence MRJ-2026-000123 (Société Exemple SA), valide jusqu'au 2027-10-11.
Configuration : D:\donnees-pg\miraj_config.xml.

La mention langage PostgreSQL confirme le choix. Le protocole PostgreSQL est servi sur le port principal (--port, 7007 par défaut). Le compte root est créé et son mot de passe affiché comme en 3.1.

3.11.2 Se connecter#

Avec psql :

psql -h 127.0.0.1 -p 7007 -U root

ou avec la console de MIRAJ, qui reconnaît le langage de l'instance :

miraj-cli.exe --host 127.0.0.1 --port 7007 --user root --password
MIRAJ 1.0.0 - connecté (langage PostgreSQL) - tapez \help pour l'aide, \q pour quitter.
miraj=>
SELECT version(), current_user;
+--------------------------------------------------------+--------------+
| version()                                              | current_user |
+--------------------------------------------------------+--------------+
| PostgreSQL 16.4 (MIRAJ 1.0.0) on aarch64-macos, 64-bit | root         |
+--------------------------------------------------------+--------------+
1 ligne(s)

(la plateforme en fin de version dépend de la machine). Dans une instance en langage PostgreSQL, une base MIRAJ est un schéma : CREATE SCHEMA boutique crée la base boutique, et SET search_path choisit le schéma courant (voir 32.2).

3.11.3 Créer un schéma et des tables#

CREATE SCHEMA boutique;
SET search_path TO boutique;

CREATE TABLE clients (
    id       serial PRIMARY KEY,
    nom      varchar(80) NOT NULL,
    email    varchar(120) NOT NULL UNIQUE,
    cree_le  timestamp DEFAULT now()
);

CREATE TABLE commandes (
    id         serial PRIMARY KEY,
    client_id  integer NOT NULL REFERENCES clients (id),
    montant    numeric(10,2) NOT NULL,
    passee_le  timestamp DEFAULT now()
);
OK, 0 ligne(s) affectée(s)
OK, 0 ligne(s) affectée(s)
OK, 0 ligne(s) affectée(s)
OK, 0 ligne(s) affectée(s)

L'invite devient boutique=>. serial remplace INT AUTO_INCREMENT, timestamp et now() remplacent DATETIME et CURRENT_TIMESTAMP, numeric remplace DECIMAL.

3.11.4 Écrire des données#

RETURNING rend les lignes écrites, avec leurs valeurs générées :

INSERT INTO clients (nom, email) VALUES
    ('Amel Kaci', '[email protected]'),
    ('Youssef Ben Ali', '[email protected]'),
    ('Claire Dupont', '[email protected]')
RETURNING id, nom;
+----+-----------------+
| id | nom             |
+----+-----------------+
|  1 | Amel Kaci       |
|  2 | Youssef Ben Ali |
|  3 | Claire Dupont   |
+----+-----------------+
3 ligne(s)
INSERT INTO commandes (client_id, montant) VALUES
    (1, 59.90),
    (1, 12.50),
    (2, 249.00);
OK, 3 ligne(s) affectée(s)

Le doublon sur email est refusé avec le SQLSTATE de PostgreSQL :

INSERT INTO clients (nom, email) VALUES ('Doublon', '[email protected]');
ERREUR 23505 : Duplicate entry '[email protected]' for key 'email'

ON CONFLICT … DO NOTHING ignore la ligne en conflit au lieu de lever l'erreur :

INSERT INTO clients (nom, email) VALUES ('Doublon', '[email protected]')
ON CONFLICT (email) DO NOTHING;
OK, 0 ligne(s) affectée(s)

3.11.5 Interroger et joindre#

LIKE y distingue la casse ; ILIKE l'ignore :

SELECT id, nom, email FROM clients WHERE nom ILIKE '%dupont%' OR nom ILIKE 'a%' ORDER BY nom;
+----+---------------+---------------------------+
| id | nom           | email                     |
+----+---------------+---------------------------+
|  1 | Amel Kaci     | [email protected]     |
|  3 | Claire Dupont | [email protected] |
+----+---------------+---------------------------+
2 ligne(s)

Jointure, limitée aux deux premières lignes par FETCH FIRST :

SELECT c.nom, o.id AS commande, o.montant
FROM commandes o
JOIN clients c ON c.id = o.client_id
ORDER BY o.montant DESC
FETCH FIRST 2 ROWS ONLY;
+-----------------+----------+---------+
| nom             | commande | montant |
+-----------------+----------+---------+
| Youssef Ben Ali |        3 |  249.00 |
| Amel Kaci       |        1 |   59.90 |
+-----------------+----------+---------+
2 ligne(s)

Agrégat par client ; NULLS LAST range le total NULL en fin de liste :

SELECT c.nom, count(o.id) AS nb_commandes, sum(o.montant) AS total
FROM clients c
LEFT JOIN commandes o ON o.client_id = c.id
GROUP BY c.id, c.nom
ORDER BY total DESC NULLS LAST;
+-----------------+--------------+--------+
| nom             | nb_commandes | total  |
+-----------------+--------------+--------+
| Youssef Ben Ali |            1 | 249.00 |
| Amel Kaci       |            2 |  72.40 |
| Claire Dupont   |            0 |   NULL |
+-----------------+--------------+--------+
3 ligne(s)

3.11.6 Transaction#

BEGIN;
UPDATE commandes SET montant = montant * 2 WHERE client_id = 1;
SELECT sum(montant) FROM commandes WHERE client_id = 1;
ROLLBACK;
SELECT sum(montant) FROM commandes WHERE client_id = 1;
OK, 0 ligne(s) affectée(s)
OK, 2 ligne(s) affectée(s)
+--------------+
| sum(montant) |
+--------------+
|       144.80 |
+--------------+
1 ligne(s)
OK, 0 ligne(s) affectée(s)
+--------------+
| sum(montant) |
+--------------+
|        72.40 |
+--------------+
1 ligne(s)

3.11.7 Index et schéma#

CREATE INDEX idx_clients_nom ON clients (nom);
SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'clients' ORDER BY indexname;
DROP INDEX idx_clients_nom;
OK, 0 ligne(s) affectée(s)
+-----------------+-----------------------------------------------------------------------+
| indexname       | indexdef                                                              |
+-----------------+-----------------------------------------------------------------------+
| clients_pkey    | CREATE UNIQUE INDEX clients_pkey ON boutique.clients USING btree (id) |
| email           | CREATE UNIQUE INDEX email ON boutique.clients USING btree (email)     |
| idx_clients_nom | CREATE INDEX idx_clients_nom ON boutique.clients USING btree (nom)    |
+-----------------+-----------------------------------------------------------------------+
3 ligne(s)
OK, 0 ligne(s) affectée(s)

Le catalogue se lit par information_schema (ou pg_catalog, et les commandes \dt, \d table de psql) :

SELECT table_name FROM information_schema.tables WHERE table_schema = 'boutique' ORDER BY table_name;

SELECT column_name, data_type, is_nullable, column_default
FROM information_schema.columns
WHERE table_schema = 'boutique' AND table_name = 'clients'
ORDER BY ordinal_position;
+------------+
| table_name |
+------------+
| clients    |
| commandes  |
+------------+
2 ligne(s)
+-------------+-----------------------------+-------------+-------------------------------------+
| column_name | data_type                   | is_nullable | column_default                      |
+-------------+-----------------------------+-------------+-------------------------------------+
| id          | integer                     | NO          | nextval('clients_id_seq'::regclass) |
| nom         | character varying           | NO          | NULL                                |
| email       | character varying           | NO          | NULL                                |
| cree_le     | timestamp without time zone | YES         | now()                               |
+-------------+-----------------------------+-------------+-------------------------------------+
4 ligne(s)

La colonne serial a pour valeur par défaut la séquence clients_id_seq, créée avec la table.

3.12 Pour la suite#

Vous savez maintenant créer une base, des tables avec contraintes, insérer des données, les interroger avec des jointures et de l'agrégation, travailler en transaction, indexer et inspecter le schéma, dans les deux langages. Les chapitres suivants détaillent chaque sujet :