0% ont trouvé ce document utile (0 vote)
442 vues103 pages

Apprendre Mysql

Ce document décrit différents systèmes de gestion de base de données relationnelles MySQL et ses forks ainsi que leur installation et configuration sous différents systèmes d'exploitation.

Transféré par

Natheo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
442 vues103 pages

Apprendre Mysql

Ce document décrit différents systèmes de gestion de base de données relationnelles MySQL et ses forks ainsi que leur installation et configuration sous différents systèmes d'exploitation.

Transféré par

Natheo
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
Vous êtes sur la page 1/ 103

Un livre de Wikilivres.

Une version à jour et éditable de ce livre est disponible sur Wikilivres,


une bibliothèque de livres pédagogiques, à l'URL:
//fr.wikibooks.org/wiki/MySQL

Vous avez la permission de copier, distribuer et/ou modifier ce document


selon les termes de la Licence de documentation libre GNU, version 1.2
ou plus récente publiée par la Free Software Foundation; sans sections
inaltérables, sans texte de première page de couverture et sans Texte de
dernière page de couverture. Une copie de cette licence est inclue dans
l'annexe nommée « Licence de documentation libre GNU ».

Pourquoi MySQL ?
Gratuiciel en licence GPL version 2.
Facile d'utilisation : intuitif et ergonomique.
Vitesse performante [1] .
Supporte la plupart des commandes SQL ANSI.
Support technique complet, avec des tutoriels en ligne, des forums, mailing list (lists.mysql.com),et des
contrats payants possibles.
Portabilité : importation et exportation faciles vers des fichiers Excel et autres bases de données.
Échelonnable : pratique aussi bien pour des petites bases, que pour celles contenant des milliards
d'enregistrements avec plusieurs téraoctets de données et des centaines de milliers de tables.
Contrôle des permission des utilisateurs précis.

La licence MySQL

MySQL est disponible sous un schéma double licence :

Licence publique générale GNU version 2 : copyleft, permettant d'utiliser MySQL à des fins
commerciales ou pas, tant que l'application est à la même licence. Il y existe par ailleurs une exception
Free/Libre Open Source Software (FLOSS) qui autorise des programmes non GPL mais gratuits à se
connecter au serveur MySQL (comme par exemple des programmes en licence PHP).
Une soi-disante "commerciale" (bien que GNU GPL puisse être aussi utilisée en commercial mais pas
propriétaire), licence payante, conférant le droit d'intégrer MySQL avec une application non FLOSS,
redistribuable en dehors de son organisation. Mais ces bibliothèque ne peuvent pas se connecter aux
nouvelles versions de MySQL.

MySQL et ses forks


MySQL étant un freeware, il a donc engendré des fork officieux.

MariaDB

En 2008, Sun Microsystems acheta MySQL, puis fût acheté par Oracle en 2010. Après l'acquisition, le
processus de développement changea. L'équipe commença à sortir de nouvelles versions de MySQL moins
fréquemment, avec du nouveau code moins testé, par une communauté moins active

En 2009 Monty Widenius, fondateur de MySQL, quitta l'entreprise pour en créer une autre, appelée The
Monty Program (http://www.askmonty.org/) [archive]. Son fork fût appelé MariaDB, il permet de :

importer le nouveau code qui sera ajouté à la branche MySQL, en le rendant plus stable ;
nettoyer le code MySQL ;
ajouter des contributions de la communauté (plugins et fonctionnalités) ;
développer le moteur de stockage Aria, anciennement Maria ;
augmenter les performances ;
ajouter d'autres fonctionnalités au serveur.

Sa licence est GNU GPLv2, héritée de MySQL.

La plateforme primaire de MariaDB est GNU/Linux, mais il tourne aussi sur Windows [2] . Les moteurs de
stockage suivants ont été ajoutés :

Aria (utilisé pour les tables internes)


PBXT
XtraDB
FederatedX
SphinxSE
OQGRAPH

Drizzle

En 2008 Brian Aker, architecte en chef de MySQL, quitta le projet pour démarrer un nouveau fork appelé
Drizzle (http://www.drizzle.org/) [archive]. Initialement financé par Oracle, Drizzle l'est maintenant par
Rackspace. Ses caractéristiques sont :

seule une petite partie du code MySQL a été conservée : les fonctionnalités essentielles ;
modularité : beaucoup de chose peut être implémenté sous forme de plugins ;
optimisé multiprocesseur et multicore 64 bits ;
seuls les systèmes GNU/Linux et UNIX sont supportés.

Il n'existe pas de version publique de ce fork. Il est en licence GNU GPLv2 (héritée de MySQL), mais une
licence BSD peut être appliquée.

OurDelta
OurDelta (http://ourdelta.org/) [archive] est un autre fork, maintenu par Open Query. La première branche
(5.0), est basée sur MySQL 5.0. La 5.1 est issue de MariaDB. OurDelta contient des patchs développés par
la communauté ou des tiers. Il fournit des packages pour certaines distributions GNU/Linux : Debian,
Ubuntu, Red Hat/CentOS. Il n'est pas disponible sur d'autres plateformes mais son code source est
disponible gratuitement.

Percona Server

Percona Server set un fork maintenu par Percona. Il propose le moteur de stockage ExtraDB, fork
d'InnoDB, et des patchs d'amélioration des performances.

Références
1. ↑ http://www.mysql.com/why-mysql/benchmarks/
2. ↑ http://archive.mariadb.org/mariadb-5.5.28a/

Microsoft Windows
Tout-en-un

Des logiciels tout-en-un (serveur Web, base de donnée MySQL, et PHP) permettent de s'affranchir d'une
installation fastidieuse et rédhibitoire pour le débutant :

1. EasyPHP téléchargement (http://www.easyphp.org) [ archive ] : n'a pas vocation à être installé pour de la
production, mais pour le développement.
2. WAMP téléchargement (http://www.wampserver.com) [ archive ] : est du même type qu'EasyPHP : ce logiciel
installe facilement un serveur Web Apache, une base de données MySQL et PHP 4 et 5. Il a l'avantage
de permettre de passer facilement de PHP 4 à PHP 5, sans avoir à refaire une installation ou une
compilation. Tout comme EasyPHP, c'est un environnement de développement, et non un
environnement de production. Attention : la résolution des noms d'hôtes se réalise séparément. Les
installations WAMP servent à tester en local sur votre PC. Dans la plupart des cas, il suffit d'utiliser le
fichier Hosts local, comme on le ferait sur une machine Linux, afin de lier des noms aux adresses IP.
Dans Windows XP, Vista et 7, ce fichier se trouve dans le répertoire systemroot\System32\Drivers\Etc.
Il peut se faire que le service ait déjà été configuré. Lorsque vous vous en doutez, contactez votre
administrateur réseau. Remarque : vous trouverez une liste des possibilités de résolution de noms avec
MS Windows sur microsoft.com (http://www.microsoft.com/technet/prodtechnol/winxppro/reskit
/c24621675.mspx) [archive].
3. XAMPP téléchargement (http://www.apachefriends.org/fr/xampp.html) [ archive ] : est du même type qu'EasyPHP ou
WAMP, le deuxième P étant pour Perl. Son usage est recommandé avec PHPEclipse
(http://www.phpeclipse.de/tiki-view_articles.php) [archive].
4. The Uniform Server téléchargement (http://www.uniformserver.com) [ archive] : en anglais seulement avec
Apache2, Perl5, PHP5, MySQL5, phpMyAdmin.

Message d'erreur relatif à SSL

Pour l'instant, WAMP ne supporte pas encore le Secure Socket Layer (SSL). L'installation se finit par un
message qui vous informe de ce fait. Afin de pouvoir travailler sans problèmes, éditez le fichier c:\windows
\php.ini. Cherchez dans ce fichier la ligne qui commence avec extension=php_openssl.dll. Commentez cette
ligne en la faisant précéder d'un point-virgule :
;extensions=php_openssl.dll

Si tout se passe bien, vous pouvez ouvrir la page de test dans votre navigateur.

Installation manuelle

Apache est disponible sur le site Web de Apache Software Foundation apache.org
(http://www.apache.org) [archive].
PHP est téléchargeable sur le site officiel de php (http://www.php.net) [archive]. Choisissez le fichier au
format ZIP.
Enfin, vous trouverez MySQL sur mysql.com (http://www.mysql.com) [archive].

Installer Apache

Pour installer Apache, double-cliquez sur le fichier exécutable, et suivez les instructions d'installation
automatique.

Si vous installez Apache sur un ordinateur de développement, renseignez le champ "nom de domaine" avec
la valeur localhost.

Si vous installez un serveur de production et que vous disposez d'un nom de domaine, vous devriez disposer
des informations nécessaires concernant votre nom de domaine, fournies par le registrar.

Debian / Ubuntu
Apache seul

Pour plus de détails voir : Le système d'exploitation GNU-Linux/Le serveur Web Apache.

commande nécessitant les privilèges root

# apt-get install apache2

Le service peut ne pas être lancé par défaut, mais même s'il l'est on peut quand-même essayer de l'activer
avec :

commande nécessitant les privilèges root

# /etc/init.d/apache2 start

On peut ensuite tester le serveur, pour voir si une page s'affiche ou s'il refuse la connexion :

commande

$ lynx http://localhost/

Cette adresse est la boucle locale, elle peut aussi être rentrée directement dans tout navigateur web.
LAMP

Logiciel tout-en-un pour Linux (Apache + MySQL + PHP), comme WAMP pour Windows.

Gentoo
Premièrement il faut installer Apache si ce n'est pas déjà fait :

emerge apache

Ensuite, il faut installer PHP :

emerge dev-lang/php

Puis il faut qu'apache utilise PHP dans sa configuration.

Code: Configuration de apache

# nano -w /etc/conf.d/apache2
APACHE2_OPTS="-D PHP5"

Test des bases de données


Pour tester si les comptes utilisateurs peuvent se connecter au serveur de bases de données il suffit de lancer
un fichier de testBDD.php comme suit [1] :

<?php
$connexion = mysql_connect("localhost", "mysql_user", "mysql_password");
if ($connexion) {
print ("Connexion OK");
}
else {
print ("Connexion KO");
}
?>

En cas d'erreur :

1045 échec de la connexion : le compte "mysql_user" n'a pas le droit de se connecter au serveur, il faut le
recréer dans PHPmyadmin. Le faire en cochant "créer une base à son nom", même si elle existe déjà (cela
ne l'effacera pas).
1044 : le compte "mysql_user" n'a pas le droit de se connecter à la base, il faut le modifier dans
PHPmyadmin.
1449 The user specified as a definer does not exist :

GRANT ALL privileges ON NomBase TO `NomUtilisateur`@`localhost`


Certaines fonctions permettent d'afficher des erreurs plus précises :

MySQL : mysql_error()
MS-SQL : sqlsrv_errors()

Erreurs possibles
S'il est impossible de créer des fichiers ou répertoires depuis un navigateur c'est que le serveur n'autorise pas
l'utilisateur apache à le faire dans le répertoire du site.

Références
1. ↑ http://www.phpsources.org/tutoriel-connection.htm

INFORMATION_SCHEMA
information_schema est une base de données virtuelle apparue dans
MySQL 5, qui contient des métadonnées sur le serveur et ses bases.
Elle n'est pas modifiable (ni la structure, ni les données), on peut
donc juste la lire.

Beaucoup de ses informations sont récupérables aussi avec la Base information_schema dans
commande SHOW, plus rapide. Toutefois information_schema est phpMyAdmin.
plus flexible.

La table de INFORMATION_SCHEMA sur les bases est SCHEMATA. Le programme mysqlshow (en ligne
de commande DOS/Unix) peut aussi être utilisé à la place.

Cela ne peut fonctionner que si le serveur est démarré, et sans l'option --skip-all-databases.

En l'absence des privilèges SHOW DATABASES, seule les bases sur lesquelles le compte a des permissions
seront visibles.

Lister les bases


Les commandes SQL suivante fournissent les informations relatives aux bases de données situées sur le
serveur courant.

Toutes :

SHOW DATABASES;

le mot clé SCHEMA peut être utilisé en lieu et place de DATABASES. MySQL ne supporte pas les SCHEMA des
standards SQL, donc il est synonyme de DATABASES. il a été ajouté pour la compatibilité avec d'autres
SGBD.
Ajouter un filtre sur les noms des bases

SHOW DATABASES LIKE 'expression';

L'opérateur LIKE fonctionne selon le langage de manipulation de données standard. Donc il est faisable de
lister toutes les bases commençant pas 'wiki' ainsi :

SHOW DATABASES LIKE 'wiki%';

Filtres complexes

En utilisant la clause WHERE :

SHOW DATABASES WHERE conditions;

Elle autorise les expressions rationnelles, les opérateur de comparaison '=', '<' et '>', et les fonctions sur les
chaines de caractères.

Lister les tables et les vues


Les tables `TABLES` et `VIEWS` de la base INFORMATION_SCHEMA fournissent des informations sur
les tables et les vues de toutes les bases du serveur.

Les commandes SQL suivantes donnant relativement peu d'information sur les vues, il faudra recourir à la
table `VIEWS` pour les métadonnées.

mysqlshow peut aussi être utilisé à la place.

Show all tables

USE `database`;
SHOW TABLES;

SHOW TABLES FROM `database`;

Les deux formes sont équivalentes.

Appliquer un filtre

la syntaxe est la même que pour les bases :


SHOW TABLES LIKE `expression`;
SHOW TABLES WHERE condition;

De plus, par défaut SHOW TABLES ne retourne que la colonne du nom des tables. Le mot FULL permet d'en
ajouter une deuxième appelée `Table_type` :

SHOW FULL TABLES;

Elle peut contenir trois valeurs différentes : 'BASE TABLE' pour les tables, 'VIEW' pour les vues, et
'SYSTEM VIEW' pour les tables spéciales du serveur (généralement celles de la base
INFORMATION_SCHEMA).

Donc pour lister les vues :

SHOW FULL TABLES WHERE `Table_type`='VIEW';

Filtrer les tables ouvertes

La liste des tables non temporaires (sans les vues) ouvertes dans le cache :

SHOW OPEN TABLES;

Lister les champs


Les commandes suivantes correspondent aux informations de la table COLUMNS de
INFORMATION_SCHEMA.

mysqlshow le permet également.

DESCRIBE

USE `base`;
DESCRIBE `table`;
-- ou
DESCRIBE `base`.`table`;

Le résultat contient six colonnes :

Field Type Null Key Default Extra


... ... ... ... ... ...
DESC est un alias de DESCRIBE.

USE `base`;
DESC `table` 'filtre';

'filtre' peut être un nom de colonne. S'il est spécifié, seule cette colonne sera affichée. Si 'filtre' contient '%'
ou '_', il sera évalué comme une condition LIKE. Par exemple, pour obtenir tous les champs commençant par
'wiki' :

DESC `table` 'wiki%';

EXPLAIN

Synonyme de DESC :

EXPLAIN `table`;

SHOW FIELDS

Autre synonyme de DESC :

SHOW FIELDS FROM `table`;

Remarque : le mot FULL rajoute une colonne "Privileges" et une "Comment" :

SHOW FULL FIELDS FROM `table`;

Field Type Collation Null Key Default Extra Privileges Comment


... ... ... ... ... ... ... ... ...

SHOW COLUMNS

Autre synonyme de DESC :

SHOW COLUMNS FROM `table`;

En fait FIELDS et COLUMNS sont synonymes. EXPLAIN et DESC ne supportent pas toutes leurs clauses
(filtre).

De plus, les syntaxes ci-dessous sot équivalentes :

SHOW COLUMNS FROM `table` FROM `base`;


-- ou
SHOW COLUMNS FROM `base`.`table`;

Lister les indexes


Les commande suivantes renseignent sur les indexes d'une table, ses clés. Elles sont aussi dans la table
`COLUMNS` de INFORMATION_SCHEMA, et accessibles via mysqlshow -k.

SHOW INDEX FROM `TABLE`;


SHOW INDEX FROM `TABLE` FROM `bases`;

Exemple de résultat :

Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed


Table1 0 PRIMARY 1 id A 19 NULL NULL

Le mot KEYS est synonyme de INDEX. Aucune autre clause n'est possible avec.

Afin de distinguer les variables des mots réservés, on place les identificateurs MySQL (noms des tables,
champs, et bases) entre deux accents graves (`). Il s'agit du caractère ASCII 96, disponible sous Linux en
pressant les deux touches ALT + '.

Généralement il est optionnel, mais il permet de meilleurs messages d'erreur, par exemple :

mysql> SELECT user_id, group_id FROM USER,GROUP LIMIT 1;


ERROR 1064 (42000): You have an error IN your SQL syntax;
CHECK the manual that corresponds TO your MySQL server version
FOR the RIGHT syntax TO USE near 'group LIMIT 1' at line 1

vs :

mysql> SELECT user_id, group_id FROM `user`,`group` LIMIT 1;


ERROR 1146 (42S02): TABLE 'savannah.group' doesn't exist

Montre qu'il manquait un s à group:

mysql> SELECT user_id, group_id FROM `user`,`groups` LIMIT 1;


+---------+----------+
| user_id | group_id |
+---------+----------+
| 100 | 2 |
+---------+----------+
1 ROW IN SET (0.02 sec)

Cette syntaxe autorise l'utilisateur à employer des mots réservés dans leurs noms d'objets. On peut même
utiliser des accents graves en es tapant deux fois, à la manière des caractères d'échappement :

RENAME TABLE `user` TO ````

Par contre cette syntaxe n'est pas portable, car le standard SQL recommande le guillemet (").

Le LDD est composé de CREATE, ALTER et DROP. Il permet d'ajouter, modifier et supprimer les structures
logiques qui contiennent les données, ou autorisent les utilisateurs à y accéder ou à les maintenir (bases,
tables, vues, clés...). le LDD concerne les métadonnées.
Le LMD est constitué de INSERT, UPDATE et DELETE. Pour ajouter, modifier et supprimer les données
stockées dans les bases.
Le LCD représente GRANT et REVOKE. Il s'agit de la sécurité de la base, des permissions des utilisateurs.

On peut aussi distinguer deux autres catégories :

Le DQL (Data Query Language : langage de requête de données), comme SELECT, SHOW et HELP. Ils sont
rattachés au LMD dans le modèle traditionnel.
Le DTL (Data Transaction Language : langage de transaction de données) avec START TRANSACTION,
SAVEPOINT, COMMIT et ROLLBACK [TO SAVEPOINT]. Affiliable au LCD dans le modèle à trois catégories.

Variables de session
Les variables obéissent à certaines règles :

Leurs noms commencent par "@" (ex : @total).


Elles sont déclarées avec le mot SET, ou bien SELECT accompagné de l'opérateur d'assignation :=.
Une variable définie dans la liste de champ ne peut pas être utilisée comme une condition.
Les variables de session durent le temps du thread.

SELECT @test := 2;
SELECT @test + 1; -- renvoie 3

SET @datedebut='date_de_debut', @datefin='date_de_fin';

SELECT @nbmembre:=COUNT(*) FROM membres;

SELECT @numzero := COUNT(*) FROM table1 WHERE FIELD=0;


SELECT @numdistint := COUNT(DISTINCT FIELD) FROM table1 WHERE FIELD <> 0 ;
SELECT @numzero @numdistinct;

Pour copier dans valeurs d'une sélection dans une ou plusieurs variables :

SET @id = 0, @nom = '';


SELECT id, nom INTO @id, @nom FROM table1 LIMIT 1;
SELECT @id, @nom;

Variables globales
Une variable globale est visible pour tous les utilisateurs, elles peuvent modifier les fichiers de configuration
définitivement pendant la session. Donc en les changeant, il est nécessaire de préciser le critère définitif ou
éphémère, via set global et set session.

Exemple :

mysql> set @@global.max_connections = 1000;


mysql> show global variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout | 60 |
+---------------+-------+
1 row in set (0.00 sec)
mysql> set @@session.wait_timeout=120;

Une expression ou une colonne peut être baptisée avec AS. Cet alias est utilisé comme nom de colonne et
peut donc être nommé dans les clauses des requêtes. Exemple :

SELECT
CONCAT(nom,' ', prenom) AS nom_complet,
pseudonyme AS pseudo
FROM
table1
ORDER BY
nom_complet;

Ces alias fonctionnent avec ORDER BY, GROUP BY et HAVING, mais pas WHERE.

Cela peut aussi servir à raccourcir les noms des tables employées comme préfixes.

SELECT
COUNT(R.ID_reservation), U.Localisation
FROM
Utilisateurs U
LEFT OUTER JOIN
Reservations AS R
ON
U.ID_Utilisateur = R.ID_Utilisateur AND
R.ID_Projet = '10'
GROUP BY
U.Localisation;

De plus les alias peuvent jouer un rôle crucial pour les auto-jointures. Par exemples ci-dessous, la table
personne est référencée par p et c :

SELECT
p.nom AS parent,
e.nom AS enfant,
MIN((TO_DAYS(NOW())-TO_DAYS(e.date_naissance))/365) AS agemini
FROM
personne AS p
LEFT JOIN
personne AS e
ON
p.nom=e.parent WHERE e.nom IS NOT NULL
GROUP BY
parent HAVING agemini > 50 ORDER BY p.date_naissance;

VARCHAR
VARCHAR est l'abréviation de CHARACTER VARYING (caractère variant en anglais). 'n' représente la taille
maximum de colonne (jusqu'à 65 535 caractères). Par exemple, une colonne de type VARCHAR(10) peut
contenir 10 caractères maximum. La taille du stockage correspondant en fait à la taille du texte contenu (L),
plus un ou deux octets (un si la taille est inférieure à 255).

Par exemple pour la chaine "abcd", L = 4 et le stockage = 5.

CHAR(n) est similaire à VARCHAR(n) sauf qu'il occupe une taille fixe, il ne tient pas compte de son contenu.

TEXT et BLOB
Les types BLOB et TEXT ont une taille maximum de 65 535 caractères. L'espace requis est la taille réelle des
données stockées, plus un ou deux octets (un si < 255). Comme elles ne sont pas stockées dans le fichier de
données, toutes les opérations (INSERT / UPDATE / DELETE / SELECT) les concernant sont plus lentes,
mais cela a l'avantage de rendre celles qui ne les touchent pas plus rapides.

INTEGER
Spécifier une valeur n n'a aucun effet. De toute façon, la taille maximum est des données stockées est de 429
fois 107.

Pour les nombres uniquement positifs, utiliser UNSIGNED, sinon SIGNED.

DECIMAL
Syntaxe : DECIMAL(n,m).

Ex : DECIMAL(4,2) signifie des nombres jusqu'à 99,99 (quatre chiffres deux dont réservés aux décimales).

DATE
Il existe trois types pour stocker des dates : DATETIME, DATE, et TIMESTAMP.

MySQL récupère et affiche les dates au format "AAAA-MM-JJ" (plus pratique pour les classer de gauche à
droite).

DATETIME est utilisé quand les valeurs doivent contenir l'heure en plus du jour.

La différente entre DATETIME et TIMESTAMP est que la taille des TIMESTAMP est limitée aux années 1970-2037.
Le type TIME peut stocker les heures du jour (HH:MM:SS) sans date. Il peut aussi représenter une période de
temps (ex : -02:00:00 pour deux heures avant). Limité entre '-838:59:59' et '838:59:59'.

YEAR peut stocker des années.

Pour manipuler des dates, il faut préciser un jour et pas seulement une heure, car pourrait interpréter
"HH:MM:SS" comme une valeur "YY:MM:DD".

Les exemples suivant montrent la plage de date précise pour les temps Unix, démarrant à l'époque Unix
jusqu'à 2038 ( ).

mysql> SET time_zone = '+00:00'; -- GMT


Query OK, 0 rows affected (0.00 sec)

mysql> SELECT FROM_UNIXTIME(-1);


+-------------------+
| FROM_UNIXTIME(-1) |
+-------------------+
| NULL |
+-------------------+
1 row in set (0.00 sec)

mysql> SELECT FROM_UNIXTIME(0); -- "Epoch"


+---------------------+
| FROM_UNIXTIME(0) |
+---------------------+
| 1970-01-01 00:00:00 |
+---------------------+
1 row in set (0.00 sec)

mysql> SELECT FROM_UNIXTIME(2145916799);


+---------------------------+
| FROM_UNIXTIME(2145916799) |
+---------------------------+
| 2037-12-31 23:59:59 |
+---------------------------+
1 row in set (0.00 sec)

mysql> SELECT FROM_UNIXTIME(2145916800);


+---------------------------+
| FROM_UNIXTIME(2145916800) |
+---------------------------+
| NULL |
+---------------------------+
1 row in set (0.00 sec)

SET et ENUM
SET est un type dont les valeurs sont prédéfinies dans une liste lors de la création de la table [1] .

ENUM est similaire mais restreint à un seul membre, alors que SET autorise le stockage de n'importe lesquelles
de ses valeurs ensemble.

Exemple :

SET("madame", "monsieur") -- autorise un champ vide, "madame", "monsieur", "madame, monsieur", ou "monsieur, ma

ENUM("madame", "monsieur") -- autorise un champ vide, "madame" ou "monsieur"

Références
1. ↑ http://dev.mysql.com/doc/refman/5.0/fr/set.html

Création

CREATE DATABASE Nom_de_la_base;

mysqladmin create permet de le faire en ligne de commande.

Suppression

DROP DATABASE Nom_de_la_base;

mysqladmin drop permet de le faire en ligne de commande. Le paramètre -f force celle-ci sans poser de
question.

Renommage
Dans les versions 5.1.x il existait une commande RENAME DATABASE, mais elle a été retirée suite à des
problèmes.

Il reste toutefois la ligne de commande pour le faire en plusieurs étapes :

mysqladmin create Nom_de_la_nouvelle_base


mysqldump --opt Nom_de_la_base | mysql Nom_de_la_nouvelle_base
mysqladmin drop -f Nom_de_la_base

Une autre option avec les droits root, est de renommer le répertoire de la base :
cd /var/lib/mysql/
/etc/init.d/mysql stop
mv Nom_de_la_base/ Nom_de_la_nouvelle_base/
/etc/init.d/mysql start

Après renommage, il convient de migrer les permissions :

UPDATE mysql.db SET `Db`='Nom_de_la_nouvelle_base' WHERE `Db`='Nom_de_la_base';


FLUSH PRIVILEGES;

Copier
Avec phpMyAdmin

Pour plus de détails voir : phpMyAdmin.

Avec mysqldump

mysqldump peut sauvegarder les bases, il suffit de réinjecter son résultat dans d'autres bases.

# Premièrement, nettoyer la base de destination :


mysqladmin drop -f base2
mysqladmin create base2
# Ensuite, copier la base1 dans la base2 :
mysqldump --opt base1 | mysql base2

DBDesigner et MySQL Workbench

Ces logiciels permettent de représenter les tables sous formes de diagrammes.

DBDesigner est en licence GNU GPL, mais ne peut pas être considéré comme un freeware car i requiert un
compilateur Kylix non gratuit.

Il recontre une erreur de connexion à MySQL sur la version 4 : unable to load libmysqlclient.so Pour la
résoudre :

Installer les "Shared compatibility libraries" Télécharger (http://dev.mysql.com/downloads/mysql


/5.0.html#downloads) [ archive ]
MySQL pour version 5.0).

Sous Linux :

Remplacer le fichier libmysqlclient.so de DBDesigner par le nouveau :

sudo ln -sf /usr/lib/libmysqlclient.so.10 /usr/lib/DBDesigner4/libmysqlclient.so

Trouver et installer kylixlibs3-unwind-3.0-rh.4.i386.rpm


Trouver un vieux xorg (ex : xorg-x11-libs-6.8.2-37.FC4.49.2.1.i386.rpm depuis FC4) et l'extraire :

rpm2cpio x.rpm | cpio -i

Récupérer libXft.so.1.1 dans ce package et l'installer :

sudo cp libXft.so.1.1 /usr/lib


ldconfig

Maintenant DBDesigner4 peut se connecter à MySQL5.

MySQL Workbench permet également la migration depuis d'autres bases de données.

OpenOffice Base et ODBC

Configuration typique :

Soit une base MySQL appelée mysqlhost.


OpenOffice.org sur la machine cliente (Debian GNU/Linux dans l'exemple).
Connexion via ODBC.

Sur le client, installer mysql-client :

aptitude install mysql-client

Sous Fedora/CentOS :

yum install mysql

Avant d'installer ODBC, test la connexion distante localement :

$ mysql -h mysqlhost -u user1 mysqldatabase -p


Enter password: PassUser1

Il faut créer la base mysqldatabase et l'utilisateur user1 sur mysqlhost.

mysql> show databases;


+--------------------+
| Database |
+--------------------+
| information_schema |
| mysqldatabase |
+--------------------+
2 rows in set (0.00 sec)
....
mysql> quit;
Bye

Toujours sur la machine cliente :

aptitude install libmyodbc unixodbc

Pour Fedora/CentOS :

yum install mysql-connector-odbc unixODBC

Les fichiers /etc/odbc.ini et /etc/odbcinst.ini sont créés.

odbcinst.ini déclare le pilote ODBC disponible. Exemple pour Debian :

[MySQL]
Description = MySQL driver
Driver = /usr/lib/odbc/libmyodbc.so
Setup = /usr/lib/odbc/libodbcmyS.so
CPTimeout =
CPReuse =
FileUsage = 1

for CentOS:

[MySQL]
Description = ODBC for MySQL
Driver = /usr/lib/libmyodbc3.so
Setup = /usr/lib/libodbcmyS.so
FileUsage = 1

Maintenant odbcinst est utilisable :

# odbcinst -j
unixODBC 2.2.4
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
USER DATA SOURCES..: /root/.odbc.ini

Pour d'autres options : man odbcinst


Il faut créer au moins un DSN (Data Source Name ou Data Set Name), parce que chaque connexion ODBC
avec OOo est initialisée avec.

Pour créer un DSN, il existe différente possibilités :

Modifier /etc/odbc.ini (concerne tous les utilisateurs)


Modifier ~/.odbc.ini (concerne un seul utilisateur)
Utilise les applications graphiques comme ODBCConfig (Debian : unixodbc-bin, Fedora :
unixODBC-kde).

Finalement, ces applications graphiques modifient /etc/odbc.ini ou ~/.odbc.ini.

Par exemple, un fichier /etc/odbc.ini (le nom du DSN est entre crochets []) :

[MySQL-test]
Description = MySQL ODBC Database
TraceFile = stderr
Driver = MySQL
SERVER = mysqlhost
USER = user1
PASSWORD =
DATABASE = mysqldatabase

Dans ce cas, le DSN est appelé MySQL-test.

Ensuite pour tester, utiliser la commande isql :

$ isql -v MySQL-test user1 PassUser1


+---------------------------------------+
| Connected! |
| |
| sql-statement |
| help [tablename] |
| quit |
| |
+---------------------------------------+
SQL> show databases;
+-------------------+
| Database |
+-------------------+
| information_schema|
| mysqldatabase |
+-------------------+
2 rows affected
2 rows returned
SQL> quit;

Depuis OOo :

-> File
-> New
-> Database
-> Connecting to an existing database
-> MySQL
-> Next
-> Connect using ODBC
-> Next
-> Choosing a Data Source
-> MySQL-test
-> Next
-> Username : user1 (tick password required)
-> Yes, register the database for me
-> Finish

A ce stade, le programme est connecté à la base mysqldatabase en tant que user1. Il reste donc le mot de
passe à rentrer.

Ensuite, Java est requis dans les Wizards uniquement (lors de création directe JRE est inutile) :

Wizard pour créer un formulaire.


Wizard pour créer des rapports.
Wizard pour créer des requêtes.
Wizard pour créer tables.

Les distributions GNU/Linux fournissent généralement OpenOffice avec IcedTea (openjdk-6-jre/java-


1.6.0-openjdk) ou GCJ (java-gcj-compat/java-1.4.2-gcj-compat) donc les fonctionnalités basées sur
du Java fonctionnent.

Outils de modélisation des données


PhpMyAdmin possède un onglet "Concepteur".
MySQL Workbench (http://dev.mysql.com/downloads/tools/workbench/) [archive] vidéo (http://www.grafikart.fr
/tutoriels/mysql/modeliser-base-de-donnee-75) [ archive ]

MySQL Query Browser (http://dev.mysql.com/downloads/gui-tools/5.0.html) [archive] inclut un module


MySQL Table Editor.
Kexi (http://userbase.kde.org/Calligra/Download/fr) [archive]

CREATE TABLE
La syntaxe de création des tables d'une base est ainsi :

CREATE TABLE tablename (FieldName1 DataType, FieldName2 DataType)

Les enregistrements de la requête SELECT peuvent être enregistrés dans une nouvelle table. Les types des
données seront les mêmes que dans l'ancienne table. Exemple :
CREATE TABLE LearnHindi
SELECT english.tag, english.Inenglish AS english, hindi.Inhindi AS hindi
FROM english, hindi
WHERE english.tag = hindi.tag

ALTER TABLE
ALTER TABLE sert à ajouter, supprimer ou modifier la structure des tables (colonnes, index, propriétés).

Ajouter une colonne

ALTER TABLE awards


ADD COLUMN AwardCode INT(2)

Modifier une colonne

ALTER TABLE awards


CHANGE COLUMN AwardCode VARCHAR(2) NOT NULL

ALTER TABLE awards


MODIFY COLUMN AwardCode VARCHAR(2) NOT NULL

Supprimer une colonne

ALTER TABLE awards


DROP COLUMN AwardCode

Reclasser les enregistrements d'une table

ALTER TABLE awards ORDER BY id

Remarque : Cette opération n'est pas supportée par tous les moteurs de stockage. Elle peut accélérer
certaines requêtes.

Renommer une table

Pour renommer une table, il faut préalablement retirer ses privilèges avec ALTER et DROP, puis CREATE et
INSERT pour ceux à attribuer à la nouvelle table.

Renommage :

ALTER TABLE `old` RENAME `new`


Raccourci :

RENAME TABLE `old_name` TO `new_name`

Plusieurs :

RENAME TABLE `old1` TO `new1`, `old2` TO `new2`, ...

La différence entre ALTER TABLE et RENAME est que seul le premier peut renommer les tables temporaires,
mais il n'en permet qu'un par requête.

DROP TABLE

DROP TABLE `awards`

Supprime toute la table (enregistrements et structure).

Plusieurs :

DROP TABLE `table1`, `table2`, ...

Avec vérification :

DROP TEMPORARY TABLE `table`;


DROP TABLE `table` IF EXISTS;

Exemple pour travaux pratiques


Soit l'exemple suivant qui sera utilisé pour les sélections ensuite (toute ressemblance avec un framework
connu est purement non fortuite : si vous avez déjà votre propre wiki, il est possible de sauter cette phase
pour passer directement au paragraphe SELECT).

Création d'une base

CREATE DATABASE wiki1;


USE wiki1;
-- Liste des utilisateurs
CREATE TABLE IF NOT EXISTS `wiki1_user` (
`user_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_name` varbinary(255) NOT NULL DEFAULT '',
`user_real_name` varbinary(255) NOT NULL DEFAULT '',
`user_password` tinyblob NOT NULL,
`user_newpassword` tinyblob NOT NULL,
`user_newpass_time` BINARY(14) DEFAULT NULL,
`user_email` tinyblob NOT NULL,
`user_touched` BINARY(14) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
`user_token` BINARY(32) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0
`user_email_authenticated` BINARY(14) DEFAULT NULL,
`user_email_token` BINARY(32) DEFAULT NULL,
`user_email_token_expires` BINARY(14) DEFAULT NULL,
`user_registration` BINARY(14) DEFAULT NULL,
`user_editcount` INT(11) DEFAULT NULL,
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name` (`user_name`),
KEY `user_email_token` (`user_email_token`),
KEY `user_email` (`user_email`(50))
) ENGINE=InnoDB DEFAULT CHARSET=BINARY AUTO_INCREMENT=41 ;

INSERT INTO `wiki1_user` (`user_id`, `user_name`, `user_real_name`, `user_password`, `user_newpassword`,


(1, 'Utilisateur1', 'admin', '', '', NULL, '', '', '', '', '', '20130101', '20130101', 1000),
(2, 'Utilisateur2', '', '', '', NULL, '', '', '', '', '', '20130101', '20130101', 800),
(3, 'Bot1', 'admin', '', '', NULL, '', '', '', '', '', '20130101', '20130101', 5000),
(4, 'Utilisateur3', '', '', '', NULL, '', '', '', '', '', '20130102', '20130102', 500),
(5, 'Utilisateur4', '', '', '', NULL, '', '', '', '', '', '20130102', '20130102', 200);
(6, 'Utilisateur5', '', '', '', NULL, '', '', '', '', '', '20130103', '20130103', 200);

-- Liste des pages


CREATE TABLE IF NOT EXISTS `wiki1_page` (
`page_id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`page_namespace` INT(11) NOT NULL,
`page_title` varbinary(255) NOT NULL,
`page_restrictions` tinyblob NOT NULL,
`page_counter` BIGINT(20) UNSIGNED NOT NULL DEFAULT '0',
`page_is_redirect` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
`page_is_new` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
`page_random` DOUBLE UNSIGNED NOT NULL,
`page_touched` BINARY(14) NOT NULL DEFAULT '\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
`page_latest` INT(10) UNSIGNED NOT NULL,
`page_len` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`page_id`),
UNIQUE KEY `name_title` (`page_namespace`,`page_title`),
KEY `page_random` (`page_random`),
KEY `page_len` (`page_len`),
KEY `page_redirect_namespace_len` (`page_is_redirect`,`page_namespace`,`page_len`)
) ENGINE=InnoDB DEFAULT CHARSET=BINARY AUTO_INCREMENT=8;

INSERT INTO `wiki1_page` (`page_id`, `page_namespace`, `page_title`, `page_restrictions`, `page_counter`,


(1, 0, 'Accueil', '', 0, 0, 0, 0, '', 0, 0),
(2, 8, 'Sidebar', '', 0, 0, 0, 0, '', 0, 0),
(3, 0, 'MySQL', '', 0, 0, 0, 0, '', 0, 0),
(4, 0, 'PHP', '', 0, 0, 0, 0, '', 0, 0);

-- Propriétés des pages


CREATE TABLE IF NOT EXISTS `wiki1_page_props` (
`pp_page` INT(11) NOT NULL,
`pp_propname` varbinary(60) NOT NULL,
`pp_value` BLOB NOT NULL,
UNIQUE KEY `pp_page_propname` (`pp_page`,`pp_propname`)
) ENGINE=InnoDB DEFAULT CHARSET=BINARY;

INSERT INTO `wiki1_page_props` (`pp_page`, `pp_propname`, `pp_value`) VALUES


(1, 'noindex', ''),
(2, 'defaultsort', ''),
(2, 'noindex', '');

-- Hyperliens dans les pages


CREATE TABLE IF NOT EXISTS `wiki1_pagelinks` (
`pl_from` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`pl_namespace` INT(11) NOT NULL DEFAULT '0',
`pl_title` varbinary(255) NOT NULL DEFAULT '',
UNIQUE KEY `pl_from` (`pl_from`,`pl_namespace`,`pl_title`),
UNIQUE KEY `pl_namespace` (`pl_namespace`,`pl_title`,`pl_from`)
) ENGINE=InnoDB DEFAULT CHARSET=BINARY;
INSERT INTO `wiki1_pagelinks` (`pl_from`, `pl_namespace`, `pl_title`) VALUES
(1, 0, 'Lien1'),
(3, 0, 'Lien2');

INSERT
La syntaxe est la suivante :

Insert value1 into Column1, value2 into Column2, and value3 into Column3:

INSERT INTO TableName (Column1, Column2, Column3)


VALUES (value1, value2, value3)

Insérer un enregistrement (les valeurs sont insérées dans l'ordre où les colonnes apparaissent dans la base) :

INSERT INTO TableName


VALUES (value1, value2, value3)

Deux lignes :

INSERT INTO TableName


VALUES (value1, value2, value3), (value4, value5, value6)

INSERT INTO antiques VALUES (21, 01, 'Ottoman', 200.00);


INSERT INTO antiques (buyerid, sellerid, item) VALUES (01, 21, 'Ottoman');

Copier ceux d'une autre table :

INSERT INTO table1(field1, field2)


SELECT field1, field2
FROM table2

INSERT INTO World_Events SELECT * FROM National_Events

Astuces de performances :

Pour insérer plusieurs lignes, utiliser LOAD DATA INFILE de préférence.


Si un gros volume d'insertion est trop lent sur des tables indexées non vides, augmenter la valeur de
bulk_insert_buffer_size.
Avant des insertions en masse, retirer les clés.
Verrouiller une table (LOCK) accélère les INSERT.

UPDATE
UPDATE TABLE SET FIELD = newvalue WHERE criteria ORDER BY FIELD LIMIT n

Exemples :

UPDATE owner SET ownerfirstname = 'John'


WHERE ownerid = (SELECT buyerid FROM antiques WHERE item = 'Bookcase');

UPDATE antiques SET price = 500.00 WHERE item = 'Chair';

UPDATE ORDER SET discount=discount * 1.05

UPDATE tbl1 JOIN tbl2 ON tbl1.ID = tbl2.ID


SET tbl1.col1 = tbl1.col1 + 1
WHERE tbl2.STATUS='Active'

UPDATE tbl SET names = REPLACE(names, 'aaa', 'zzz')

UPDATE products_categories AS pc
INNER JOIN products AS p ON pc.prod_id = p.id
SET pc.prod_sequential_id = p.sequential_id

UPDATE TABLE_NAME SET col_name =


REPLACE(col_name, 'host.domain.com', 'host2.domain.com')

UPDATE posts SET deleted=TRUE


ORDER BY DATE LIMIT 1

Avec ORDER BY il est possible de classer les enregistrements avant l'insertion, voire même sur un nombre
donné de lignes (avec LIMIT).

Il est impossible de mettre à jour une table pendant en même temps qu'elle une subit sous-requête. Par
exemple, pour réinitialiser un mot de passe SPIP :

mysql> UPDATE spip_auteurs SET pass =


(SELECT pass FROM spip_auteurs WHERE login='paul') where login='admin';
ERROR 1093 (HY000): You can't specify target table 'spip_auteurs' for update i

Par ailleurs, il est possible de sélectionner les enregistrements à mettre à jour automatiquement [1] .

Astuces de performances :

La vitesse des UPDATE dépend du nombre d'index mis à jour.


En cas d'UPDATE d'une table MyISAM au format dynamique, les colonnes larges causes des lectures de
mémoire superflues. Il faut régulièrement lancer OPTIMIZE TABLE pour les réduire à la taille de leur
contenu.
Lancer plein d'UPDATE en même temps sur une table verrouillée est plus rapide qu'individuellement.

REPLACE
REPLACE fonctionne exactement comme INSERT, sauf que si l'ancien enregistrement a la même valeur que le
nouveau en tant que PRIMARY KEY ou UNIQUE index, l'ancien est supprimé avant l'insertion du
nouveau.

Le mot IGNORE ajuste les valeurs invalides au plus près et insérées, en affichant des avertissements.
Avant MySQL 4.0.1, INSERT ... SELECT opérait implicitement en mode IGNORE : ignorer les
enregistrements qui causeraient des erreurs de valeur de clé dupliquée.

DELETE et TRUNCATE

DELETE [QUICK] FROM `table1`


TRUNCATE [TABLE] `table1`

Quelques précisions :

Utiliser DELETE sans clause WHERE, supprime tous les enregistrements.


Si une table contient beaucoup d'index, on peut agrandir le cache pour accélérer les DELETE (variable
key_buffer_size).
Pour les tables indexées MyISAM, parfois DELETE est plus rapide en spécifiant le mot QUICK (DELETE
QUICK FROM ...). Cela permet de réutiliser les valeurs des index effacées.
TRUNCATE/ efface également les lignes rapidement, en faisant DROP et CREATE (sur certains moteurs de
stockage seulement).
TRUNCATE ne garantit pas la transaction ou le verrouillage.
DELETE informe de combien de lignes ont été supprimées, mais pas TRUNCATE.
Après une suppression massive (au moins 30 % des lignes), il convient de lancer OPTIMIZE TABLE juste
après pour accélérer la suite.
Sur des tables InnoDB avec contraintes FOREIGN KEY, TRUNCATE se comporte comme DELETE.

DELETE FROM `antiques`


WHERE item = 'Ottoman'
ORDER BY `id`
LIMIT 1

Il est possible de classer les lignes avant leur suppression, tout en en choisissant le nombre.

Références

1. ↑ (en) http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/

SELECT
La syntaxe de sélection est la suivante (chaque clause fera l'objet d'un paragraphe explicatif ensuite) :

SELECT *
FROM nom_table
WHERE condition
GROUP BY champ1, champ2
HAVING groupe condition
ORDER BY champ
LIMIT limite, taille;
Liste de champs

Il faut spécifier les données à récupérer avec SELECT :

SELECT DATABASE(); -- renvoie le nom de la base courante


SELECT CURRENT_USER(); -- l'utilisateur courant
SELECT 1+1; -- 2

L'étoile permet d'obtenir tous les champs d'une table :

SELECT * FROM `wiki1_page`;

Mais il est plutôt conseillé de nommer chaque champ (projection) pour accélérer la requête.

Noms des tables

Pour récupérer les champs d'une table ou d'une vue, il faut la placer dans la clause FROM :

USE wiki1;
SELECT page_id FROM `wiki1_page`; -- renvoie les valeurs du champ "page_id" de la table "wiki1_page".

SELECT `wiki1`.`wiki1_page`.`page_id`; -- idem

Autres exemples :

SELECT MAX(page_id) FROM `wiki1_page`; -- le nombre le plus élevé


SELECT page_id*2 FROM `wiki1_page`; -- le double de chaque identifiant

WHERE

Cette clause permet de filtrer les enregistrements. Prenons pas exemple celui ou ceux dont le champ
identifiant est égal à 42 :

SELECT * FROM `wiki1_page` WHERE `page_id`=42;

Ou bien ceux qui ne sont pas nuls :

SELECT * FROM `wiki1_page` WHERE page_id IS NOT NULL;


GROUP BY

Quand plusieurs enregistrements sont identiques dans le résultat, qu'ils ont les mêmes valeurs dans leurs
champs sélectionnés, ils peuvent être groupés en une seule ligne.

Par exemple, en regroupant les enregistrements de la table utilisateurs sur le champ de date d'inscription au
wiki, on peut obtenir pour chacune le nombre d'édition maximum, minimum et leurs moyennes :

SELECT user_registration, MAX(user_editcount), MIN(user_editcount), AVG(user_editcount)


FROM wiki1_user
GROUP BY `user_registration`;

Idem mais classé par nom et prénom d'utilisateur :

SELECT user_registration, user_real_name, MAX(user_editcount), MIN(user_editcount), AVG(user_editcount)


FROM wiki1_user
GROUP BY `user_registration`, `user_real_name`;

HAVING

HAVING déclare un filtre valable uniquement pour les enregistrements de la clause GROUP BY, ce qui le
distingue de WHERE qui lui opère avant GROUP BY.

HAVING n'est pas optimisé et ne peut pas utiliser les index.

Voici un exemple d'erreur d'optimisation classique : l'ordonnancement des opérations ne filtre le gros des
résultats (valeur admin) qu'à la fin de la requête (utilisant plus de mémoire, donc plus de temps qu'avec un
WHERE) :

SELECT MAX(user_editcount), MIN(user_editcount), AVG(user_editcount)


FROM wiki1_user
GROUP BY user_real_name
HAVING user_real_name = 'admin';

Par contre, cet exemple ne peut pas être optimisé car le HAVING utilise le résultat du MAX() calculé après le
GROUP BY :

SELECT MAX(user_editcount), MIN(user_editcount), AVG(user_editcount)


FROM wiki1_user
GROUP BY user_real_name
HAVING MAX(user_editcount) > 500;

ORDER BY

Il est possible de classer les résultat, par ordre croissant ou décroissant, des nombres ou des lettres.
SELECT * FROM `wiki1_page` ORDER BY `page_id`;

Par défaut, l'ordre est ASCENDING (croissant). Pour le décroissant il faut donc préciser DESCENDING :

SELECT * FROM `wiki1_page` ORDER BY `page_id` ASC; -- ASC est facultatif


SELECT * FROM `wiki1_page` ORDER BY `page_id` DESC; -- ordre inversé

Les valeurs NULL sont considérées comme inférieures aux autres.

Il est également possible de nommer la colonne à classer par son numéro :

SELECT `page_title`, `page_id` FROM `wiki1_page` ORDER BY 1; -- nom


SELECT `page_title`, `page_id` FROM `wiki1_page` ORDER BY 2; -- id
SELECT `page_title`, `page_id` FROM `wiki1_page` ORDER BY 1 DESC;

Les expressions SQL sont autorisées :

SELECT `page_title` FROM `wiki1_page` ORDER BY REVERSE(`page_title`)

La fonction RAND() classe de façon aléatoire :

SELECT `page_title` FROM `wiki1_page` ORDER BY RAND()

Quand un GROUP BY est spécifié, les résultats sont classés selon les champs qui y sont nommés, sauf avant
un ORDER BY. Donc l'ordre décroissant peut aussi être précisé depuis le GROUP BY :

SELECT user_registration, user_real_name, MAX(user_editcount)


FROM wiki1_user
GROUP BY `user_registration` ASC, `user_real_name` DESC;

Pour éviter ce classement automatique du GROUP BY, utiliser ORDER BY NULL :

SELECT user_registration, user_real_name, MAX(user_editcount)


FROM wiki1_user
GROUP BY `user_registration`, `user_real_name` ORDER BY NULL;

LIMIT
Le nombre maximum d'enregistrements dans le résultat est facultatif, on l'indique avec le mot LIMIT :

SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 10;

Ce résultat retourne donc entre 0 et 10 lignes.

Généralement cela s'emploie après un ORDER BY pour avoir les maximums et minimums, mais voici un
exemple pour en avoir trois au hasard :

SELECT * FROM `wiki1_page` ORDER BY rand() LIMIT 3;

Il est possible de définir une plage d’enregistrements, sachant que le premier est le numéro zéro :

SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 10;


SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 0, 10; -- synonyme

On peut donc paginer :

SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 0, 10; -- première page


SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 10, 10; -- seconde page
SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 20, 10; -- troisième page

La seconde commande est équivalente à celle-ci :

SELECT * FROM `wiki1_page` ORDER BY page_id LIMIT 10 OFFSET 10

Une astuce consiste à déboguer la syntaxe de sa requête rapidement en lui demandant un résultat vide, et
observer ainsi s'il y a des messages d'erreur sans attendre :

SELECT ... LIMIT 0

Conseils d'optimisation

SQL_CALC_FOUND_ROWS peut accélérer les requêtes [1] [2] .


LIMIT est particulièrement pratique dans des SELECT avec ORDER BY, DISTINCT et GROUP BY, car leurs
calculs n'impliquent pas toutes les lignes.
Si la requête est résolue par le serveur en copiant les résultats dans une table temporaire, LIMIT aide
MySQL à calculer combien de mémoire est requise par la table.
DISTINCT

Le mot DISTINCT peut être utilisé pour supprimer les doublons des lignes du résultat :

SELECT DISTINCT * FROM `wiki1_page` -- aucun doublon


SELECT DISTINCTROW * FROM `wiki1_page` -- synonyme
SELECT ALL * FROM `wiki1_page` -- doublons (comportement par défaut)

Cela permet par exemple de récupérer la liste de toutes les valeurs différentes d'un champ :

SELECT DISTINCT `user_real_name` FROM `wiki1_page` ORDER BY `user_real_name`

On peut également en sortir les différentes combinaisons de valeurs :

SELECT DISTINCT `user_real_name`, `user_editcount` FROM `wiki1_page` ORDER BY `user_real_name`

Remarque : si une clé primaire ou un index unique fait partie de la sélection, le DISTINCT devient
inutile. C'est également le cas avec GROUP BY.

IN and NOT IN

Équivalent du signe =, qui ne nécessite pas d'être répété quand il concerne plusieurs valeurs :

SELECT page_id
FROM wiki1_page
WHERE page_namespace IN (0, 1);

-- Liste des pages qui ont des propriétés plus celles qui n'ont aucun hyperlien
SELECT page_id
FROM wiki1_page AS p, wiki1_user AS u WHERE p.page_id = u.user_id
UNION
SELECT page_id
FROM wiki1_page WHERE page_id NOT IN (SELECT pp_page FROM wiki1_page_props);

EXISTS

Fonction disponible depuis MySQL 4.

-- N'affiche la première sélection que si la seconde n'est pas nulle


SELECT page_title
FROM wiki1_page
WHERE EXISTS (SELECT * FROM wiki1_page_props WHERE pp_propname = 'noindex');

ALL
-- Ne renvoie que les pages dont le numéro est le seul de la seconde sélection
SELECT page_title
FROM wiki1_page
WHERE page_id = ALL (SELECT pp_page FROM wiki1_page_props WHERE pp_propname = 'defaultsort');

Hints d'optimisation

L'ordre des mots réservés est important si on applique plusieurs hints [3] :

SELECT [ALL | DISTINCT | DISTINCTROW ]


[HIGH_PRIORITY] [STRAIGHT_JOIN]
[SQL_SMALL_RESULT | SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
[SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
...

HIGH_PRIORITY

Généralement les commandes LMD (INSERT, DELETE, UPDATE) sont prioritaires sur le SELECT. Mais grâce
à HIGH_PRIORITY un SELECT peut être traité avec elles.

STRAIGHT_JOIN

Force MySQL à évaluer les tables d'un JOIN dans l'ordre où elles sont nommées (de gauche à droite).

SQL_SMALL_RESULT

Lors d'un DISTINCT ou d'un GROUP BY, ce hint prévient l'optimiseur que la requête va renvoyer un petit
nombre de lignes.

SQL_BIG_RESULT

Lors d'un DISTINCT ou d'un GROUP BY, dit à l'optimiseur que la requête renvoie un nombre élevé de résultats.

SQL_BUFFER_RESULT

Force MySQL à copier le résultat dans une table temporaire. Cela peut s'avérer utile par exemple pour
supprimer des LOCK rapidement.

SQL_CACHE

Force MySQL à copier le résultat dans le cache. Ne fonctionne que si la valeur de query_cache_type est
DEMAND ou 2.

SQL_NO_CACHE

Demande à MySQL de ne pas mettre le résultat en cache. C'est utile quand la requête survient très rarement,
ou que le résultat change très souvent.
SQL_CALC_FOUND_ROWS

Si une requête contient LIMIT, ce hint dit au serveur de calculer combien de lignes auraient été retournées en
cas d'absence de LIMIT. Pour récupérer le nombre il faut sélectionner FOUND_ROWS().

SELECT SQL_CALC_FOUND_ROWS * FROM `wiki1_page` LIMIT 2 OFFSET 100;


SELECT FOUND_ROWS();

UNION et UNION All

Compatible MySQL 4 et plus. L'union de sélections nécessite qu'elles aient le même nombre de colonnes.

La requête suivante renvoie tous les enregistrements de deux tables :

SELECT page_title FROM wiki1_page


UNION ALL
SELECT user_name FROM wiki1_user;

UNION est équivalent à UNION DISTINCT, ce qui le distingue de UNION ALL qui ne filtre pas les doublons.

SELECT page_id FROM wiki1_page


UNION
SELECT page_id FROM wiki1_page;
-- égal
(SELECT page_id FROM wiki1_page)
UNION DISTINCT
(SELECT page_id FROM wiki1_page)
ORDER BY page_id;

JOIN
Les relations entre les tables permettent de joindre intelligemment
leurs résultats. La jointure naturelle est la plus rapide sur la plupart
des plateformes SQL.

L'exemple suivant compare les nombres en anglais et en hindi.

CREATE TABLE english (Tag INT, Inenglish VARCHAR(255));


CREATE TABLE hindi (Tag INT, Inhindi VARCHAR(255));

INSERT INTO english (Tag, Inenglish) VALUES (1, 'One');


INSERT INTO english (Tag, Inenglish) VALUES (2, 'Two');
INSERT INTO english (Tag, Inenglish) VALUES (3, 'Three');

INSERT INTO hindi (Tag, Inhindi) VALUES (2, 'Do');


INSERT INTO hindi (Tag, Inhindi) VALUES (3, 'Teen');
INSERT INTO hindi (Tag, Inhindi) VALUES (4, 'Char');

select * from english select * from hindi


Tag Inenglish Tag Inhindi
1 One 2 Do
2 Two 3 Teen
3 Three 4 Char

CROSS JOIN

La jointure cartésienne décrit le cas où chaque ligne d'une table est jointe à toutes celles d'une autre.

SELECT * FROM english, hindi


-- égal
SELECT * FROM english CROSS JOIN hindi

3*3 = 9 lignes :

Tag Inenglish Tag Inhindi


1 One 2 Do
2 Two 2 Do
3 Three 2 Do
1 One 3 Teen
2 Two 3 Teen
3 Three 3 Teen
1 One 4 Char
2 Two 4 Char
3 Three 4 Char

INNER JOIN

SELECT hindi.Tag, english.Inenglish, hindi.Inhindi


FROM english, hindi
WHERE english.Tag = hindi.Tag
-- égal
SELECT hindi.Tag, english.Inenglish, hindi.Inhindi
FROM english INNER JOIN hindi ON english.Tag = hindi.Tag

Tag Inenglish Inhindi


2 Two Do
3 Three Teen

Le mot USING est compatible MySQL 4, mais change avec MySQL 5. La requête suivante est équivalente à
celles ci-dessus :

SELECT hindi.tag, hindi.Inhindi, english.Inenglish


FROM hindi NATURAL JOIN english
USING (Tag)
OUTER JOIN

SELECT hindi.Tag, english.Inenglish, hindi.Inhindi


FROM english OUTER JOIN hindi ON english.Tag = hindi.Tag

Tag Inenglish Tag Inhindi


1 One
2 Two 2 Do
3 Three 3 Teen
4 Char

LEFT JOIN / LEFT OUTER JOIN

SELECT field1, field2 FROM table1 LEFT JOIN table2 ON field1=field2

SELECT e.Inenglish AS English, e.Tag, '--rien--' AS Hindi


FROM english AS e LEFT JOIN hindi AS h
ON e.Tag=h.Tag
WHERE h.Inhindi IS NULL

English tag Hindi


One 1 --rien-

RIGHT OUTER JOIN

SELECT '--rien--' AS English, h.tag, h.Inhindi AS Hindi


FROM english AS e RIGHT JOIN hindi AS h
ON e.Tag=h.Tag
WHERE e.Inenglish IS NULL

English tag Hindi


--rien-- 4 Char

S'assurer que le type des clés de jointes est le même dans les deux tables.
Les mots clés LEFT et RIGHT ne sont pas absolus, ils opèrent selon le contexte : en intervertissant les tables
le résultat sera identique.
La jointure par défaut est INNER JOIN (pas OUTER).

FULL OUTER JOIN

MySQL n'a pas de jointure FULL OUTER JOIN. Voici comment l'émuler :
(SELECT a.*, b*
FROM tab1 a LEFT JOIN tab2 b
ON a.id = b.id)
UNION
(SELECT a.*, b*
FROM tab1 a RIGHT JOIN tab2 b
ON a.id = b.id)

Jointures multiples

Il est possible de joindre plus de deux tables :

SELECT ... FROM a JOIN (b JOIN c ON b.id=c.id) ON a.id=b.id

Exemple :

mysql> SELECT group_type.type_id, group_type.nom, COUNT(people_job.job_id) AS COUNT


FROM group_type
JOIN (groups JOIN people_job ON groups.group_id = people_job.group_id)
ON group_type.type_id = groups.TYPE
GROUP BY type_id ORDER BY type_id
+---------+--------------------------------------+-------+
| type_id | nom | COUNT |
+---------+--------------------------------------+-------+
| 1 | Official GNU software | 148 |
| 2 | non-GNU software AND documentation | 268 |
| 3 | www.gnu.org portion | 4 |
| 6 | www.gnu.org translation team | 5 |
+---------+--------------------------------------+-------+
4 ROWS IN SET (0.02 sec)

Sous requêtes
Compatible MySQL 4.1 et plus.

Les sous-requêtes SQL permettent aux résultats d'une requête d'être utilisés par une autre.
Elles apparaissent toujours comme une partie de clause WHERE ou HAVING.
Seul un champ peut être dans la sous-requête SELECT.
Les ORDER BY ne sont donc pas autorisés (inutiles sur une seule colonne).

Par exemple, la "table" RepOffice = OfficeNbr from Offices, liste les bureaux où le quota de vente excède la
somme des quotas des vendeurs individuels :

SELECT ville FROM Offices WHERE Target > ???

??? est la somme des quotas des vendeurs.

SELECT SUM(Quota)
FROM SalesReps
WHERE RepOffice = OfficeNbr
En combinant ces deux requêtes, les points d'interrogations disparaissent :

SELECT ville FROM Offices


WHERE Target > (SELECT SUM(Quota) FROM SalesReps
WHERE RepOffice = OfficeNbr)

Par exemple, tous les clients avec des commandes ou limites de crédits > 50000 €. En utilisant le mot
DISTINCT pour ne lister les clients qu'une seule fois :

SELECT DISTINCT CustNbr


FROM Customers, Orders
WHERE CustNbr = Cust AND (CreditLimit > 50000 OR Amt > 50000);

References

1. ↑ http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/
2. ↑ http://dev.mysql.com/doc/refman/5.0/en/information-functions.html
3. ↑ http://dev.mysql.com/doc/refman/5.7/en/index-hints.html

Resources
Official MySQL documentation (http://dev.mysql.com/doc) [archive]

De nombreux langages de programmation ont deux valeurs logiques : True et False. SQL en possède une
troisième pour les valeurs inconnue : NULL.

NULL étant une absence de valeur, il peut être assigné à des colonnes TEXT, INTEGER ou autres. Toutefois une
colonne déclarée NOT NULL ne pourra pas en contenir.

INSERT into Singer


(F_Name, L_Name, Birth_place, Language)
values
("", "Homer", NULL, "Greek"),
("", "Sting", NULL, "English"),
("Jonny", "Five", NULL, "Binary");

NULL ne doit pas être entouré d'apostrophes ou de guillemets, ou bien il désignera une chaine de caractères
contenant son nom.

Remarque : NULL n'apparait pas dans les colonnes Varchar sous Windows XP mais sous Fedora oui.

L'exemple ci-dessous peut sélectionner des chanteurs avec prénom de taille zéro (""), par exemple pour
Sting et Homer. Il vérifie si la date de naissance est nulle :
SELECT * from Singer WHERE Birth_place IS NULL;

SELECT * from Singer WHERE Birth_place IS NOT NULL;

SELECT * from Singer WHERE isNull(Birth_place)

COUNT ne fonctionne pas avec les NULL.

select count(Birth_place) from Singer;


0
and sum(NULL) gives a NULL answer.

Les opérations normales (comparaisons, expressions...) renvoient NULL si au moins un des éléments
comparés est NULL :

SELECT (NULL=NULL) OR (NULL<>NULL) OR (NOT NULL) OR (1<NULL) OR (1>NULL) OR (1 + NULL) OR (1 LIKE NULL)

Deux valeurs inconnues ne sont donc pas égales (NULL=NULL renvoie NULL).

Gérer NULL
La fonction COALESCE peut simplifier le travail avec NULL.

Par exemple, pour éviter de montrer les valeurs nulles en les traitant comme des zéros :

SELECT COALESCE(colname,0) from table where COALESCE(colname,0) > 1;

Dans un champ date, les traiter comme celle actuelle :

ORDER BY (COALESCE(TO_DAYS(date),TO_DAYS(CURDATE()))-TO_DAYS(CURDATE()))

EXP(SUM(LOG(COALESCE(''*the field you want to multiply*'',1)))

La fonction coalesce() prévient des problèmes de calcul logarithmique d'une valeur nulle, et peut être
optionnelle selon les circonstances.

SELECT t4.gene_name, COALESCE(g2d.score,0),


COALESCE(dgp.score,0), COALESCE(pocus.score,0)
FROM t4
LEFT JOIN g2d ON t4.gene_name=g2d.gene_name
LEFT JOIN dgp ON t4.gene_name=dgp.gene_name
LEFT JOIN pocus ON t4.gene_name=pocus.gene_name;

IFNULL() dans un SELECT fait de NULL n'importe quelle valeur désirée.

IFNULL(expr1,expr2)

Si expr1 n'est pas nulle, IFNULL() renvoie expr1, sinon expr2.

IFNULL() renvoie une chaine ou un nombre, selon le contexte :

mysql> SELECT IFNULL(1,0);


-> 1
mysql> SELECT IFNULL(NULL,10);
-> 10
mysql> SELECT IFNULL(1/0,10);
-> 10
mysql> SELECT IFNULL(1/0,'yes');
-> 'yes'

Attention aux résultats peu prévisibles, par exemple la requête suivante efface toutes les entrées :

DELETE FROM my_table WHERE field > NULL -- fonctionne aussi avec une fonction renvoyant NULL

Pour obtenir les NULL en dernier lors d'un ORDER BY :

SELECT * FROM my_table ORDER BY ISNULL(field), field [ ASC | DESC ]

MySQL propose plus que les standards des opérateurs SQL. Ils peuvent être utilisés pour rédiger des
expressions contenant des constantes, variables, valeurs contenues dans des champs ou autres expressions.

Précédence
Précédence des opérateurs

Du plus au moins prioritaire :

INTERVAL
BINARY, COLLATE
!
-, ~
^
*, /, DIV, %, MOD
-, +
<<, >>
&
|
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
BETWEEN, CASE, WHEN, THEN, ELSE
NOT
&&, AND
XOR
||, OR
:=

Modificateurs :

PIPES_AS_CONCAT : si activé, || est prioritaire sur ^, mais - et ~ le reste sur ||.


HIGH_NOT_PRECEDENCE : si activé, NOT est au niveau de !.

Utilisation des parenthèses

Tout comme en mathématiques, les parenthèses permettent d'évaluer des sous-expressions avant d'autres :

SELECT 1 + 1 * 5 -- = 6
SELECT (1 + 1) * 5 -- = 10

Cela peut aussi se faire pour rendre les requêtes plus lisibles aux humains :

SELECT 1 + (2 * 5)

Opérateurs d'assignation
L'opérateur = peut assigner une valeur à une colonne :

UPDATE `table1` SET `champ1`=0

Par contre pour assigner une valeur à une variable, l'opérateur est :=, car = est déjà utilisé pour la
comparaison.

SELECT @variable1 := 1

SELECT INTO peut aussi remplir les variables.

SELECT 1 INTO @variable1

Opérateurs de comparaison
Égalité

Pour vérifier si deux valeurs sont égales, utiliser = :

SELECT TRUE = TRUE -- 1


SELECT TRUE = FALSE -- 0

Pour vérifier si deux valeurs sont différentes, c'est <> ou != :

SELECT TRUE <> FALSE -- 1


SELECT TRUE != TRUE -- 0

Comparaison IS NULL

Pour savoir si une valeur est nulle, utiliser IS :

SELECT (NULL = NULL) -- NULL


SELECT (NULL IS NULL) -- 1
SELECT (1 IS NULL) -- 0
SELECT (TRUE IS TRUE) -- erreur

Pour savoir si une valeur n'est pas nulle :

SELECT (TRUE IS NOT NULL) -- 1

Il existe par ailleurs l'opérateur <=> qui considère NULL comme une valeur normale :

SELECT NULL <=> NULL -- 1


SELECT TRUE <=> TRUE -- 1
SELECT col1 <=> col2 FROM table1

Comparaison IS booléen

IS et IS NOT fonctionnent aussi avec TRUE, FALSE et UNKNOWN (qui est purement un synonyme de
NULL).

SELECT 1 IS TRUE -- 1
SELECT 1 IS NOT TRUE -- 0
SELECT 1 IS FALSE -- 0
SELECT (NULL IS NOT FALSE) -- 1 : unknown n'est pas false
SELECT (NULL IS UNKOWN) -- 1
SELECT (NULL IS NOT UNKNOWN) -- 0

Plus grand et plus petit que

Avec des nombres :

SELECT 100 > 0 -- 1


SELECT 4 > 5 -- 0

SELECT 1 < 2 -- 1
SELECT 2 < 2 -- 0

Avec du texte dans l'ordre alphabétique :

SELECT 'a' < 'b' -- 1


SELECT `a` >= `b` FROM `table1`
SELECT NOT (`a` < `b`) FROM `table1`
SELECT `a` <= `b` FROM `table1`

Cet ordre alphabétique est définit par COLLATION, pour un CHARACTER SET donné. Par exemple, une
COLLATION peut être sensible à la casse ou pas.

BETWEEN

l'opéraeur BETWEEN ... AND ... permet de vérifier si une valeur appartient à une plage :

SELECT 20 BETWEEN 10 AND 100 -- 1

SELECT 8 NOT BETWEEN 5 AND 10 -- 0

IN

IN permet de s'assurer si une valeur est dans une liste :

SELECT 5 IN (5, 6, 7) -- 1
SELECT 1 IN (5, 6, 7) -- 0
SELECT 1 NOT IN (1, 2, 3) -- 0

Attention : si la liste contient des nombres et des chaines, il faut tout mettre entre apostrophe pour obtenir le
résultat escompté.

SELECT 4 IN ('a', 'z', '5')


Il n'y a aucune limite théorique au nombre de valeurs de la liste.

Opérateurs logiques
Booléens logiques

MySQL n'a pas vraiment de type BOOLEAN.

FALSE est un synonyme de 0. Les chaines vides sont considérées FALSE.

TRUE est un synonyme de 1. Tout ce qui n'est ni FALSE, ni NULL est considéré TRUE.

UNKNOWN est un synonyme de NULL. La date spéciale 0/0/0 est nulle.

NOT

NOT est le seul opérateur qui n'a qu'une seule opérande. Il renvoie 0 si l'opérande est TRUE, 1 si elle est
FALSE, et NULL si elle est NULL.

SELECT NOT 1 -- 0
SELECT NOT FALSE -- 1
SELECT NOT NULL -- NULL
SELECT NOT UNKNOWN -- NULL

! est synonyme de NOT.

AND

AND renvoie 1 si les deux opérandes sont TRUE, sinon 0 ; si au moins l'une des deux opérandes est nulle, il
renvoie NULL.

SELECT 1 AND 1 -- 1
SELECT 1 AND '' -- 0
SELECT '' AND NULL -- NULL

&& est synonyme de AND.

OR

OR renvoie TRUE si au moins une des opérandes est TRUE, sinon FALSE ; si les deux opérandes sont
nulles, il renvoie NULL.

SELECT TRUE OR FALSE -- 1


SELECT 1 OR 1 -- 1
SELECT FALSE OR FALSE -- 0
SELECT NULL OR TRUE -- NULL

|| est un synonyme de OR.


XOR

XOR (ou exclusif) renvoie :

1 si une seule des deux opérandes est TRUE et l'autre FALSE.


0 si les deux sont TRUE ou FALSE.
NULL si au moins l'une des deux est NULL.

SELECT 1 XOR 0 -- 1
SELECT FALSE XOR TRUE -- 1
SELECT 1 XOR TRUE -- 0
SELECT 0 XOR FALSE -- 0
SELECT NULL XOR 1 -- NULL

Opérateurs arithmétiques
Addition

SELECT +1 -- 1
SELECT 1 + 1 -- 2

Soustraction

SELECT -1 -- -1
SELECT -+1 -- -1
SELECT --1 -- 1
SELECT TRUE - 1 -- 0

Multiplication

SELECT 1 * 1 -- 1

Divisions

Renvoie un nombre de type FLOAT :

SELECT 10 / 2 -- 5,0000
SELECT 1 / 1 -- 1,0000
SELECT 1 / 0 -- NULL

Pour retourner la valeur entière du résultat d'une division sous forme de type INTEGER, utiliser DIV :
SELECT 10 DIV 3 -- 3

Le reste de la division (modulo) se trouve avec '%' ou MOD :

SELECT 10 MOD 3 -- 1

Utiliser + pour convertir des données

Pour convertir un INTEGER en FLOAT :

SELECT 1 + 0.0 -- 1.0


SELECT 1 + 0.000 -- 1.000
SELECT TRUE + 0.000 -- 1.000

Il est impossible de convertir une valeur FLOAT en ajoutant 0.0, mais on peut forcer le type en INTEGER :

SELECT '1' + 0 -- 1
SELECT '1' + FALSE -- 1
SELECT <nowiki>''</nowiki> + <nowiki>''</nowiki> -- 0

Opérateurs de texte
Il n'y a pas d'opérateurs de concaténation en MySQL. Les opérateurs arithmétiques convertissent les valeurs
en nombres et pour leurs opérations, donc la concaténation avec + est impossible.

La fonction CONCAT() pallie à cela.

LIKE

L'opérateur LIKE si la chaine recherchée est inclue dans une colonne :

SELECT * FROM articles WHERE titre LIKE 'hello world'

Généralement cette chaine est sensible à la casse, mais il y a deux exceptions, quand :

une comparaison LIKE touche une colonne déclarée en BINARY ;


l'expression contient une clause BINARY :

SELECT * 'test' LIKE BINARY 'TEST' -- 0


Les comparaisons LIKE acceptent deux caractères spéciaux :

_ : n'importe quel caractère (un seul, ni zéro ni deux).


% : n'importe quel séquence de caractères (par exemple zéro ou mille).

A noter que dans les expressions LIKE, \ est aussi le caractère d'échappement pour ', et son comportement
ne peut pas être changé par la clause ESCAPE. Il peut aussi échapper d'autres caractères, mais pas lui-même.

Utilisations courantes de LIKE :

Trouver tous les titres commençant par "hello" :

SELECT * FROM articles WHERE titre LIKE 'hello%'

Trouver tous les titres finissant par "world" :

SELECT * FROM articles WHERE titre LIKE '%world'

Trouver tous les titres contenant la chaine "gnu" :

SELECT * FROM articles WHERE titre LIKE '%gnu%'

Ces caractères spéciaux peuvent être contenus dans le pattern lui-même. Par exemple, pour rechercher les
symboles _ ou % dans la base :

SELECT * FROM articles WHERE titre LIKE '\_%'


SELECT * FROM articles WHERE titre LIKE '\%%'

/ peut-être une alternative à \ si on le précise :

SELECT * FROM articles WHERE titre LIKE '/_%' ESCAPE '/'

Quand on utilise l'opérateur =, les espaces des chaines sont ignorés, mais avec LIKE ils sont reconnus :

SELECT 'word' = 'word ' -- 1


SELECT 'word' LIKE 'word ' -- 0
LIKE fonctionne aussi avec les nombres :

SELECT 123 LIKE '%2%' -- 1

Pour tester si un pattern ne fonctionne pas alors qu'il devrait, utiliser NOT LIKE :

SELECT 'a' NOT LIKE 'b' -- 1

SOUNDS LIKE

SOUNDS LIKE permet de vérifier si deux textes se prononcent pareils. Il utilise l'algorithme SOUNDEX, basé sur
les règles de l'anglais, et peut s'avérer assez approximatif :

SELECT `word1` SOUNDS LIKE `word2` FROM `wordList` -- forme courte


SELECT SOUNDEX(`word1`) = SOUNDEX(`word2`) FROM `wordList` -- forme longue

SOUNDS LIKE est une extension apparue depuis MySQL 4.1.

Expressions régulières

Syntaxe :

SELECT 'string' REGEXP 'pattern'

RLIKE est synonyme de REGEXP.

Exemple, est-ce que la sélection est différente des lettres de A à Z :

SELECT 'a' REGEXP '^[a-z]'; -- 1


SELECT 'A' REGEXP '^[a-z]'; -- 1
SELECT '1' REGEXP '^[a-z]'; -- 0

Opérateur bit à bit


Il existe des opérateurs pour les opérations bit à bit.

Bit-NOT :
SELECT ~0 -- 18446744073709551615
SELECT ~1 -- 18446744073709551614

Bit-AND :

SELECT 1 & 1 -- 1
SELECT 1 & 3 -- 1
SELECT 2 & 3 -- 2

Bit-OR :

SELECT 1 | 0 -- 1
SELECT 3 | 0 -- 3
SELECT 4 | 2 -- 6

Bit-XOR :

SELECT 1 ^ 0 -- 1
SELECT 1 ^ 1 -- 0
SELECT 3 ^ 1 -- 2

Décalage de bit à gauche :

SELECT 1 << 2 -- 4

Décalage de bit à droite :

SELECT 1 >> 2 -- 0

Syntaxe
A l'instar des mots réservés SQL, les noms des fonctions ne sont pas sensibles à la casse :

SELECT DATABASE() -- ok
SELECT DATABASE() -- ok
SELECT DATABASE() -- ok

Si le SQL_MODE IGNORE_SPACE SQL_MODE n'est pas défini, il est impossible de placer un espace
entre le no de la fonction et la première parenthèse, sous peine de voir une erreur 1064. IGNORE_SPACE
est généralement à 0, car cela accélère le parseur. Donc :
SELECT DATABASE () -- déconseillé
SELECT DATABASE() -- recommandé

Toutefois, cette restriction ne s'applique qu'aux fonctions natives de MySQL (pas aux procédures stockées).

Fonctions générales
Fonctions qui dépendent du type.

BENCHMARK(nombre, expression)

Exécute l'expression n fois et retourne toujours zéro [1] , le chiffre pertinent est donc le temps pris par cette
opération de simulation. Utile pour trouver les goulots d'étranglement des expressions SQL :

SELECT BENCHMARK(10000, 'Bonjour'); -- Traitement en 0.0010 sec

CAST(valeur AS type)

Renvoie la valeur convertie en chaine de caractères, comme les apostrophes.

SELECT CAST(20130101 AS DATE); -- 2013-01-01

CHARSET(chaine)

Renvoie le type de caractères de la chaine :

SELECT CHARSET(20130101); -- binary


SHOW CHARACTER SET; -- montre tous les CHARACTER SET installés

COALESCE(valeur, ...)

Renvoie le premier paramètre non nul. S'ils sont tous nuls, renvoie NULL.

SELECT COALESCE(NULL, 'Bonjour', NULL); -- bonjour

COERCIBILITY(chaine)
Renvoie la coercibility d'une chaine (entre 0 et 5) :

SELECT COERCIBILITY('bonjour'); -- 4

Coercibility [2] Signification Exemple


0 Explicit collation Value with COLLATE clause
1 No collation Concatenation of strings with different collations
2 Implicit collation Column value
3 System constant USER() return value
4 Coercible Literal string
5 Ignorable NULL or an expression derived from NULL

COLLATION(chaine)

Renvoie la collation d'une chaine :

SELECT COLLATION('bonjour'); -- utf8_general_ci

CONNECTION_ID()

Renvoie l'identifiant du thread courant :

SELECT CONNECTION_ID(); -- 31

CONVERT(valeur, type)

Tout comme CAST(), retourne la valeur convertie dans le type mentionné :

SELECT CONVERT (20130101, DATE); -- 2013-01-01

CONVERT(chaine USING charset)

Convertit la chaine string passée dans le CHARACTER SET spécifié :

SELECT CONVERT ('Voici une écriture' USING utf8); -- Voici une écriture
SELECT CONVERT ('Voici une écriture' USING ASCII); -- Voici une ?criture
CURRENT_USER()

Retourne les noms de l'utilisateur et de l'hôte courants :

SELECT CURRENT_USER(); -- root@localhost

DATABASE()

Retourne le nom de la base de données courante :

SELECT DATABASE(); -- wiki1

FOUND_ROWS()

Après un SELECT avec une LIMIT et le mot clé SQL_CALC_FOUND_ROWS, il est possible de lancer un autre
SELECT avec FOUND_ROWS(). En effet il renvoie le nombre de ligne de la clause précédente, sans la limite :

SELECT FOUND_ROWS() AS n; -- 0
SELECT SQL_CALC_FOUND_ROWS * FROM wiki1_page ORDER BY page_id LIMIT 10 OFFSET 2; -- deux lignes
SELECT FOUND_ROWS() AS n; -- 1

GREATEST(valeur1, valeur2, ...)

Renvoie la plus grande valeur des paramètres :

SELECT GREATEST(1, 2, 21, 3); -- 21

IF(valeur1, valeur2, valeur3)

If valeur1 est vraie, renvoie valeur2, sinon (fausse ou nulle) renvoie valeur3.

SELECT IF(1=2, 'irréel', 'réel'); -- réel

IFNULL(valeur1, valeur2)

Si valeur1 est nulle, renvoie valeur2, sinon valeur1.

SELECT IFNULL('variable1', 'défaut'); -- variable1


ISNULL(valeur)

Si la valeur passée est nulle, renvoie 1, sinon 0.

SELECT ISNULL('variable1'); -- 0

INTERVAL(valeur1, valeur2, valeur3, ...)

Renvoie l'emplacement du premier argument supérieur au premier, en partant du zéro dans la liste des
entiers en paramètres :

SELECT INTERVAL(10, 20, 9, 8, 7); -- 0


SELECT INTERVAL(10, 9, 20, 8, 7); -- 1
SELECT INTERVAL(10, 9, 8, 20, 7); -- 2
SELECT INTERVAL(10, 9, 8, 7, 20); -- 3

NULLIF(valeur1, valeur2)

Renvoie NULL si valeur1 = valeur2, sinon valeur1.

SELECT NULLIF(10, 20); -- 10

LEAST(valeur1, valeur2, ...)

Renvoie la plus petite valeur dans la liste des paramètres passés :

SELECT LEAST(1, 2, 21, 3, -1); -- -1

Date et heure
Trouver la date de l'an dernier :

SELECT CURDATE() - INTERVAL 1 YEAR

Sélectionner toutes les pages du wiki non lues depuis plus un an :


SELECT * FROM wiki1_page
WHERE page_touched <= (CURDATE() - INTERVAL 1 YEAR);

Autres exemples de sélections :

SELECT IF(DAYOFMONTH(CURDATE()) <= 15,


DATE_FORMAT(CURDATE(), '%Y-%m-15'),
DATE_FORMAT(CURDATE() + INTERVAL 1 MONTH, '%Y-%m-15')) AS next15
FROM TABLE;

SELECT YEAR('2002-05-10'), MONTH('2002-05-10'), DAYOFMONTH('2002-05-10')

SELECT PurchaseDate FROM TABLE WHERE YEAR(PurchaseDate) <= YEAR(CURDATE())

SELECT COLUMNS FROM TABLE


WHERE start_time >= '2004-06-01 10:00:00' AND end_time <= '2004-06-03 18:00:00'

SELECT * FROM t1
WHERE DATE_FORMAT(datetime_column, '%T') BETWEEN 'HH:MM:SS' AND 'HH:MM:SS'

SELECT Start_time, End_time FROM TABLE


WHERE Start_time >= NOW() - INTERVAL 4 HOUR

SELECT NOW() + INTERVAL 60 SECOND

SELECT UNIX_TIMESTAMP('2007-05-01'); -- 1177970400


SELECT FROM_UNIXTIME(1177970400); -- 2007-05-01 00:00:00

Fonctions d'agrégation
COUNT(champ)

Si le paramètre est "*" au lieu d'un nom de colonne, COUNT() renvoie les nombre de lignes total de la
requête. Cela peut permettre de savoir combien de lignes possède une table, par exemple le nombre de pages
d'un wiki :

SELECT COUNT(*) FROM `wiki1_page`;

Si le mot DISTINCT est employé, cela ignore les doublons :

SELECT COUNT(DISTINCT *) FROM `wiki1_page`;

Si le nom d'un champ est précisé, cela renvoie le nombre de valeurs non nulles :

SELECT COUNT(`user_real_name`) FROM `wiki1_user`;

SELECT COUNT(DISTINCT `user_real_name`) FROM `wiki1_user`;

Cela fonctionne aussi pour des expressions, des combinaisons de champs :


SELECT COUNT(`user_name` + `user_real_name`) FROM `wiki1_user`;

MAX(champ)

MAX() renvoie la valeur maximum d'une expression issue du résultat d'une requête, ou NULL s'il n'y en a
pas :

SELECT MAX(`user_editcount`) FROM `wiki1_user`;

SELECT MAX(LENGTH(CONCAT(`user_name`, ' ', `user_real_name`))) FROM `wiki1_user`;

MIN(champ)

MIN() renvoie la valeur minimum d'une expression issue du résultat d'une requête, ou NULL s'il n'y en a pas :

SELECT MIN(`user_editcount`) FROM `wiki1_user`;

SELECT MIN(LENGTH(CONCAT(`user_name`, ' ', `user_real_name`))) FROM `wiki1_user`;

AVG(champ)

AVG() renvoie la valeur moyenne d'une expression, ou NULL s'il n'y en a pas :

SELECT AVG(`user_editcount`) FROM `wiki1_user`;

SUM(champ)

SUM() dresse la somme des valeurs d'une expression, ou NULL s'il n'y en a pas.

Si SUM(DISTINCT expression) est utilisé, les valeurs identiques ne sont ajoutées qu'une seule fois. Il a été
ajouté après MySQL 5.1.

SELECT SUM( DISTINCT user_editcount )


FROM wiki1_user

GROUP_CONCAT(champ)

GROUP_CONCAT() concatène les valeurs de tous les enregistrements d'un groupe dans une seule chaine
séparée par une virgule, ou un token additionnel.
CREATE TEMPORARY TABLE p (
id INTEGER, ptype VARCHAR(10), pnom VARCHAR(50)
);

INSERT INTO p VALUES


(1,'mp3','iPod'),
(2,'mp3','Zune'),
(3,'mp3','ZEN'),
(4,'notebook','Acer Eee PC'),
(4,'notebook','Everex CloudBook');

SELECT * FROM p;

SELECT ptype,group_concat(pnom)
FROM p
GROUP BY ptype;

SELECT ptype,group_concat(' ',pnom)


FROM p
GROUP BY ptype;

Fonctions d'agrégation de bit

Syntaxe générale :

FUNCTION_NAME(''expression'')

Ces fonctions bit à bit calculent expression pour chaque ligne du résultat et entre les expressions. La
précision est de 64 bit.

AND

SELECT BIT_AND(ip) FROM log

OR

SELECT BIT_OR(ip) FROM log

(retourne 0 s'il n'y a aucun résultat)

XOR

SELECT BIT_XOR(ip) FROM log

(retourne 0 s'il n'y a aucun résultat)


Références

1. ↑ (en) http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/

MySQL peut enregistrer des requêtes pour les rappeler comme les fonctions d'un programme. Elles peuvent
intégrer des contrôles de flux, des boucles et des curseurs. Il en existe trois sortes :

Déclencheurs (ou triggers) : programmes qui se déclenchent avant ou après un évènement impliquant une
table (DELETE, INSERT, UPDATE) ;
Évènements : programmes exécutés à une certaine date, régulièrement ;
Procédures stockées : programmes invocable par la commande SQL CALL.

Les futures versions de MySQL pourraient même stocker des procédures écrites dans d'autres langages que
SQL.

Déclencheurs
Gestion des TRIGGER

Disponibles depuis MySQL 5.0.2, ils fonctionnent sur les tables persistantes, mais pas les temporaires.

CREATE TRIGGER

CREATE TRIGGER `effacer_ancien` AFTER INSERT ON `wiki1_page`


FOR EACH ROW
DELETE FROM `wiki1_page` ORDER BY `page_id` ASC LIMIT 1

Cet exemple est une requête DELETE appelée `effacer_ancien`, qui se lance après qu'un nouvel
enregistrement soit inséré dans la table. Si un INSERT ajoute plusieurs lignes à une table, le déclencheur est
appelé plusieurs fois.

Les conditions de déclenchement des triggers doivent être des commandes LMD basiques :

INSERT, dont LOAD DATA et REPLACE ;


DELETE, incluant REPLACE, mais pas TRUNCATE ;
UPDATE

Un cas particulier est INSERT ... ON DUPLICATE KEY UPDATE. Si INSERT est exécuté, BEFORE INSERT ou
AFTER INSERT sont exécutés. Si UPDATE est exécuté à la place de INSERT, l'ordre des évènements est le
suivant : BEFORE INSERT, BEFORE UPDATE, AFTER UPDATE.

Le déclencheur peut aussi s'appliquer à une table en particulier :

... ON `base1`.`table1` ...

Les noms des triggers doivent être unique pour chaque base.
Contrairement au standard SQL, tous les déclencheurs sont exécutés FOR EACH ROW, et non pour chaque
commande.

Une procédure stockée doit être spécifiée entre les mots BEGIN et END sauf s'il ne contient qu'une seule
commande. Le SQL dynamique ne peut pas y être utilisé (PREPARE) ; Une autre procédure stockée peut être
appelée à la place.

Il est posible d'accéder à l'ancienne valeur d'un champ (avant l'exécution de la procédure) et à la nouvelle
valeur :

CREATE TRIGGER `use_values` AFTER INSERT ON `example_tab`


FOR EACH ROW BEGIN
UPDATE `changelog` SET `old_value`=OLD.`field1`, `new_value`=NEW.`field1` WHERE `backup_tab`.`id`
END

DROP TRIGGER

Pour supprimer un déclencheur :

DROP TRIGGER `trigger1`


-- ou
DROP TRIGGER `base1`.`trigger1`
-- ou
DROP TRIGGER IF EXISTS `trigger1`

Pour modifier un trigger, il faut le supprimer puis le recréer.

Métadonnées des TRIGGER

SHOW CREATE TRIGGER

Disponible depuis MySQL 5.1. Affiche la commande pour recréer un déclencheur nommé :

SHOW CREATE TRIGGER effacer_ancien;

Trigger : Nom du déclencheur.


sql_mode : valeur du SQL_MODE au moment de l'exécution.
SQL Original Statement
character_set_client
collation_connection
Database Collation

SHOW TRIGGERS

Pour obtenir la liste des triggers de la base courante :


SHOW TRIGGERS;

Pour obtenir la liste des triggers d'une autre base :

SHOW TRIGGERS IN `base2`


-- ou
SHOW TRIGGERS FROM `base2`

D'autres filtres sont possibles :

SHOW TRIGGERS WHERE TABLE='wiki1_page'

Remarque : Il est impossible d'utiliser LIKE et WHERE ensemble.

Les colonnes du déclencheur sont :

Trigger : nom
Event : commande SQL qui le déclenche
Table : table associée
Statement : requête exécutée
Timing : BEFORE ou AFTER
Created : toujours NULL
sql_mode : SQL_MODE définit lors de sa création
Definer : créateur
character_set_client : valeur de la variable `character_set_client` lors de la création
collation_connection : valeur de la variable `collation_connection` lors de la création
Database Collation : COLLATION utilisée par la base du trigger.

INFORMATION_SCHEMA.TRIGGERS

La base virtuelle INFORMATION_SCHEMA a une table `TRIGGERS` avec les colonnes suivantes :

TRIGGER_CATALOG : catalogue contenant le trigger ;


TRIGGER_SCHEMA : SCHEMA (DATABASE) contenant le trigger ;
TRIGGER_NAME : nom du trigger ;
EVENT_MANIPULATION : INSERT, UPDATE ou DELETE ;
EVENT_OBJECT_CATALOG : pas encore implémenté ;
EVENT_OBJECT_SCHEMA : schéma contenant la table associée au trigger ;
EVENT_OBJECT_NAME : nom de la table associée au trigger ;
ACTION_ORDER : pas encore implémenté ;
ACTION_CONDITION : pas encore implémenté ;
ACTION_STATEMENT : commande exécutée lors de l'activation du trigger ;
ACTION_ORIENTATION : pas encore implémenté ;
ACTION_TIMING : BEFORE ou AFTER ;
ACTION_REFERENCE_OLD_TABLE : pas encore implémenté ;
ACTION_REFERENCE_NEW_TABLE : pas encore implémenté ;
ACTION_REFERENCE_OLD_ROW : pas encore implémenté ;
ACTION_REFERENCE_NEW_ROW : pas encore implémenté ;
CREATED : date et heure de création (pas encore implémenté) ;
SQL_MODE : SQL_MODE valide pour l'exécution du trigger ;
DEFINER : créateur du trigger, sous la forme 'utilisateur@hôte' ;
CHARACTER_SET_CLIENT : valeur de la variable `character_set_client` lors de la création ;
COLLATION_CONNECTION : valeur de la variable `collation_connection` lors de la création ;
DATABASE_COLLATION : COLLATION utilisée par la base.

Évènements
Les évènements sont aussi appelé en anglais Scheduled Events ou Temporal Triggers. Ils sont planifiés pour
s'exécuter à un moment donné, date ou intervalle de temps. Ils sont similaire aux crontab UNIX.

Quand un évènement est lancé, il doit être complètement exécuté. S'il est réactivé avant la fin de son
exécution, une nouvelle instance du même évènement est créée. Donc il est conseillé d'utiliser LOCK pour
éviter qu'ils interfèrent entre eux.

Le planificateur des évènements est un thread en permanence en exécution, afin d'être en mesure de lancer
les évènements à tout moment. Il peut toutefois être désactivé en lançant MySQL avec ces options :

mysqld --event-scheduler=DISABLED

Ou bien en ajoutant une ligne dans le fichier de configuration (my.cnf) :

event_scheduler=DISABLED

Ou encore en cours d'utilisation :

SELECT event_scheduler -- valeurs : ON / OFF / DISABLED


SET GLOBAL event_scheduler = ON
SET GLOBAL event_scheduler = OFF

Quand il est lancé, on peut vérifier son status avec SHOW PROCESSLIST. Son utilisateur est 'event_scheduler'.
Quand il est en sommeil, `State` est à 'Waiting for next activation'.

Gestion des EVENT

Les commandes sont CREATE EVENT, ALTER EVENT, DROP EVENT.

CREATE EVENT

Pour un évènement à exécuter le lendemain :

CREATE EVENT `évènement1`


ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY
DO
INSERT INTO `wiki1`.`news` (`title`, `text`) VALUES ('Example!', 'This is not a real news')

Son nom est obligatoire et doit être précisé après CREATE EVENT.

Pour créer une tâche à exécuter une seule fois, utiliser AT. Pour ne pas spécifier la date et l'heure de manière
absolue, mais relativement après un intervalle, utiliser AT CURRENT_TIMESTAMP + INTERVAL ....

Une tâche récurrente s'obtient avec EVERY :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
DO
OPTIMIZE TABLE `wiki1`.`news`

On peut aussi spécifier la date et l'heure du début et/ou de la fin. La tâche sera exécutée à intervalle régulier
entre ces dates :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY INTERVAL 1 DAY
DO
OPTIMIZE TABLE `wiki1`.`news`
STARTS CURRENT_TIMESTAMP + 1 MONTH
ENDS CURRENT_TIMESTAMP + 3 MONTH

Les unités autorisées sont :

YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, YEAR_MONTH, DAY_HOUR, DAY_MINUTE, DAY_SECOND, HOUR_MINUTE

La clause DO spécifie la commande à exécuter.

Si la tâche est composée par plus d'une commande, utiliser BEGIN ... END :

delimiter |
CREATE EVENT `évènement3`
ON SCHEDULE
EVERY 1 DAY
DO
BEGIN
DELETE FROM `logs`.`user` WHERE `deletion_time` < CURRENT_TIMESTAMP - 1 YEAR;
DELETE FROM `logs`.`messages` WHERE `deletion_time` < CURRENT_TIMESTAMP - 1 YEAR;
UPDATE `logs`.`activity` SET `last_cleanup` = CURRENT_TIMESTAMP;
END |
delimiter ;

Si un EVENT du même nom existe déjà, le serveur renvoie une erreur. On peut l'éviter avec IF NOT EXISTS :
CREATE EVENT `évènement2`
IF NOT EXISTS
ON SCHEDULE EVERY 2 DAY
DO
OPTIMIZE TABLE `wiki1`.`news`

Après expiration de l'évènement, MySQL le supprimer par défaut. Pour éviter cela afin de pouvoir le
réutiliser son code ultérieurement, utiliser ON COMPLETION :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
ON COMPLETION PRESERVE
DO
OPTIMIZE TABLE `wiki1`.`news`

On peut aussi dire explicitement à MySQL de le supprimer :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
ON COMPLETION NOT PRESERVE
DO
OPTIMIZE TABLE `wiki1`.`news`

En précisant une date de lancement antérieure, l'évènement expire immédiatement après sa création, c'est
pourquoi le serveur prévient avec un warning 1588, normalement.

Pour préciser si un évènement est activé lors de sa création, les mots sont ENABLE, DISABLE, DISABLE ON
SLAVES (ce dernier ne se réplique pas sur les bases de données esclaves). Par défaut, il est activé :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
ON COMPLETION NOT PRESERVE
DISABLE
DO
OPTIMIZE TABLE `wiki1`.`news`

Pour le modifier : ALTER EVENT.

On peut aussi commenter l'évènement dans une limite de 64 caractères :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
ON COMPLETION NOT PRESERVE
DISABLE
COMMENT 'let\'s optimize some tables!'
DO
OPTIMIZE TABLE `wiki1`.`news`

Par ailleurs, on peut modifier l'utilisateur de l'évènement pour obtenir d'autres permissions. Par exemple
depuis celui voulu avec CURRENT_USER :
CREATE DEFINER = CURRENT_USER
EVENT `évènement2`
ON SCHEDULE EVERY 2 DAY
DO
OPTIMIZE TABLE `wiki1`.`news`

Spécifier un autre utilisateur nécessite les droits root :

CREATE DEFINER = 'allen@localhost'


EVENT `évènement2`
ON SCHEDULE EVERY 2 DAY
DO
OPTIMIZE TABLE `wiki1`.`news`

ALTER EVENT

Renommage d'un évènement :

CREATE EVENT `évènement2`


ON SCHEDULE EVERY 2 DAY
ON COMPLETION NOT PRESERVE
RENAME TO `évènement3`
DISABLE
COMMENT 'let\'s optimize some tables!'
DO
OPTIMIZE TABLE `wiki1`.`news`

On peut aussi ne définir que la clause à modifier :

CREATE EVENT `évènement2` ENABLE;

DROP EVENT

Avec les permissions sur l'évènement à supprimer :

DROP EVENT `évènement3`

S'il n'existe pas l'erreur 1517 survient. Pour l'éviter :

DROP EVENT IF EXISTS `évènement3`

Métadonnées des EVENT


SHOW CREATE EVENT

Cette commande retourne la commande CREATE EVENT utilisée pour créer le trigger, et sur les paramètres
l'impactant.

SHOW CREATE EVENT évènement2

Les colonnes du résultat sont :

Event : nom
sql_mode : mode SQL utilisé (ex : NO_ENGINE_SUBSTITUTION)
time_zone : fuseau horaire du créateur (ex : SYSTEM)
Create Event : code qui a généré l'évènement
character_set_client (ex : utf8)
collation_connection (ex : utf8_general_ci)
Database Collation (ex : latin1_swedish_ci)

SHOW EVENTS

Pour afficher tous les évènements de la base courante :

SHOW EVENTS

Pour une base en particulier :

SHOW EVENTS FROM `wiki1`


-- Ou
SHOW EVENTS IN `wiki1`

Autres filtres :

SHOW EVENTS LIKE 'év%'


SHOW EVENTS WHERE definer LIKE 'admin@%'

Types de résultat :

Db : nom de la base ;
Name : nom de l'évènement ;
Definer : créateur (user@host) ;
Time zone : fuseau horaire ;
Type : 'ONE TIME' ou 'RECURRING' selon la récurrence ;
Executed At : date de l'exécution, ou NULL pour les récursifs ;
Interval Value : nombre d'intervalle entre les exécutions, ou NULL pour les non récursifs ;
Interval Field : unités de mesure de l'intervalle (ex : 'SECOND'), ou NULL pour les non récursifs ;
Starts : date de première exécution, ou NULL pour les non récursifs ;
Ends : date de dernière exécution, ou NULL pour les non récursifs ;
Status : ENABLED, DISABLED, ou SLAVESIDE_DISABLED ;
Originator : identifiant du serveur créateur (0 pour le courant). Disponible depuis MySQL 5.1 ;
character_set_client
collation_connection
Database Collation

INFORMATION_SCHEMA.EVENTS

La base virtuelle INFORMATION_SCHEMA contient une table `EVENTS` depuis MySQL 5.1. Voici ses
colonnes :

EVENT_CATALOG : toujours NULL (les CATALOG ne sont pas encore implémentés par MySQL) ;
EVENT_SCHEMA : nom de la base ;
EVENT_NAME : nom de l'évènement ;
DEFINER : créateur (user@host) ;
TIME_ZONE : fuseau horaire ;
EVENT_BODY : langage utilisé ;
EVENT_DEFINITION : routine à exécuter ;
EVENT_TYPE : 'ONE TIME' ou 'RECURRING' selon la récurrence ;
EXECUTE_AT : date de l'exécution, ou NULL pour les récursifs ;
INTERVAL_VALUE : nombre d'intervalle entre les exécutions, ou NULL pour les non récursifs ;
INTERVAL_FIELD : unités de mesure de l'intervalle (ex : 'SECOND'), ou NULL pour les non récursifs ;
SQL_MODE mode SQL ;
STARTS : date de première exécution, ou NULL pour les non récursifs ;
ENDS : date de dernière exécution, ou NULL pour les non récursifs ;
STATUS : ENABLED, DISABLED, ou SLAVESIDE_DISABLED ;
ON_COMPLETION : 'NOT PRESERVE' ou 'PRESERVE' ;
CREATED : date de création ;
LAST_ALTERED : date de dernière modification ;
LAST_EXECUTED : date de dernière exécution ;
EVENT_COMMENT : commentaires ;
ORIGINATOR : identifiant du serveur créateur (0 pour le courant). Disponible depuis MySQL 5.1 ;
character_set_client
collation_connection
Database Collation

Procédures stockées
Les procédures stockées sont des modules SQL exécutables avec CALL.

Il en existe deux types :

1. FUNCTION si elles retournent un résultat.


2. PROCEDUREs si elles ne retourne rien après leur traitement.

Avantages

Elles réduisent le trafic du réseau car une seule commande permet de leur en faire exécuter plusieurs. Les
appeler est donc plus rapide.
Ces modules peuvent être invoqués plusieurs fois depuis n'importe quel langage (PHP, Java...).
Elles conservent une logique entre les bases : le DBA peut les modifier sans toucher aux programmes qui
les appellent.
Peut permettre aux utilisateurs qui n'ont pas accès à une table de récupérer ses données ou la modifier dans
certaines circonstances.

Gestion des PROCEDURE et FUNCTION

CREATE PROCEDURE

Création de procédure stockée :

CREATE DEFINER = `root`@`localhost` PROCEDURE `Module1` ( ) NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER

CALL

Invocation :

CALL `Module1` ();

DROP PROCEDURE

Suppression :

DROP PROCEDURE `Module1` ;

Modification

On est obligé de supprimer et de recréer le module :

DROP PROCEDURE `Module1` ;


CREATE DEFINER = `root`@`localhost` PROCEDURE `Module1` ( ) NOT DETERMINISTIC NO SQL SQL SECURITY DEFINER
BEGIN
OPTIMIZE TABLE wiki1_page;
OPTIMIZE TABLE wiki1_user;
END

Métadonnées des PROCEDURE et FUNCTION

SHOW FUNCTION / PROCEDURE STATUS


SHOW PROCEDURE STATUS;

SHOW CREATE FUNCTION / PROCEDURE

SHOW CREATE PROCEDURE Module1;

INFORMATION_SCHEMA.ROUTINES

La base virtuelle INFORMATION_SCHEMA a une table `ROUTINES` avec les informations des
procédures et fonctions.

INFORMATION_SCHEMA.PARAMETERS

Cette section est vide, pas assez détaillée ou incomplète.

Extensions au standard SQL


Délimiteur

MySQL utilise un caractère comme délimiteur pour séparer ses requêtes, par défaut ';'. Quand on crée des
procédures stockées avec plusieurs requêtes, on en crée en fait une seule : CREATE de la procédure. Toutefois,
si elles sont séparées par ';', il faut demander à MySQL de les ignorer pour estimer la fin du CREATE.

Dans l'exemple suivant, '|' joue ce rôle :

delimiter |
CREATE EVENT évènement1
ON SCHEDULE EVERY 1 DAY
DO
BEGIN
TRUNCATE `wiki1`.`wiki1_page`;
TRUNCATE `wiki1`.`wiki1_user`;
END
delimiter ;

Flow control

Cette section est vide, pas assez détaillée ou incomplète.

Loops

Cette section est vide, pas assez détaillée ou incomplète.

Error handling
Cette section est vide, pas assez détaillée ou incomplète.

Cursors

Cette section est vide, pas assez détaillée ou incomplète.

Exporter
Le mot clé est INTO OUTFILE :

SELECT * FROM destinataire INTO OUTFILE '/tmp/test' WHERE id IN (41, 141, 260, 317, 735, 888, 1207, 2211)

Le processus MySQL écrit lui-même le fichier, pas l'utilisateur. De plus, le fichier est stocké sur le serveur,
pas le client.

Généralement le serveur a le droit d'écrire dans /tmp, donc même s'il n'est pas sécurisé ce répertoire est
utilisé pour les exemples ci-dessous.

Par ailleurs, exporter est possible en ligne de commande :

mysql < query.txt > output.txt

Ou bien via mysqldump.

Importer
Pour importer un fichier :

LOAD DATA INFILE '/tmp/test' INTO TABLE destinataire;

Options additionnelles :

FIELDS TERMINATED BY '\t'


LINES TERMINATED BY '\n'
IGNORE 1 LINES

Pour spécifier la structure du document et la présence d'en-tête, on peut associer les colonnes de la base à
des variables :
LOAD DATA LOCAL INFILE
'/tmp/test'
INTO TABLE destinataire
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(
@dummy,
name,
phone_number,
@dummy,
@dummy,
@dummy,
@dummy,
@dummy,
@dummy,
@dummy
)

Dans cet exemple, seule la seconde et troisième colonne du fichier sont stockées dans le champ name et
phone_number.

Principe
La réplication signifie que les données écrites sur le master MySQL sont envoyées à des slaves faisant
office de copies.

Applications :

sauvegardes
accès en lecture de la même base depuis plusieurs serveurs : augmentation des performances
failover

Il y a deux types de réplication :

Asynchrone (master/slave)
Semi-asynchrone (réplication asynchrone plus avec un slave avant de terminer la requête)

Configurations des réplications :

standard : master->slave
double maître : master<->master

En Master-Master les deux hôtes sont tour à tour master et slave : le serveur A se réplique sur le serveur B
qui se réplique sur le serveur A. Il n'y a pas de vérification de consistance des données, même si
auto_increment_increment/auto_increment_offset est configuré les deux serveurs ne doivent pas être
utilisés pour des accès concurrents.

Réplication asynchrone
C'est le cas le plus simple, un master écrit un fichier de log binaire, et les slaves peuvent lire ce dernier
(potentiellement sélectivement) pour rejouer les commandes de la requête.

Étant asynchrone, le master et les slaves peuvent avoir différents états au même moment. Cette
configuration peut résister aux coupures réseau.

Configuration du master
Dans /etc/mysql/my.cnf, section [mysqld] :

Définir un identifiant de serveur ; par exemple 1 :

server-id = 1

La réplication est basée sur les logs binaires, donc les activer :

log-bin
# ou log-bin = /var/log/mysql/mysql-bin.log

Créer un nouvel utilisateur pour que le slave puisse se connecter :

CREATE USER 'myreplication';


SET PASSWORD FOR 'myreplication' = PASSWORD('mypass');
GRANT REPLICATION SLAVE ON *.* TO 'myreplication';

Vérifier l'identifiant de serveur :

SHOW VARIABLES LIKE 'server_id';

Configuration de chaque slave

Dans /etc/mysql/my.cnf, section [mysqld] :

Définir un identifiant de serveur différent du master et des autres slaves :

server-id = 2

Vérifier avec :

SHOW VARIABLES LIKE 'server_id';

Il est aussi possible de déclarer le nom de la machine slave dans le master (cf. SHOW SLAVE HOSTS) :

report-host=slave1
Déclarer le master :

CHANGE MASTER TO MASTER_HOST='master_addr', MASTER_USER='myreplication', MASTER_PASSWORD='mypass';

Si la réplication sert de backup, spécifier le point de départ :

MASTER_LOG_FILE='<binary_log_from_master>', MASTER_LOG_POS=<master_binary_log_position>;

Démarrer la réplication :

START SLAVE;

Cela va créer un fichier master.info, typiquement dans /var/lib/mysql/master.info ; contenant la


configuration et le statut.

Vérifier la réplication

Sur le slave

SHOW SLAVE STATUS;

Ou bien pour avoir un résultat formaté plus lisible :

SHOW SLAVE STATUS\G

Exemple :

*************************** 1. ROW ***************************


Slave_IO_State:
Master_Host: master_addr
Master_User: myreplication
Master_Port: 3306
...

Vérifier en particulier :

Slave_IO_Running: Yes
Slave_SQL_Running: Yes
On peut supposer une nature réplication asynchrone :

Seconds_Behind_Master: 0

Voir aussi :

mysql> SHOW GLOBAL VARIABLES LIKE "%SLAVE%";

Sur le master

Vérifier les connexions des slaves :

mysql> SHOW PROCESSLIST\G


[...]
*************************** 6. ROW ***************************
Id: 14485
USER: myreplication
Host: 10.1.0.106:33744
db: NULL
Command: Binlog Dump
TIME: 31272
State: Has sent ALL binlog TO slave; waiting FOR binlog TO be updated
Info: NULL

IF you enabled <code>report-host</code>, the slave IS also visible IN:


mysql> SHOW SLAVE HOSTS;
+-----------+---------+------+-------------------+-----------+
| Server_id | Host | Port | Rpl_recovery_rank | Master_id |
+-----------+---------+------+-------------------+-----------+
| 2 | myslave | 3306 | 0 | 1 |
+-----------+---------+------+-------------------+-----------+
1 ROW IN SET (0.00 sec)

Consistance

La réplication est une simple copie, similaire aux sorties mysqldump dans le client mysql.

par conséquent, pour maintenir cette consistance :

Ne pas écrire sur le slave ;


Démarrer la réplication avec des données initiales identiques sur le master et le slave ;
Utiliser les mêmes versions de MySQL sur eux peut aider.

Réparer

Par défaut, la réplication stoppe en cas d'erreur (provenant du réseau ou d'une requête).

Dans ce cas, regarder la trace dans le log (généralement /var/log/syslog) :


Oct 15 21:11:19 builder mysqld[4266]: 101015 21:11:19 [ERROR] Slave: Error 'Table 'mybase.form'
doesn't exist' on query. Default database: 'mybase'. Query:
'INSERT INTO `form` (`form_id`,`timestamp`,`user_id`) VALUES ('abed',1287172429,0)',
Error_code: 1146

La meilleure façon et de relancer la réplication entièrement.

On peut aussi tenter de réparer, par exemple faire sauter à MySQL la commande 1 :

STOP SLAVE;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE;

Attention en définissant ce nombre car il contient toutes les commandes, pas seulement les erreurs.

Une autre façon est d'utiliser les outils Maatkit :

mk-slave-restart (pour relancer la réplication du slave si SQL_SLAVE_SKIP_COUNTER ne peut pas aider)


mk-table-checksum (pour faire un checksum des tables sur le master et le slave)
mk-table-sync (pour synchroniser le slave avec le master basé sur des statistiques générés par mk-table-
checksum).

Désinstaller

Pour supprimer une réplication :

mysql> RESET SLAVE;

MySQL me le slave en pause et remplace la configuration avec les valeurs par défaut. master.info est
effacé.
Relancer MySQL pour effacer toute la configuration.

Attention : STOP SLAVE arrêt la réplication. Elle peut être relancée manuellement ensuite, ou bien
automatiquement lors de la relance du serveur MySQL. Pour éviter ce lancement automatique :

slave-skip-START

Pour arrêter d'utiliser la réplication, vérifier que la configuration est bien vide :

mysql> SHOW SLAVE STATUS;


Empty SET (0.00 sec)
Avant de démarrer l'optimisation
Quand la base est anormalement lente, vérifier les points suivants :

1. Trouver les goulots d'étranglements (processeur, RAM, I/O, requêtes)


2. Chercher à complexifier les requêtes gourmandes. Généralement on effectue les opérations suivantes
dans cet ordre pour éliminer un maximum de données inutiles des résultats rapidement : projection,
sélection, jointure.
3. Optimiser l'application en retirant les requêtes ou cache PHP des pages web.
4. Optimiser les requêtes (ajouter des index, des tables temporaires ou changer de jointure).
5. Optimiser la base du serveur (taille du cache, etc.).
6. Optimiser le système (les différents systèmes de fichier, le swap (mémoire virtuelle) et les versions du
noyau).
7. Optimiser l'hardware.

Des outils existent pour trouver les goulots d'étranglement :

vmstat
monitore les utilisations du processeur, de la RAM et des I/O en les classant.
mytop
trouve les requêtes lourdes.
mysql-admin (à ne pas confondre avec mysqladmin)
monitore et personnalise MySQL de façon convenable.
mysqlreport (http://hackmysql.com/mysqlreport) [archive]
checklist pas à pas.

On peut ensuite classer les applications en trois groupes par leurs nécessités :

I/O et lecture (blogs, news).


I/O et écriture (traqueur de connexion web, collection de données de compte).
CPU (CMS, logiciel de business).

Optimiser les requêtes


Comparer les fonctions avec BENCHMARK

BENCHMARK() permet de mesurer les rapidité des fonctions ou opérateurs MySQL :

mysql> SELECT BENCHMARK(100000000, CONCAT('a','b'));


+---------------------------------------+
| BENCHMARK(100000000, CONCAT('a','b')) |
+---------------------------------------+
| 0 |
+---------------------------------------+
1 ROW IN SET (21.30 sec)

Toutefois, on ne peut pas comparer des requêtes avec :


mysql> SELECT BENCHMARK(100, SELECT `id` FROM `lines`);
ERROR 1064 (42000): You have an error IN your SQL syntax;
CHECK the manual that corresponds TO your MySQL server version FOR
the RIGHT syntax TO USE near 'SELECT `id` FROM `lignes`)' at line 1

En effet, sachant que MySQL doit parser la requête, on peut considérer que les benchmarks inférieurs à 10 s
ne sont pas exploitables.

Analyse des fonctions avec EXPLAIN

En ajoutant EXPLAIN devant SELECT, MySQL détaille les différentes opérations qu'il effectue dans le cadre
de cette sélection (comment les tables sont jointes et dans quel ordre).

Exemple

Jointure de deux tables sans indice :

mysql> EXPLAIN SELECT * FROM a LEFT JOIN b USING (i) WHERE a.i < 2;
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 4 | USING WHERE |
| 1 | SIMPLE | b | ALL | NULL | NULL | NULL | NULL | 3 | |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
2 ROWS IN SET (0.01 sec)

Maintenant on ajoute un index sur la seconde table, ce qui fait descendre ensuite lors de la même sélection,
la colonne rows de la seconde ligne : MySQL a donc effectué une lecture de moins pour le même résultat.

mysql> ALTER TABLE b ADD KEY(i);


Query OK, 3 ROWS affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> EXPLAIN SELECT * FROM a LEFT JOIN b USING (i) WHERE a.i < 2;
+----+-------------+-------+------+---------------+------+---------+----------+------+-------------+
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
+----+-------------+-------+------+---------------+------+---------+----------+------+-------------+
| 1 | SIMPLE | a | ALL | NULL | NULL | NULL | NULL | 4 | USING WHERE |
| 1 | SIMPLE | b | REF | i | i | 5 | test.a.i | 2 | |
+----+-------------+-------+------+---------------+------+---------+----------+------+-------------+
2 ROWS IN SET (0.00 sec)

Enfin, en ajoutant un index sur la première table, la condition WHERE est améliorée car MySQL sait qu'il ne
lui faut qu'une ligne de la première table (au lieu de quatre) :

mysql> ALTER TABLE a ADD KEY(i);


Query OK, 4 ROWS affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql> EXPLAIN SELECT * FROM a LEFT JOIN b USING (i) WHERE a.i < 2;
+----+-------------+-------+-------+---------------+------+---------+----------+------+-------------+
| id | select_type | TABLE | TYPE | possible_keys | KEY | key_len | REF | ROWS | Extra |
+----+-------------+-------+-------+---------------+------+---------+----------+------+-------------+
| 1 | SIMPLE | a | range | i | i | 5 | NULL | 1 | USING WHERE |
| 1 | SIMPLE | b | REF | i | i | 5 | test.a.i | 2 | |
+----+-------------+-------+-------+---------------+------+---------+----------+------+-------------+
2 ROWS IN SET (0.02 sec)

Optimiser le serveur MySQL


Variables de status et serveur

MySQL peut être monitoré et personnalisé en surveillant les variables de status, et définissant les variables
de serveur qui peuvent être globales ou par session.

Les variables de status peuvent être monitorées par SHOW [GLOBAL|SESSION] STATUS [LIKE '%foo%']
ou mysqladmin [extended-]status.

Les variables de serveur peuvent être définies dans /etc/mysql/my.cnf ou via SET [GLOBAL|SESSION]
VARIABLE foo := bar, et affichées avec mysqladmin variables ou SHOW [GLOBAL|SESSION] VARIABLES
[LIKE '%foo%'].

Généralement, les variables de status commencent par une majuscule, et pas les variables de serveur.

Pour gérer les quotas de ces variables, il faut les multiplier par la valeur de max_connections pour avoir une
estimation de la mémoire maximum utilisée. Cela permettra d'éviter des crashs lors des pics de connexions.
Exemple :

min_memory_needed = global_buffers + (thread_buffers * max_connections)

global_buffers:
key_buffer
innodb_buffer_pool
innodb_log_buffer
innodb_additional_mem_pool
net_buffer

thread_buffers:
sort_buffer
myisam_sort_buffer
read_buffer
join_buffer
read_rnd_buffer

Index

Les index permettent de situer les données ou plages de données plus rapidement.

Expérience

Remarque : Lors des tests, désactiver le cache (query_cache_type=0 dans my.cnf) pour forcer un
recalcul systématique des requêtes.

Lançons le programme Perl suivant :

#!/usr/bin/perl

use strict;
print "DROP TABLE IF EXISTS weightin;\n";
print "CREATE TABLE weightin (
id INT PRIMARY KEY auto_increment,
line TINYINT,
date DATETIME,
weight FLOAT(8,3)
);\n";

# 2 millions records, interval = 100s


for (my $timestamp = 1000000000; $timestamp < 1200000000; $timestamp += 100) {
my $date = int($timestamp + rand(1000) - 500);
my $weight = rand(1000);
my $line = int(rand(3)) + 1;
print "INSERT INTO weightin (date, line, weight) VALUES (FROM_UNIXTIME($date), $line, $weight);\n";
}

Rôle

Simule une entrée de données en quantité industrielle à intervalle régulier.

Utilisation

mysql> CREATE DATABASE industrial


$ perl generate_huge_db.pl | mysql industrial
REAL 6m21.042s
USER 0m37.282s
sys 0m51.467s

Pour vérifier le nombre d'éléments :

mysql> SELECT COUNT(*) FROM weightin;


+----------+
| COUNT(*) |
+----------+
| 2000000 |
+----------+
1 ROW IN SET (0.00 sec)

La taille doit être importante :

$ perl generate_huge_db.pl > import.sql


$ ls -lh import.sql
-rw-r--r-- 1 root root 189M jun 15 22:08 import.sql

$ ls -lh /var/lib/mysql/industrial/weightin.MYD
-rw-rw---- 1 mysql mysql 35M jun 15 22:17 /var/lib/mysql/industrial/weightin.MYD

$ time mysqldump industrial > dump.sql


real 0m9.599s
user 0m3.792s
sys 0m0.616s
$ ls -lh dump.sql
-rw-r--r-- 1 root root 79M jun 15 22:18 dump.sql

$ time mysqldump industrial | gzip > dump.sql.gz


real 0m17.339s
user 0m11.897s
sys 0m0.488s
$ ls -lh dump.sql.gz
-rw-r--r-- 1 root root 22M jun 15 22:19 dump.sql.gz
Incidemment, restaurer d'un dump est plus rapide car il y a moins d'insertions :

# time zcat dump.sql.gz | mysql industrial


real 0m31.772s
user 0m3.436s
sys 0m0.580s

La commande SQL scanne tous les enregistrements pour obtenir une somme :

mysql> SELECT SUM(*) FROM weightin;

Par exemple, pour compter le matériel depuis le premier janvier 2008 :

mysql> SELECT COUNT(*), SUM(poids) FROM pesee WHERE date >= '2008-01-01' AND date < '2008-01-02';

MySQL a besoin de lire toute la base même pour un petit nombre d'enregistrement, car rien ne garantit qu'ils
soient classés. Pour améliorer ceci, on peut faire de la date un index. MySQL va donc créer une nouvelle
table cachée avec les dates classées dans l'ordre, et stocker leur position dans la table 'weightin' afin de
pouvoir faire le lien avec. Comme l'index est ordonné, MySQL peut plus rapidement localiser un
enregistrement (ex : par dichotomie) plutôt que lors d'une lecture séquentielle.

Ajout de l'index :

ALTER TABLE weightin ADD INDEX (date);

On remarque que le fichier .MYD a grossi :

$ ls -lh /var/lib/mysql/industrial/
-rw-rw---- 1 mysql mysql 49M jun 15 22:36 weightin.MYI

C'est parce qu'il est utilisé pour stocker les index, par défaut toutes les clés primaires.

Autre exemple

Tentons d'optimiser la requête :

mysql> SELECT DISTINCT line FROM weightin;


Il suffit de faire de 'line' un index, afin qu'il puisse éviter les doublons regroupés ensemble, au lieu de
rescanner toute la table pour les localiser :

ALTER TABLE weightin ADD INDEX (line);

Taille du fichier :

-rw-rw---- 1 mysql mysql 65M jun 15 22:38 weightin.MYI

Considérations générales

La première question pour optimiser les sélections est toujours de savoir si les index sont configurés, et si
oui s'ils sont utilisés.

1. Vérifier si les index sont utilisés

Les requêtes individuelles peuvent être détaillées par EXPLAIN. Pour tout le serveur les variables "Sort_%"
peuvent être surveillés pour indiquer combien de fois MySQL doit aller les chercher dans le fichier de
données en l'absence d'index.

2. Est-ce que les index sont stockés dans un tampon

Garder les index en mémoire vive augmente les performances de lecture. Le quotient des clés lues sur les
requêtes de lecture de clés reflète les réels accès de MySQL au fichier d'index sur le disque quand il
nécessitait une clé.

Idem avec les clés écrites, utiliser mysqlreport pour faire le calcul. Si le pourcentage est trop haut,
key_buffer_size pour MyISAM et innodb_buffer_pool_size pour InnoDB sont les variables à régler.

Les variables Key_blocks_% peuvent être utilisées pour voir combien les clés tampons sont réellement
utilisées. Une unité correspond à 1 ko, sauf si key_cache_block_size a été modifié. Comme MySQL utilise
les blocs internes, key_blocks_unused doit être vérifié. Pour estimer la taille du tampon à définir, celle des
fichiers .MYI doit être vérifiée. Pour InnoDB il y a innodb_buffer_pool_size qui concerne tous les types de
données en tampon (pas seulement les index).

3. Configuration avancée

sort_buffer_size (par thread) est la mémoire utilisée pour ORDER BY et GROUP BY. Il set déconseillé par contre
d'utiliser myisam_sort_buffer_size.

read_buffer_size (par thread) est la taille de mémoire allouée pour les scans complets de table (comme les
tables volumineuses ne tiennent pas complètement en mémoire).

Query cache

La principale raison de ne pas rétrograder vers des versions antérieures à MySQL 4.0.1, est la faculté de
stocker les requêtes SELECT jusqu'à ce que les tables soient modifiées.
Le Query Cache peut être configuré au travers des variables query_cache_%. La plus importante est la
globale query_cache_size et query_cache_limit qui préviennent les requêtes uniques à résultats
anormalement plus larges que la taille du cache.

Les blocs Query Cache ont une taille variable dont le minimum est définit par query_cache_min_res_unit,
donc après reset du cache le nombre de bloc libre doit être idéalement de un. Une large valeur de
Qcache_free_blocks engendrerait de la fragmentation.

Voir aussi les variables :

Qcache_free_blocks : si la valeur est haute, cela indique une forte fragmentation.


Qcache_not_cached : si la valeur est haute, il y a soit plus de requête hors du cache (par exemple parce
qu'ils utilisent des fonctions comme now()) soit la valeur de query_cache_limit est trop basse.
Qcache_lowmem_prunes : montant des anciens résultats purgés car le cache était plein, et les tables
modifiées. query_cache_size doit être augmenté pour abaisser cette variable.

Exemple d'un cache vide :

mysql> SHOW VARIABLES LIKE 'query_cache_type';


+------------------+-------+
| Variable_name | VALUE |
+------------------+-------+
| query_cache_type | ON |
+------------------+-------+
1 ROW IN SET (0.00 sec)

mysql> SHOW VARIABLES LIKE 'query_cache_size';


+------------------+-------+
| Variable_name | VALUE |
+------------------+-------+
| query_cache_size | 0 |
+------------------+-------+
1 ROW IN SET (0.00 sec)

mysql> SHOW STATUS LIKE 'Qcache%';


+-------------------------+-------+
| Variable_name | VALUE |
+-------------------------+-------+
| Qcache_free_blocks | 0 |
| Qcache_free_memory | 0 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 0 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 0 |
+-------------------------+-------+
8 ROWS IN SET (0.00 sec)

Cache utilisé (savannah.gnu.org) :

mysql> SHOW VARIABLES LIKE "query_cache_size";


+------------------+----------+
| Variable_name | VALUE |
+------------------+----------+
| query_cache_size | 33554432 |
+------------------+----------+
1 ROW IN SET (0.00 sec)

mysql> SHOW STATUS LIKE "Qcache%";


+-------------------------+----------+
| Variable_name | VALUE |
+-------------------------+----------+
| Qcache_free_blocks | 1409 |
| Qcache_free_memory | 27629552 |
| Qcache_hits | 7925191 |
| Qcache_inserts | 3400435 |
| Qcache_lowmem_prunes | 2946778 |
| Qcache_not_cached | 71255 |
| Qcache_queries_in_cache | 4546 |
| Qcache_total_blocks | 10575 |
+-------------------------+----------+
8 ROWS IN SET (0.00 sec)

Le paramètre de my.cnf correspondant est :

query_cache_size = 32M

Pour nettoyer le cache afin d'améliorer les performances :

mysql> RESET QUERY CACHE;


Query OK, 0 ROWS affected (0.00 sec)

Attendre les locks

Les variables Table_locks_% affichent le nombre de requêtes en attente faute de pouvoir accéder aux tables
actuellement verrouillées par d'autres requêtes. Ces situations peuvent être causées par la commande LOCK
TABLE ou encore par plusieurs accès en écriture simultanés sur la même table.

Cache des tables

MySQL a besoin d'un certain temps pour ouvrir une table et lire ses métadonnées comme les noms de
colonnes.

Si plusieurs threads tentent d'accéder à la même table, elle est ouverte plusieurs fois.

Pour accélérer ceci la métadonnée peut être stockée dans le table_cache.

Une bonne valeur est le nombre max_connections multiplié par le nombre de tables moyen par sélection.

Utiliser mysqlreport ou regarder les Open_tables après que les Opened_tables ou le Uptime nombre de
tables ouvertes par seconde peut être calculé (hors des heures de pointe comme la nuit).

Connexions et threads

Pour chaque connexion de client, MySQL crée un thread séparé sous le processus principal mysqld. Pour les
grands sites à plusieurs centaines de connexions par semaine, créer les threads eux-mêmes peut consommer
un temps non négligeable. Pour l'accélérer, les threads en attente sont mis en cache après déconnexion de
leur client. En règle générale, moins d'un thread par seconde peut être créé ensuite.

Les clients qui envoient plusieurs requêtes au serveur doit utiliser les connexions persistantes comme avec la
fonction PHP mysql_pconnect().

Ce cache peut être configuré par thread_cache_size et monitoré avec les variables threads_%.
Pour éviter les surcharges MySQL bloque les nouvelles connexions si plus que max_connections sont
utilisé à cet instant. Commencer par max_used_connections et surveiller le nombre de connexion rejetées
(Aborted_clients) et celle time out (Aborted_connections).

Ne pas déconnecter les clients aux connexions persistantes peut rapidement provoquer un déni de service.
Les connexions normales sont fermées après le wait_timeout d'inactivité en seconde.

Tables temporaires

Il est parfaitement normal que MySQL crée des tables temporaires pendant les classements ou les résultats
de regroupement. Ces tables sont soit en mémoire, soit trop larges et sont écrites sur le disque (plus lent).

Le nombre de tables sur le disque (variables Created_tmp_%) doit être négligeable ou la configuration de
max_heap_table_size et tmp_table_size doit être reconsidérée.

Écritures différées

Pour rédiger les logs d'accès au serveur web dans une base, avec de nombreux INSERT subséquents dans la
même table, les performances peuvent être améliorées en conseillant au serveur de mettre en cache les
requêtes d'écriture un court moment, puis de tout envoyer comme batch sur le disque.

Attention au fait que toutes les méthodes mentionnées ne contreviennent pas à la recommandation ACID car
les insertions sont reconnus avec OK au client avant leur écriture définitive sur le disque, et donc des
données pourraient être perdues en cas de crash.

Pour les tables MyISAM, les écritures différées peuvent être définies avec DELAY_KEY_WRITE dans
un CREATE ou un ALTER TABLE. L'inconvénient est qu'après un crash la table est automatiquement marquée
comme corrompue et doit être vérifiée voire réparée ce qui prend un certain temps.
Pour InnoDB, c'est innodb_flush_log_at_trx_commit. En cas de crash seuls les index sont reconstruits.

INSERT DELAYED fonctionne sur les principaux moteurs de stockage.

Liens externes
(en) MySQL Optimization (http://investigacionit.com.ar/optimizacion-de-bases-de-datos-mysql/) [archive]
(en) A guide to mysqlreport (http://hackmysql.com/mysqlreportguide) [archive]
(en) The book High Performance MySQL (http://www.amazon.com/High-Performance-MySQL-Jeremy-
Zawodny/dp/0596003064/) [archive]
(en) Tuning tips from the company EZ (http://ez.no/community/articles
/tuning_mysql_for_ez_publish) [archive]
(en) MySysop A php script for mysql optimisation and tuning, demo : MySysop (http://www.fillon.org
/mysysop) [archive]
Voir aussi les newsgroups et mailing lists MySQL

Sécurité
Sur Internet de nombreuses personnes tentent de récupérer des données en violant leurs accès.

Paramètres de connexion

Parfois, les paramètres de connexion (dont login et mot de passe) sont stockés dans un fichier texte non
crypté, comme un .ini. Cela n'est donc pas recommandé : si un utilisateur devine son nom il peut le lire sans
peine. S'il est situé en dehors du répertoire WWW c'est mieux, mais la meilleure façon est de les enregistrer
dans un programme (ex : .php).

Il est toujours possible pour un utilisateur de trouver les accès FTP, donc il vaut mieux en utiliser d'autres
pour MySQL.

Inutile de se souvenir des mots de passe MySQL car le programme est sensé le retrouver automatiquement.
Il convient donc d'en choisir un robuste : très long, avec au moins une majuscule, une minuscule, un
symbole (ex : '_') et un chiffre. Le tout sans contenir de mots du dictionnaire car ils sont utilisés pour
accélérer les crackages lors d'attaque par force brute.

SQL Injections

Définition

Normalement les valeurs stockées dans $_POST peuvent être insérées directement dans des requêtes SQL.
Toutefois les injections SQL exploitent une faille de sécurité engendrée par le caractère d’échappement.

Exemple

Si on s'attend à recevoir un nombre (ex : 42), et qu'en fait $_POST contient une chaine avec échappement
("'42' OR 1") cela change complètement son résultat :

DELETE FROM `articles` WHERE `id`=42 -- supprime une ligne


DELETE FROM `articles` WHERE `id`=42 OR 1 -- supprime toutes les lignes (car 1 est toujours vrai)

L'utilisateur peut aussi insérer des commandes plus complexes séparées par des points-virgules :

SELECT * FROM `table1` WHERE title='bla bla' -- sélectionne


SELECT * FROM `table1` WHERE title='bla bla'; TRUNCATE TABLE `table1` -- supprime tout

Par ailleurs, si un utilisateur découvre comment manipuler une base de cette façon, il peut très bien se créer
un compte administrateur ensuite, et effectuer des modifications discrètes dans le but de récupérer de l'argent
(fausses factures, phishing...).

Solution

Il faut vérifier que la variable stocke bien le type de données prévu :

Pour les chaines de caractères : comme elles sont entourées d'apostrophes, tous ceux qu'elles contiennent
doivent être convertis (ex : en '' ou \'). Par exemple, PHP propose mysql_real_escape_string pour gérer
ces substitutions.
Pour les dates : les entourer d'apostrophes comme les chaines.
Pour les noms SQL (tables, champs...) : les entourer d'apostrophes comme les chaines.
Pour les nombres : s'ils contiennent autre chose que des chiffres, ils ne conviennent pas.
NULL / UNKNOWN / TRUE / FALSE : ne doivent jamais être rentrées par l'utilisateur.

Par ailleurs, aucun commentaire SQL ne devrait pourvoir être inséré par l'utilisateur.
Mots de passe

Généralement ils sont cryptés puis dans la base par les applications. Par contre si c'est fait en SQL, c'est
qu'ils ont été écrits au moins une fois en clair et donc étés visibles :

Dans les logs du serveur.


Dans les logs MySQL.
Dans SHOW PROCESSLIST.

Il est donc fortement déconseillé d'envoyer ce genre de commandes :

SELECT 1 FROM `users` WHERE `password`=MD5('abraxas')

Préférer depuis un .php par exemple :

$sql = "SELECT 1 FROM `users` WHERE `password`=MD5('".md5('abraxas')."')";

Ne jamais utiliser de fonctions de cryptage non sécurisées, comme PASSWORD().


Ni de cryptage réversible (se contenter de comparer si un chaine cryptée est égale à une autre chaine
cryptée comme authentification). Ou bien les mots de passe stockées dans une base doivent être
impossibles à sélectionner (avec SELECT).
Seulement du hachage cryptographique, comme SHA256, pas d'algorithmes plus vieux comme MD5.

SSL

Si le contenu de la base est publique, il n'y a pas de raison de crypter les communications.

Toutefois il peut y avoir un accès restreint pour les droits d'écriture, ce qui nécessite des mots de passe.

Le cryptage SSL s'avère une bonne solution pour cela. En effet, en plus de crypter les messages, il certifie
que l'utilisateur est bien celui qui était prévu (même si ce dernier a donné son mot de passe par phishing).

Optimisation
Appels API

Connexions persistantes

En utilisant les connexions persistantes, plusieurs requêtes peuvent être exécutées sans reconnexion. C'est un
gain de temps pour l'utilisateur, mais le serveur doit y allouer une partie de sa RAM pendant tout ce temps,
ce qui peut le saturer, surtout quand tous ses sites le font.

Mémoire libre

Certaines requêtes enregistrent une ligne dans une variable. Cela peut donc avoir du sens de libérer cette
mémoire un peu avant la fin du script, plutôt qu'à la toute fin.
Recherche de ligne

La plupart des APIs proposent deux types de recherches de ligne : en tableau (associatif ou pas) ou en objet.

Assigner les lignes dans un objet est plus lent, alors que le tableau non associatif est le plus rapide (et c'est le
mieux si on ne prend qu'un seul champ par enregistrement).

API vs SQL

Généralement, les APIs ont des méthodes optimisées qui créent des commandes SQL et les envoient au
serveur MySQL.

Réduire les communications client/serveur

Certains scripts utilisent deux requêtes pour extraire une table pivot. Les communications client/serveur
étant toujours le facteur ralentissant des applications, il faut préférer une seule jointure à la place.
Si toutefois plusieurs requêtes s'avèrent nécessaires, utiliser les connexions persistantes.
Ne sélectionner que le minimum de champs (éviter *).
Éviter d'inclure dans les commandes SQL des caractères inutiles (espaces, tabs, commentaires...).

CREATE ... SELECT, INSERT ... SELECT

Lors de création de nouvelle table depuis une existante, CREATE ... SELECT peut être utilisé.

Pour remplir une table existante, c'est INSERT ... SELECT ou REPLACE ... SELECT.

INSERT DELAYED

Certains scripts n'ont pas besoin de vérifier si les insertions se sont bien déroulées.

Dans ce cas, faire appel à INSERT DELAYED pour que le serveur n'attende pas.

REPLACE

Lors d'un DELETE précédé d'un INSERT, le serveur reçoit deux commandes SQL.

En revanche, avec REPLACE il n'en reçoit qu'une.

De plus, REPLACE DELAYED est possible.

Autres techniques

Stocker les données dans des cookies

Parfois, des données de session sont stockées dans la base.

Cela nécessite un UPDATE et un SELECT à charge chargement de page.

Cela peut être évité avec les cookies (même si l'utilisateur peut refuser leur utilisation, ou bien lire leur
contenu). Il faut éviter d'y stocker des mots de passe et leur attribuer un bref temps de vie sous peine de
compromettre la vie privée de l'utilisateur.
Autre solution :

Une fois l'utilisateur loggué sur le site, lancer CURRENT_TIMESTAMP() et un ID au hasard ;


Définir un cookie avec cet ID ;
Quand l'utilisateur fait quelque chose qui nécessite de vérifier son identification :

SELECT FROM `access` WHERE `id`=id_cookie AND `timestamp`>=CURRENT_TIMESTAMP() - login_lifetime

Mettre à jour le timestamp.

Créer du contenu statique

Quand un utilisateur lit du contenu dynamique (d'une base), un document HTML est généré.

Souvent, cette page ne contient pas de variable mais du contenu inséré une seule fois, sans mise à jour.

D'où l'idée de stocker des pages HTML statiques, supprimée puis regénérées lors des mises à jour de la base.

PHP
Pilotes

PHP possède les pilotes officiels suivant pour MySQL :

mysql : ancien mais toujours utilisé dans les applications web ; c'est un module PHP procédural.
mysqli : plus rapide, peut être utilisé comme un ensemble de classes ou comme une bibliothèque
procédurale.
PDO (PHP Data Objects) : utilise PDO, une couche abstraite pour interaction avec les bases, avec des
pilotes pour MySQL et ODBC.
PDO_MYSQL : propose des fonctionnalités MySQL avancées, et les émulent si absentes.

Les fonctions de ces pilotes utilisent l'API C. Elles peuvent utiliser MySQL Client Library ou mysqlnd,
comme pilotes natifs pour PHP.

Parfois, activer mysql et mysqli peut causer des problèmes. Il est donc préférable d'en activer qu'un.

De plus, PHP possède une extension ODBC qui fonctionne avec MySQL.

PEAR est un framework PHP important qui prend en charge MySQL.

register_globals et $_REQUEST

PHP a des variables d'environnement appelées register_globals. Depuis PHP 4.2, elles sont False par
défaut, et ne doivent pas être activées. Dans PHP 5.3, cette variable est également désuète, et dans PHP 6
retirée.

Cependant, si la version de PHP utilisée accepte register_globals, on peut vérifier s'il est activé lancer
ini_get(). Si c'est le cas, ini_set() ne pourra pas le changer. Il y a deux façons de le faire :

Éditer php.ini.
Ajouter une ligne au .htaccess :

php_flag register_globals off

En fait si register_globals est True, un utilisateur peut arbitrairement ajouter des variables à votre script avec
ce genre de commande :

your_script.php?new_variable=new_value

Ne jamais utiliser le tableau $_REQUEST, lui préférer :

$_ENV
$_GET
$_POST
$_COOKIE
$_SERVER

Cet ordre est celui suivi par PHP, mais il peut être modifié par variables_order.

Cela signifie que si votre script définit une variable serveur appelée "userid" et que l'application tente de la
lire dans $_REQUEST, l'utilisateur peut prévenir en ajoutant une variable à la requête.

Cet aide-mémoire pour MySQL recense les commandes usuelles.

Visualisation

SELECT * FROM TABLE


SELECT * FROM table1, table2, ...
SELECT champ1, champ2, ... FROM table1, table2, ...
SELECT ... FROM ... WHERE condition
SELECT ... FROM ... WHERE condition GROUPBY champ
SELECT ... FROM ... WHERE condition GROUPBY champ HAVING condition2
SELECT ... FROM ... WHERE condition ORDER BY champ1, champ2
SELECT ... FROM ... WHERE condition ORDER BY champ1, champ2 DESC
SELECT ... FROM ... WHERE condition LIMIT 10
SELECT DISTINCT champ1 FROM ...
SELECT DISTINCT champ1, champ2 FROM ...

Jointures

SELECT ... FROM t1 JOIN t2 ON t1.id1 = t2.id2 WHERE condition


SELECT ... FROM t1, t2 WHERE t1.id1 = t2.id2 AND condition
SELECT ... FROM t1 INNER JOIN t2 ON (t1.id1 = t2.id2) WHERE condition
SELECT ... FROM t1 NATURAL JOIN t2 WHERE condition
SELECT ... FROM t1 LEFT JOIN t2 ON t1.id1 = t2.id2 WHERE condition
SELECT ... FROM t1 JOIN (t2 JOIN t3 ON ...) ON ...

Conditions
champ1 = valeur1
champ1 <> valeur1
champ1 LIKE 'valeur _ %'
champ1 IS NULL
champ1 IS NOT NULL
champ1 IS IN (valeur1, valeur2)
champ1 IS NOT IN (valeur1, valeur2)
champ1 BETWEEN valeur1 AND valeur2
condition1 AND condition2
condition1 OR condition2

Modification du contenu

INSERT INTO table1 (champ1, champ2, ...) VALUES (valeur1, valeur2, ...)

DELETE FROM table1 / TRUNCATE table1


DELETE FROM table1 WHERE condition
-- jointure:
DELETE FROM table1, table2 WHERE table1.id1 = table2.id2 AND condition

UPDATE table1 SET champ1=nouvelle_valeur1 WHERE condition


-- jointure:
UPDATE table1, table2 SET champ1=nouvelle_valeur1, champ2=nouvelle_valeur2, ... WHERE table1.id1 = table2

Naviguer dans MySQL

SHOW DATABASES
SHOW TABLES
SHOW FIELDS FROM TABLE / DESCRIBE TABLE
SHOW CREATE TABLE TABLE
SHOW PROCESSLIST
KILL numero
USE ma_bdd

Créer / supprimer une base

CREATE DATABASE mabase


CREATE DATABASE mabase CHARACTER SET utf8
DROP DATABASE mabase

ALTER DATABASE mabase CHARACTER SET utf8

Créer/supprimer/modifier une table

CREATE TABLE TABLE (champ1 type1, champ2 type2, ...)


CREATE TABLE TABLE (champ1 type1, champ2 type2, ..., INDEX (champ))
CREATE TABLE TABLE (champ1 type1, champ2 type2, ..., PRIMARY KEY (champ1))
CREATE TABLE TABLE (champ1 type1, champ2 type2, ..., PRIMARY KEY (champ1, champ2))
CREATE TABLE table1 (fk_champ1 type1, champ2 type2, ...,
FOREIGN KEY (fk_champ1) REFERENCES table2 (t2_champA))
[ON UPDATE|ON DELETE] [CASCADE|SET NULL]
CREATE TABLE table1 (fk_champ1 type1, fk_champ2 type2, ...,
FOREIGN KEY (fk_champ1, fk_champ2) REFERENCES table2 (t2_champA, t2_champB))
CREATE TABLE TABLE IF NOT EXISTS (...)
CREATE TABLE TABLE (champ1 type1, champ2 type2, ...) SELECT ...

CREATE TEMPORARY TABLE TABLE (...)

DROP TABLE TABLE


DROP TABLE IF EXISTS TABLE
DROP TABLE table1, table2, ...

ALTER TABLE TABLE ADD (champ1 type1, champ2 type2, ...)


ALTER TABLE TABLE MODIFY champ1 type1
ALTER TABLE TABLE MODIFY champ1 type1 NOT NULL ...
ALTER TABLE TABLE CHANGE ancien_nom_champ1 nouveau_nom_champ1 type1
ALTER TABLE TABLE CHANGE ancien_nom_champ1 nouveau_nom_champ1 type1 NOT NULL ...
ALTER TABLE TABLE ALTER champ1 SET DEFAULT ...
ALTER TABLE TABLE ALTER champ1 DROP DEFAULT
ALTER TABLE TABLE ADD INDEX (champ);

ALTER TABLE ancien_nom RENAME nouveau_nom;

Clés primaires et étrangères

CREATE TABLE TABLE (..., PRIMARY KEY (champ1, champ2))


CREATE TABLE TABLE (..., FOREIGN KEY (champ1, champ2) REFERENCES table2 (t2_champ1, t2_champ2))

Créer/supprimer une vue

CREATE VIEW nomvue AS SELECT champ1, champ2 FROM table1 -- ou


CREATE VIEW nomvue (champ1, champ2...) AS SELECT champ1, champ2 FROM table1

ALTER VIEW nomvue (champ1, champ2...) AS SELECT champ2 FROM table1;


DROP VIEW nomvue;

Permissions

GRANT ALL PRIVILEGES ON base.* TO 'utilisateur'@'localhost' IDENTIFIED BY 'password';


GRANT SELECT, INSERT, DELETE ON base.* TO 'utilisateur'@'localhost' IDENTIFIED BY 'password';
REVOKE ALL PRIVILEGES ON base.* FROM 'utilisateur'@'hote'; -- une seule permission
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'utilisateur'@'hote'; -- toutes les permissions

SET PASSWORD = PASSWORD('nouveau_pass')


SET PASSWORD FOR 'utilisateur'@'hote' = PASSWORD('nouveau_pass')
SET PASSWORD = OLD_PASSWORD('nouveau_pass')

DROP USER 'utilisateur'@'hote'

Types de données principaux


TINYINT (1o: -127+128)
SMALLINT (2o: +-65 000)
MEDIUMINT (3o: +-16 000 000) INT (4o: +- 2 000 000 000)
BIGINT (8o: +- 9 trillions)
Intervalle précis: -(2^(8*N-1)) -> (2^8*N)-1
/!\ INT(2) = "2 chiffres affichés" -- ET NON PAS "nombre à 2 chiffres"

FLOAT(M,D) DOUBLE(M,D) FLOAT(D=0->53)


/!\ 8,3 -> 12345,678 -- PAS 12345678,123!

TIME (HH:MM)
YEAR (AAAA)
DATE (AAAA-MM-JJ)
DATETIME (AAAA-MM-JJ HH:MM; années 1000->9999)
TIMESTAMP (comme DATE, mais 1970->2038, compatible Unix)

VARCHAR(ligne)
TEXT (multi-lignes; taille MAX=65535)
BLOB (binaire; taille MAX=65535)

Variantes:
TINY (MAX=255)
MEDIUM (MAX=~16000)
LONG (MAX=4Go)
Ex: TINYTEXT, LONGBLOB, MEDIUMTEXT

ENUM ('valeur1', 'valeur2', ...) -- (default NULL, ou '' si NOT NULL)

Oubli de mot de passe oublié

$ service mysql stop


$ mysqld_safe --skip-grant-tables
> UPDATE mysql.user SET password=PASSWORD('nouveau') WHERE user='root';
## Tuer mysqld_safe, avec Control + \
$ service mysql start

Réparer les tables après un arrêt soudain

mysqlcheck --all-databases
mysqlcheck --all-databases --fast

Relancer la synchronisation de la base du serveur secondaire

$ mysql
mysql> slave start;
mysql> show slave status\G

Manipuler des variables


Les définitions sont effectuées à l'aide des mots clés "select" (suivi de ":=") ou "set" (avec "=") :

SELECT @test := 2;
SELECT @test + 1

SET @date1='date une', @date1='date deux'

Pour les afficher ensuite :

SHOW VARIABLES LIKE 'test';


SHOW VARIABLES LIKE 'date1';
SHOW VARIABLES LIKE 'date2';

Certaines variables globales représentent la configuration du système, et peuvent être changées


provisoirement le temps d'une session, ou de façon permanente :

mysql> SET @@global.max_connections = 1000;


mysql> SHOW global VARIABLES LIKE 'wait_timeout';
+---------------+-------+
| Variable_name | VALUE |
+---------------+-------+
| wait_timeout | 60 |
+---------------+-------+
1 ROW IN SET (0.00 sec)
mysql> SET @@SESSION.wait_timeout=120;

Langage
Liste des mots réservés MySQL :

ACCESSIBLE
ADD
ALL
ALTER
ANALYZE
AND
AS
ASC
ASENSITIVE
AUTO_INCREMENT
BDB
BEFORE
BERKELEYDB
BETWEEN
BIGINT
BINARY
BLOB
BOTH
BY
CALL
CASCADE
CASE
CHANGE
CHAR
CHARACTER
CHECK
COLLATE
COLUMN
COLUMNS
CONDITION
CONNECTION
CONSTRAINT
CONTINUE
CONVERT
CREATE
CROSS
CURRENT_DATE
CURRENT_TIME
CURRENT_TIMESTAMP
CURRENT_USER
CURSOR
DATABASE
DATABASES
DAY_HOUR
DAY_MICROSECOND
DAY_MINUTE
DAY_SECOND
DEC
DECIMAL
DECLARE
DEFAULT
DELAYED
DELETE
DESC
DESCRIBE
DETERMINISTIC
DISTINCT
DISTINCTROW
DIV
DOUBLE
DROP
DUAL
EACH
ELSE
ELSEIF
ENCLOSED
ESCAPED
EXISTS
EXIT
EXPLAIN
FALSE
FETCH
FIELDS
FLOAT
FLOAT4
FLOAT8
FOR
FORCE
FOREIGN
FOUND
FRAC_SECOND
FROM
FULLTEXT
GENERAL
GRANT
GROUP
HAVING
HIGH_PRIORITY
HOUR_MICROSECOND
HOUR_MINUTE
HOUR_SECOND
IF
IGNORE
IGNORE_SERVER_IDS
IN
INDEX
INFILE
INNER
INNODB
INOUT
INSENSITIVE
INSERT
INT
INT1
INT2
INT3
INT4
INT8
INTEGER
INTERVAL
INTO
IO_THREAD
IS
ITERATE
JOIN
KEY
KEYS
KILL
LEADING
LEAVE
LEFT
LIKE
LIMIT
LINEAR
LINES
LOAD
LOCALTIME
LOCALTIMESTAMP
LOCK
LONG
LONGBLOB
LONGTEXT
LOOP
LOW_PRIORITY
MASTER_HEARTBEAT_PERIOD
MASTER_SERVER_ID
MASTER_SSL_VERIFY_SERVER_CERT
MATCH
MAXVALUE
MEDIUMBLOB
MEDIUMINT
MEDIUMTEXT
MIDDLEINT
MINUTE_MICROSECOND
MINUTE_SECOND
MOD
MODIFIES
MySQL
NATURAL
NOT
NO_WRITE_TO_BINLOG
NULL
NUMERIC
ON
OPTIMIZE
OPTION
OPTIONALLY
OR
ORDER
OUT
OUTER
OUTFILE
PRECISION
PRIMARY
PRIVILEGES
PROCEDURE
PURGE
RANGE
READ
READS
READ_WRITE
REAL
REFERENCES
REGEXP
RELEASE
RENAME
REPEAT
REPLACE
REQUIRE
RESIGNAL
RESTRICT
RETURN
REVOKE
RIGHT
RLIKE
SCHEMA
SCHEMAS
SECOND_MICROSECOND
SELECT
SENSITIVE
SEPARATOR
SET
SHOW
SIGNAL
SLOW
SMALLINT
SOME
SONAME
SPATIAL
SPECIFIC
SQL
SQLEXCEPTION
SQLSTATE
SQLWARNING
SQL_BIG_RESULT
SQL_CALC_FOUND_ROWS
SQL_SMALL_RESULT
SQL_TSI_DAY
SQL_TSI_FRAC_SECOND
SQL_TSI_HOUR
SQL_TSI_MINUTE
SQL_TSI_MONTH
SQL_TSI_QUARTER
SQL_TSI_SECOND
SQL_TSI_WEEK
SQL_TSI_YEAR
SSL
STARTING
STRAIGHT_JOIN
STRIPED
TABLE
TABLES
TERMINATED
THEN
TIMESTAMPADD
TIMESTAMPDIFF
TINYBLOB
TINYINT
TINYTEXT
TO
TRAILING
TRIGGER
TRUE
The
UNDO
UNION
UNIQUE
UNLOCK
UNSIGNED
UPDATE
USAGE
USE
USER_RESOURCES
USING
UTC_DATE
UTC_TIME
UTC_TIMESTAMP
VALUES
VARBINARY
VARCHAR
VARCHARACTER
VARYING
WHEN
WHERE
WHILE
WITH
WRITE
XOR
YEAR_MONTH
ZEROFILL

Logiciel
En Unix, ce service se lance avec la commande "$ mysql ".

Voici le résultat de la première commande avec MySQL5.4.3 :


mysql> ?

For information about MySQL products and services, visit:


http://www.mysql.com/
For developer information, including the MySQL Reference Manual, visit:
http://dev.mysql.com/
To buy MySQL Network Support, training, or other products, visit:
https://shop.mysql.com/

List of all MySQL commands:


Note that all text commands must be first on line and end with ';'
? (\?) Synonym for `help'.
clear (\c) Clear the current input statement.
connect (\r) Reconnect to the server. Optional arguments are db and
host.
delimiter (\d) Set statement delimiter.
ego (\G) Send command to mysql server, display result vertically.
exit (\q) Exit mysql. Same as quit.
go (\g) Send command to mysql server.
help (\h) Display this help.
notee (\t) Don't write into outfile.
print (\p) Print current command.
prompt (\R) Change your mysql prompt.
quit (\q) Quit mysql.
rehash (\#) Rebuild completion hash.
source (\.) Execute an SQL script file. Takes a file name as an
argument.
status (\s) Get status information from the server.
tee (\T) Set outfile [to_outfile]. Append everything into given
outfile.
use (\u) Use another database. Takes database name as argument.
charset (\C) Switch to another charset. Might be needed for
processing binlog
with multi-byte charsets.
warnings (\W) Show warnings after every statement.
nowarning (\w) Don't show warnings after every statement.

For server side help, type 'help contents'

mysql>

Il en existe aussi d'autres :

describe Describe the table in argument.


substring (or substr) Convert a data type to another in the result.
trim Suppress the prefixes and suffixes of a string of characters.
alter table
...

Références
http://dev.mysql.com/doc/refman/5.5/en/reserved-words.html
http://www.htmlite.com/mysql002a.php

Licence de documentation libre GNU


Résumé
La licence de documentation libre GNU (GNU Free Documentation License) est une licence produite par
la Free Software Foundation. Cette licence a pour but de permettre la diffusion de contenu libre.

L'objet de cette Licence est de rendre tout manuel, livre ou autre document écrit « libre » au sens de la
liberté d'utilisation, à savoir : assurer à chacun la liberté effective de le copier ou de le redistribuer, avec ou
sans modifications, commercialement ou non.

Attention, contenu libre ne veut pas dire domaine public. Les différents créateurs de documents sous licence
GFDL restent propriétaire de leurs écrits ou de leurs images. La licence GNU requiert que les auteurs
gardent le crédit de leurs contributions. Pour cette raison, toute utilisation de document sous licence GFDL
doit mentionner la source de ce contenu (par exemple, soit en créditant l'organisation d'où origine le
document ou encore le document directement).

en français (traduction non officielle, version 1.1): http://cesarx.free.fr/gfdlf.html


version officielle en anglais: http://www.gnu.org/copyleft/fdl.html

Texte intégral

GNU Free Documentation License


Version 1.2, November 2002

Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.


51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other


functional and useful document "free" in the sense of freedom: to
assure everyone the effective freedom to copy and redistribute it,
with or without modifying it, either commercially or noncommercially.
Secondarily, this License preserves for the author and publisher a way
to get credit for their work, while not being considered responsible
for modifications made by others.

This License is a kind of "copyleft", which means that derivative


works of the document must themselves be free in the same sense. It
complements the GNU General Public License, which is a copyleft
license designed for free software.
We have designed this License in order to use it for manuals for free
software, because free software needs free documentation: a free
program should come with manuals providing the same freedoms that the
software does. But this License is not limited to software manuals;
it can be used for any textual work, regardless of subject matter or
whether it is published as a printed book. We recommend this License
principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that
contains a notice placed by the copyright holder saying it can be
distributed under the terms of this License. Such a notice grants a
world-wide, royalty-free license, unlimited in duration, to use that
work under the conditions stated herein. The "Document", below,
refers to any such manual or work. Any member of the public is a
licensee, and is addressed as "you". You accept the license if you
copy, modify or distribute the work in a way requiring permission
under copyright law.

A "Modified Version" of the Document means any work containing the


Document or a portion of it, either copied verbatim, or with
modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of


the Document that deals exclusively with the relationship of the
publishers or authors of the Document to the Document's overall subject
(or to related matters) and contains nothing that could fall directly
within that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not explain any
mathematics.) The relationship could be a matter of historical
connection with the subject or with related matters, or of legal,
commercial, philosophical, ethical or political position regarding
them.

The "Invariant Sections" are certain Secondary Sections whose titles


are designated, as being those of Invariant Sections, in the notice
that says that the Document is released under this License. If a
section does not fit the above definition of Secondary then it is not
allowed to be designated as Invariant. The Document may contain zero
Invariant Sections. If the Document does not identify any Invariant
Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed,
as Front-Cover Texts or Back-Cover Texts, in the notice that says that
the Document is released under this License. A Front-Cover Text may
be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy,


represented in a format whose specification is available to the
general public, that is suitable for revising the document
straightforwardly with generic text editors or (for images composed of
pixels) generic paint programs or (for drawings) some widely available
drawing editor, and that is suitable for input to text formatters or
for automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent file
format whose markup, or absence of markup, has been arranged to thwart
or discourage subsequent modification by readers is not Transparent.
An image format is not Transparent if used for any substantial amount
of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain


ASCII without markup, Texinfo input format, LaTeX input format, SGML
or XML using a publicly available DTD, and standard-conforming simple
HTML, PostScript or PDF designed for human modification. Examples of
transparent image formats include PNG, XCF and JPG. Opaque formats
include proprietary formats that can be read and edited only by
proprietary word processors, SGML or XML for which the DTD and/or
processing tools are not generally available, and the
machine-generated HTML, PostScript or PDF produced by some word
processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself,
plus such following pages as are needed to hold, legibly, the material
this License requires to appear in the title page. For works in
formats which do not have any title page as such, "Title Page" means
the text near the most prominent appearance of the work's title,
preceding the beginning of the body of the text.

A section "Entitled XYZ" means a named subunit of the Document whose


title either is precisely XYZ or contains XYZ in parentheses following
text that translates XYZ in another language. (Here XYZ stands for a
specific section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve the Title"
of such a section when you modify the Document means that it remains a
section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which
states that this License applies to the Document. These Warranty
Disclaimers are considered to be included by reference in this
License, but only as regards disclaiming warranties: any other
implication that these Warranty Disclaimers may have is void and has
no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either
commercially or noncommercially, provided that this License, the
copyright notices, and the license notice saying this License applies
to the Document are reproduced in all copies, and that you add no other
conditions whatsoever to those of this License. You may not use
technical measures to obstruct or control the reading or further
copying of the copies you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large enough
number of copies you must also follow the conditions in section 3.
You may also lend copies, under the same conditions stated above, and
you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have
printed covers) of the Document, numbering more than 100, and the
Document's license notice requires Cover Texts, you must enclose the
copies in covers that carry, clearly and legibly, all these Cover
Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
the back cover. Both covers must also clearly and legibly identify
you as the publisher of these copies. The front cover must present
the full title with all words of the title equally prominent and
visible. You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they preserve
the title of the Document and satisfy these conditions, can be treated
as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit
legibly, you should put the first ones listed (as many as fit
reasonably) on the actual cover, and continue the rest onto adjacent
pages.

If you publish or distribute Opaque copies of the Document numbering


more than 100, you must either include a machine-readable Transparent
copy along with each Opaque copy, or state in or with each Opaque copy
a computer-network location from which the general network-using
public has access to download using public-standard network protocols
a complete Transparent copy of the Document, free of added material.
If you use the latter option, you must take reasonably prudent steps,
when you begin distribution of Opaque copies in quantity, to ensure
that this Transparent copy will remain thus accessible at the stated
location until at least one year after the last time you distribute an
Opaque copy (directly or through your agents or retailers) of that
edition to the public.

It is requested, but not required, that you contact the authors of the
Document well before redistributing any large number of copies, to give
them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under
the conditions of sections 2 and 3 above, provided that you release
the Modified Version under precisely this License, with the Modified
Version filling the role of the Document, thus licensing distribution
and modification of the Modified Version to whoever possesses a copy
of it. In addition, you must do these things in the Modified Version:

A. Use in the Title Page (and on the covers, if any) a title distinct
from that of the Document, and from those of previous versions
(which should, if there were any, be listed in the History section
of the Document). You may use the same title as a previous version
if the original publisher of that version gives permission.
B. List on the Title Page, as authors, one or more persons or entities
responsible for authorship of the modifications in the Modified
Version, together with at least five of the principal authors of the
Document (all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher of the
Modified Version, as the publisher.
D. Preserve all the copyright notices of the Document.
E. Add an appropriate copyright notice for your modifications
adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a license notice
giving the public permission to use the Modified Version under the
terms of this License, in the form shown in the Addendum below.
G. Preserve in that license notice the full lists of Invariant Sections
and required Cover Texts given in the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its Title, and add
to it an item stating at least the title, year, new authors, and
publisher of the Modified Version as given on the Title Page. If
there is no section Entitled "History" in the Document, create one
stating the title, year, authors, and publisher of the Document as
given on its Title Page, then add an item describing the Modified
Version as stated in the previous sentence.
J. Preserve the network location, if any, given in the Document for
public access to a Transparent copy of the Document, and likewise
the network locations given in the Document for previous versions
it was based on. These may be placed in the "History" section.
You may omit a network location for a work that was published at
least four years before the Document itself, or if the original
publisher of the version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or "Dedications",
Preserve the Title of the section, and preserve in the section all
the substance and tone of each of the contributor acknowledgements
and/or dedications given therein.
L. Preserve all the Invariant Sections of the Document,
unaltered in their text and in their titles. Section numbers
or the equivalent are not considered part of the section titles.
M. Delete any section Entitled "Endorsements". Such a section
may not be included in the Modified Version.
N. Do not retitle any existing section to be Entitled "Endorsements"
or to conflict in title with any Invariant Section.
O. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or


appendices that qualify as Secondary Sections and contain no material
copied from the Document, you may at your option designate some or all
of these sections as invariant. To do this, add their titles to the
list of Invariant Sections in the Modified Version's license notice.
These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains


nothing but endorsements of your Modified Version by various
parties--for example, statements of peer review or that the text has
been approved by an organization as the authoritative definition of a
standard.

You may add a passage of up to five words as a Front-Cover Text, and a


passage of up to 25 words as a Back-Cover Text, to the end of the list
of Cover Texts in the Modified Version. Only one passage of
Front-Cover Text and one of Back-Cover Text may be added by (or
through arrangements made by) any one entity. If the Document already
includes a cover text for the same cover, previously added by you or
by arrangement made by the same entity you are acting on behalf of,
you may not add another; but you may replace the old one, on explicit
permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License


give permission to use their names for publicity for or to assert or
imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this
License, under the terms defined in section 4 above for modified
versions, provided that you include in the combination all of the
Invariant Sections of all of the original documents, unmodified, and
list them all as Invariant Sections of your combined work in its
license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and
multiple identical Invariant Sections may be replaced with a single
copy. If there are multiple Invariant Sections with the same name but
different contents, make the title of each such section unique by
adding at the end of it, in parentheses, the name of the original
author or publisher of that section if known, or else a unique number.
Make the same adjustment to the section titles in the list of
Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History"


in the various original documents, forming one section Entitled
"History"; likewise combine any sections Entitled "Acknowledgements",
and any sections Entitled "Dedications". You must delete all sections
Entitled "Endorsements".

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents
released under this License, and replace the individual copies of this
License in the various documents with a single copy that is included in
the collection, provided that you follow the rules of this License for
verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute
it individually under this License, provided you insert a copy of this
License into the extracted document, and follow this License in all
other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate


and independent documents or works, in or on a volume of a storage or
distribution medium, is called an "aggregate" if the copyright
resulting from the compilation is not used to limit the legal rights
of the compilation's users beyond what the individual works permit.
When the Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not themselves
derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these


copies of the Document, then if the Document is less than one half of
the entire aggregate, the Document's Cover Texts may be placed on
covers that bracket the Document within the aggregate, or the
electronic equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the whole
aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may


distribute translations of the Document under the terms of section 4.
Replacing Invariant Sections with translations requires special
permission from their copyright holders, but you may include
translations of some or all Invariant Sections in addition to the
original versions of these Invariant Sections. You may include a
translation of this License, and all the license notices in the
Document, and any Warranty Disclaimers, provided that you also include
the original English version of this License and the original versions
of those notices and disclaimers. In case of a disagreement between
the translation and the original version of this License or a notice
or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements",


"Dedications", or "History", the requirement (section 4) to Preserve
its Title (section 1) will typically require changing the actual
title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except
as expressly provided for under this License. Any other attempt to
copy, modify, sublicense or distribute the Document is void, and will
automatically terminate your rights under this License. However,
parties who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions


of the GNU Free Documentation License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns. See
http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number.


If the Document specifies that a particular numbered version of this
License "or any later version" applies to it, you have the option of
following the terms and conditions either of that specified version or
of any later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a version
number of this License, you may choose any version ever published (not
as a draft) by the Free Software Foundation.

ADDENDUM: How to use this License for your documents

To use this License in a document you have written, include a copy of


the License in the document and put the following copyright and
license notices just after the title page:

Copyright (c) YEAR YOUR NAME.


Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,


replace the "with...Texts." line with this:

with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.

If you have Invariant Sections without Cover Texts, or some other


combination of the three, merge those two alternatives to suit the
situation.

If your document contains nontrivial examples of program code, we


recommend releasing these examples in parallel under your choice of
free software license, such as the GNU General Public License,
to permit their use in free software.

1. ↑ http://dev.mysql.com/doc/refman/5.0/fr/information-functions.html
2. ↑ http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_coercibility
Récupérée de « http://fr.wikibooks.org/w/index.php?title=MySQL/Version_imprimable&oldid=424954 »

Dernière modification de cette page le 17 août 2013 à 20:47.


Les textes sont disponibles sous licence Creative Commons attribution partage à l’identique ; d’autres
termes peuvent s’appliquer.
Voyez les termes d’utilisation pour plus de détails.

Vous aimerez peut-être aussi