Comme prévu, ce chapitre sera consacré aux fonctions scalaires permettant la manipulation de nombres et de chaînes de caractères. Nous verrons entre autres comment arrondir un nombre ou tirer un nombre au hasard, et comment connaître la longueur d'un texte ou en extraire une partie. La fin de ce chapitre est constituée d'exercices afin de pouvoir mettre les fonctions en pratique.
Il existe aussi des fonctions permettant de manipuler les dates en SQL, mais une partie entière leur sera consacrée.
À nouveau, si vous ne trouvez pas votre bonheur parmi les fonctions présentées ici, n'hésitez surtout pas à faire un tour sur la documentation officielle. N'essayez pas de retenir par cœur toutes ces fonctions bien sûr. Si vous savez qu'elles existent, il vous sera facile de retrouver leur syntaxe exacte en cas de besoin, que ce soit ici ou dans la documentation.
Manipulation de nombres
Voici donc quelques fonctions scalaires qui vont vous permettre de manipuler les nombres : faire des calculs, des arrondis, prendre un nombre au hasard, etc.
Toutes les fonctions de cette partie retournent NULL
en cas d'erreur !
Arrondis
Arrondir un nombre, c'est trouver une valeur proche de ce nombre avec une précision donnée et selon certains critères. La précision est en général représentée par le nombre de décimales désirées. Par exemple, pour un prix, on travaille rarement avec plus de deux décimales. Pour un âge, on préférera généralement un nombre entier (c'est-à-dire aucune décimale). Quant aux critères, il s'agit de décider si l'on veut arrondir au plus proche (ex. : 4,3 arrondi à l'entier le plus proche vaut 4), arrondir au supérieur (ex. : 4,3 arrondi à l'entier supérieur vaut 5) ou arrondir à l'inférieur (ex. : 4,3 arrondi à l'entier inférieur vaut 4).
Voici quatre fonctions permettant d'arrondir les nombres, selon ces différents critères. Pour les paramètres, n représente le nombre à arrondir, d le nombre de décimales désirées.
CEIL()
CEIL(n)
ou CEILING(n)
arrondit au nombre entier supérieur.
1 | SELECT CEIL(3.2), CEIL(3.7); |
CEIL(3.2) |
CEIL(3.7) |
---|---|
4 |
4 |
FLOOR()
FLOOR(n)
arrondit au nombre entier inférieur.
1 | SELECT FLOOR(3.2), FLOOR(3.7); |
FLOOR(3.2) |
FLOOR(3.7) |
---|---|
3 |
3 |
ROUND()
ROUND(n, d)
arrondit au nombre à d décimales le plus proche. ROUND(n)
équivaut à écrire ROUND(n, 0)
, donc arrondit à l'entier le plus proche.
1 2 3 | SELECT ROUND(3.22, 1), ROUND(3.55, 1), ROUND(3.77, 1); SELECT ROUND(3.2), ROUND(3.5), ROUND(3.7); |
ROUND(3.22, 1) |
ROUND(3.55, 1) |
ROUND(3.77, 1) |
---|---|---|
3.2 |
3.6 |
3.8 |
ROUND(3.2) |
ROUND(3.5) |
ROUND(3.7) |
---|---|---|
3 |
4 |
4 |
Si le nombre se trouve juste entre l'arrondi supérieur et l'arrondi inférieur (par exemple si on arrondit 3,5 à un nombre entier), certaines implémentations vont arrondir vers le haut, d'autres vers le bas. Testez donc pour savoir dans quel cas est votre serveur (comme vous voyez, ici, c'est vers le haut).
TRUNCATE()
TRUNCATE(n, d)
arrondit en enlevant purement et simplement les décimales en trop (donc arrondi à l'inférieur pour les nombres positifs, au supérieur pour les nombres négatifs).
1 2 3 | SELECT TRUNCATE(3.2, 0), TRUNCATE(3.5, 0), TRUNCATE(3.7, 0); SELECT TRUNCATE(3.22, 1), TRUNCATE(3.55, 1), TRUNCATE(3.77, 1); |
TRUNCATE(3.2, 0) |
TRUNCATE(3.5, 0) |
TRUNCATE(3.7, 0) |
---|---|---|
3 |
3 |
3 |
TRUNCATE(3.22, 1) |
TRUNCATE(3.55, 1) |
TRUNCATE(3.77, 1) |
---|---|---|
3.2 |
3.5 |
3.7 |
Exposants et racines
Exposants
POWER(n, e)
(ou POW(n, e)
) retourne le résultat de n exposant e ($n^e$).
Pour rappel, n exposant e ($n^e$) veut dire que l'on multiplie n par lui-même, e fois. Donc par exemple, $2^3 = 2\times2\times2 = 8$
1 | SELECT POW(2, 5), POWER(5, 2); |
POW(2, 5) |
POWER(5, 2) |
---|---|
32 |
25 |
Racines
Prendre la racine nième d'un nombre x ($\sqrt[n]{x}$), c'est trouver le (ou les) nombre(s) y qui répond(ent) à la condition suivante : $y^n = x$. Donc la racine cinquième de 32 ($\sqrt[5]{32}$) vaut 2, puisque $2^5 = 2\times2\times2\times2\times2 = 32$
SQRT(n)
donne la racine carrée positive de n ($\sqrt{n} = \sqrt[2]{n}$).
1 | SELECT SQRT(4); |
SQRT(4) |
---|
2 |
Il n'existe pas de fonction particulière pour obtenir la racine nième d'un nombre pour n > 2. Cependant, pour ceux qui ne le sauraient pas : $\sqrt[n]{x} = x^{\frac{1}{n}}$. Donc, pour obtenir par exemple la racine cinquième de 32, il suffit de faire :
1 | SELECT POW(32, 1/5); |
POW(32, 1/5) |
---|
2 |
Hasard
Le "vrai" hasard n'existe pas en informatique. Il est cependant possible de simuler le hasard, avec par exemple un générateur de nombres aléatoires. MySQL implémente un générateur de nombres aléatoires auquel vous pouvez faire appel en utilisant la fonction RAND()
, qui retourne un nombre "aléatoire" entre 0 et 1.
1 | SELECT RAND(); |
RAND() |
---|
0.08678611469155748 |
Cette fonction peut par exemple être utile pour trier des résultats de manière aléatoire. Un nombre différent va en effet être généré pour chaque ligne de résultat. Le tri se fera alors sur ce nombre généré "au hasard". Notez que ce n'est pas très bon en termes de performances, étant donné qu'un nombre doit être généré pour chaque ligne.
1 2 3 | SELECT * FROM Race ORDER BY RAND(); |
Divers
SIGN()
SIGN(n)
renvoie le signe du nombre n. Ou plus exactement, SIGN(n)
renvoie -1 si n est négatif, 0 si n vaut 0, et 1 si n est positif.
1 | SELECT SIGN(-43), SIGN(0), SIGN(37); |
SIGN(-43) |
SIGN(0) |
SIGN(37) |
---|---|---|
-1 |
0 |
1 |
ABS()
ABS(n)
retourne la valeur absolue de n, donc sa valeur sans le signe.
1 | SELECT ABS(-43), ABS(0), ABS(37); |
ABS(-43) |
ABS(0) |
ABS(37) |
---|---|---|
43 |
0 |
37 |
MOD()
La fonction MOD(n, div)
retourne le modulo, donc le reste de la division entière de n par div (comme l'opérateur %
ou MOD
)
1 | SELECT MOD(56, 10); |
MOD(56, 10) |
---|
6 |
Manipulation de chaînes de caractères
Nous allons maintenant manipuler, triturer, examiner des chaînes de caractères. À toutes fins utiles, je rappelle en passant qu'en SQL, les chaînes de caractères sont entourées de guillemets (simples, mais les guillemets doubles fonctionnent avec MySQL également).
Longueur et comparaison
Connaître la longueur d'une chaîne
Trois fonctions permettent d'avoir des informations sur la longueur d'une chaîne de caractères. Chaque fonction calcule la longueur d'une manière particulière.
BIT_LENGTH(chaine)
: retourne le nombre de bits de la chaîne. Chaque caractère est encodé sur un ou plusieurs octets, chaque octet représente huit bits.CHAR_LENGTH(chaine)
: (ouCHARACTER_LENGTH()
) retourne le nombre de caractères de la chaîne.LENGTH(chaine)
: retourne le nombre d'octets de la chaîne. Chaque caractère étant représenté par un ou plusieurs octets (rappel : les caractères que vous pouvez utiliser dépendent de l'encodage choisi).
1 2 3 | SELECT BIT_LENGTH('élevage'), CHAR_LENGTH('élevage'), LENGTH('élevage'); -- Les caractères accentués sont codés sur 2 octets en UTF-8 |
BIT_LENGTH('élevage') |
CHAR_LENGTH('élevage') |
LENGTH('élevage') |
---|---|---|
64 |
7 |
8 |
A priori, dans neuf cas sur dix au moins, la fonction qui vous sera utile est donc CHAR_LENGTH()
.
Comparer deux chaînes
La fonction STRCMP(chaine1, chaine2)
compare les deux chaînes passées en paramètres et retourne 0 si les chaînes sont les mêmes, -1 si la première chaîne est classée avant dans l'ordre alphabétique et 1 dans le cas contraire.
1 2 3 4 5 | SELECT STRCMP('texte', 'texte') AS 'texte=texte', STRCMP('texte','texte2') AS 'texte<texte2', STRCMP('chaine','texte') AS 'chaine<texte', STRCMP('texte', 'chaine') AS 'texte>chaine', STRCMP('texte3','texte24') AS 'texte3>texte24'; -- 3 est après 24 dans l'ordre alphabétique |
texte=texte |
texte<texte2 |
chaine<texte |
texte>chaine |
texte3>texte24 |
---|---|---|---|---|
0 |
-1 |
-1 |
1 |
1 |
Retrait et ajout de caractères
Répéter une chaîne
REPEAT(c, n)
retourne le texte c, n fois.
1 | SELECT REPEAT('Ok ', 3); |
REPEAT('Ok ', 3) |
---|
Ok Ok Ok |
Compléter/réduire une chaîne
Les fonctions LPAD()
et RPAD()
appliquées à une chaîne de caractères retournent cette chaîne en lui donnant une longueur particulière, donnée en paramètre. Si la chaîne de départ est trop longue, elle sera raccourcie, si elle est trop courte, des caractères seront ajoutés, à gauche de la chaîne pour LPAD()
, à droite pour RPAD()
.
Ces fonctions nécessitent trois paramètres : la chaîne à transformer (texte), la longueur désirée (long), et le caractère à ajouter si la chaîne est trop courte (caract).
1 2 | LPAD(texte, long, caract) RPAD(texte, long, caract) |
1 2 3 4 5 | SELECT LPAD('texte', 3, '@') AS '3_gauche_@', LPAD('texte', 7, '$') AS '7_gauche_$', RPAD('texte', 5, 'u') AS '5_droite_u', RPAD('texte', 7, '*') AS '7_droite_*', RPAD('texte', 3, '-') AS '3_droite_-'; |
3_gauche_@ |
7_gauche_\$ |
5_droite_u |
7_droite_* |
3_droite_- |
---|---|---|---|---|
tex |
\$\$texte |
texte |
texte** |
tex |
Ôter les caractères inutiles
Il peut arriver que certaines de vos données aient des caractères inutiles ajoutés avant et/ou après le texte intéressant. Dans ce cas, il vous est possible d'utiliser la fonction TRIM()
, qui va supprimer tous ces caractères. Cette fonction a une syntaxe un peu particulière que voici :
1 | TRIM([[BOTH | LEADING | TRAILING] [caract] FROM] texte); |
Je rappelle que ce qui est entre crochets est facultatif.
On peut donc choisir entre trois options : BOTH
, LEADING
et TRAILING
.
BOTH
: les caractères seront éliminés à l'avant, et à l'arrière du texteLEADING
: seuls les caractères à l'avant de la chaîne seront supprimésTRAILING
: seuls les caractères à l'arrière de la chaîne seront supprimés
Si aucune option n'est précisée, c'est BOTH
qui est utilisé par défaut.
caract est la chaîne de caractères (ou le caractère unique) à éliminer en début et/ou fin de chaîne. Ce paramètre est facultatif : par défaut les espaces blancs seront supprimées. Et texte est bien sûr la chaîne de caractères à traiter.
1 2 3 4 5 6 7 8 9 | SELECT TRIM(' Tralala ') AS both_espace, TRIM(LEADING FROM ' Tralala ') AS lead_espace, TRIM(TRAILING FROM ' Tralala ') AS trail_espace, TRIM('e' FROM 'eeeBouHeee') AS both_e, TRIM(LEADING 'e' FROM 'eeeBouHeee') AS lead_e, TRIM(BOTH 'e' FROM 'eeeBouHeee') AS both_e, TRIM('123' FROM '1234ABCD4321') AS both_123; |
both_espace |
lead_espace |
trail_espace |
both_e |
lead_e |
both_e |
both_123 |
---|---|---|---|---|---|---|
Tralala |
Tralala |
Tralala |
BouH |
BouHeee |
BouH |
4ABCD4321 |
Récupérer une sous-chaîne
La fonction SUBSTRING()
retourne une partie d'une chaîne de caractères. Cette partie est définie par un ou deux paramètres : pos (obligatoire), qui donne la position de début de la sous-chaîne, et long (facultatif) qui donne la longueur de la sous-chaîne désirée (si ce paramètre n'est pas précisé, toute la fin de la chaîne est prise).
Quatre syntaxes sont possibles :
SUBSTRING(chaine, pos)
SUBSTRING(chaine FROM pos)
SUBSTRING(chaine, pos, long)
SUBSTRING(chaine FROM pos FOR long)
1 2 3 4 | SELECT SUBSTRING('texte', 2) AS from2, SUBSTRING('texte' FROM 3) AS from3, SUBSTRING('texte', 2, 3) AS from2long3, SUBSTRING('texte' FROM 3 FOR 1) AS from3long1; |
from2 |
from3 |
from2long3 |
from3long1 |
---|---|---|---|
exte |
xte |
ext |
x |
Recherche et remplacement
Rechercher une chaîne de caractères
INSTR()
, LOCATE()
et POSITION()
retournent la position de la première occurrence d'une chaîne de caractères rech dans une chaîne de caractères chaine. Ces trois fonctions ont chacune une syntaxe particulière :
INSTR(chaine, rech)
LOCATE(rech, chaine)
- les paramètres sont inversés par rapport àINSTR()
POSITION(rech IN chaine)
Si la chaîne de caractères rech n'est pas trouvée dans chaine, ces fonctions retournent 0. Par conséquent, la première lettre d'une chaîne de caractères est à la position 1 (alors que dans beaucoup de langages de programmation, on commence toujours à la position 0).
LOCATE()
peut aussi accepter un paramètre supplémentaire : pos, qui définit la position dans la chaîne à partir de laquelle il faut rechercher rech : LOCATE(rech, chaine, pos)
.
1 2 3 4 | SELECT INSTR('tralala', 'la') AS fct_INSTR, POSITION('la' IN 'tralala') AS fct_POSITION, LOCATE('la', 'tralala') AS fct_LOCATE, LOCATE('la', 'tralala', 5) AS fct_LOCATE2; |
fct_INSTR |
fct_POSITION |
fct_LOCATE |
fct_LOCATE2 |
---|---|---|---|
4 |
4 |
4 |
6 |
Changer la casse des chaînes
Les fonctions LOWER(chaine)
et LCASE(chaine)
mettent toutes les lettres de chaine en minuscules, tandis que UPPER(chaine)
et UCASE(chaine)
mettent toutes les lettres en majuscules.
1 2 3 4 | SELECT LOWER('AhAh') AS minuscule, LCASE('AhAh') AS minuscule2, UPPER('AhAh') AS majuscule, UCASE('AhAh') AS majuscule2; |
minuscule |
minuscule2 |
majuscule |
majuscule2 |
---|---|---|---|
ahah |
ahah |
AHAH |
AHAH |
Récupérer la partie gauche ou droite
LEFT(chaine, long)
retourne les long premiers caractères de chaine en partant de la gauche, et RIGHT(chaine, long)
fait la même chose en partant de la droite.
1 | SELECT LEFT('123456789', 5), RIGHT('123456789', 5); |
LEFT('123456789', 5) |
RIGHT('123456789', 5) |
---|---|
12345 |
56789 |
Inverser une chaîne
REVERSE(chaine)
renvoie chaine en inversant les caractères.
1 | SELECT REVERSE('abcde'); |
REVERSE('abcde') |
---|
edcba |
Remplacer une partie par autre chose
Deux fonctions permettent de remplacer une partie d'une chaîne de caractères : INSERT()
et REPLACE()
.
INSERT(chaine, pos, long, nouvCaract)
: le paramètre chaine est la chaîne de caractères dont on veut remplacer une partie, pos est la position du premier caractère à remplacer, long le nombre de caractères à remplacer, et nouvCaract est la chaîne de caractères qui viendra remplacer la portion de chaine choisie.REPLACE(chaine, ancCaract, nouvCaract)
: tous les caractères (ou sous-chaînes) ancCaract seront remplacés par nouvCaract.
1 2 3 | SELECT INSERT('texte', 3, 2, 'blabla') AS fct_INSERT, REPLACE('texte', 'e', 'a') AS fct_REPLACE, REPLACE('texte', 'ex', 'ou') AS fct_REPLACE2; |
fct_INSERT |
fct_REPLACE |
fct_REPLACE2 |
---|---|---|
teblablae |
taxta |
toute |
Concaténation
Concaténer deux chaînes de caractères signifie les mettre bout à bout pour n'en faire qu'une seule. Deux fonctions scalaires permettent la concaténation : CONCAT()
et CONCAT_WS()
. Ces deux fonctions permettent de concaténer autant de chaînes que vous voulez, il suffit de toutes les passer en paramètres. Par conséquent, ces deux fonctions n'ont pas un nombre de paramètres défini.
CONCAT(chaine1, chaine2,…)
: renvoie simplement une chaîne de caractères, résultat de la concaténation de toutes les chaînes passées en paramètres.CONCAT_WS(separateur, chaine1, chaine2)
: même chose queCONCAT()
, sauf que la première chaîne passée sera utilisée comme séparateur, donc placée entre chacune des autres chaînes passées en paramètres.
1 | SELECT CONCAT('My', 'SQL', '!'), CONCAT_WS('-', 'My', 'SQL', '!'); |
CONCAT('My', 'SQL', '!') |
CONCAT_WS('-', 'My', 'SQL', '!') |
---|---|
MySQL! |
My-SQL-! |
FIELD(), une fonction bien utile pour le tri
La fonction FIELD(rech, chaine1, chaine2, chaine3,…)
recherche le premier argument (rech) parmi les arguments suivants (chaine1, chaine2, chaine3,…) et retourne l'index auquel rech est trouvée (1 si rech = chaine1, 2 si rech = chaine2,…). Si rech n'est pas trouvée parmi les arguments, 0 est renvoyé.
1 | SELECT FIELD('Bonjour', 'Bonjour !', 'Au revoir', 'Bonjour', 'Au revoir !') AS field_bonjour; |
field_bonjour |
---|
3 |
Par conséquent, FIELD
peut être utilisée pour définir un ordre arbitraire dans une clause ORDER BY
.
Exemple : ordonnons les espèces selon un ordre arbitraire. La fonction FIELD()
dans la clause SELECT
n'est là que pour illustrer la façon dont ce tri fonctionne.
1 2 3 | SELECT nom_courant, nom_latin, FIELD(nom_courant, 'Rat brun', 'Chat', 'Tortue d''Hermann', 'Chien', 'Perroquet amazone') AS resultat_field FROM Espece ORDER BY FIELD(nom_courant, 'Rat brun', 'Chat', 'Tortue d''Hermann', 'Chien', 'Perroquet amazone'); |
nom_courant |
nom_latin |
resultat_field |
---|---|---|
Rat brun |
Rattus norvegicus |
1 |
Chat |
Felis silvestris |
2 |
Tortue d'Hermann |
Testudo hermanni |
3 |
Chien |
Canis canis |
4 |
Perroquet amazone |
Alipiopsitta xanthops |
5 |
Si vous ne mettez pas toutes les valeurs existantes de la colonne en argument de FIELD()
, les lignes ayant les valeurs non mentionnées seront classées en premier (puisque FIELD()
renverra 0).
Code ASCII
Les deux dernières fonctions que nous allons voir sont ASCII()
et CHAR()
, qui sont complémentaires. ASCII(chaine)
renvoie le code ASCII du premier caractère de la chaîne passée en paramètre, tandis que CHAR(ascii1, ascii2,…)
retourne les caractères correspondant aux codes ASCII passés en paramètres (autant de paramètres qu'on veut). Les arguments passés à CHAR()
seront convertis en entiers par MySQL.
1 | SELECT ASCII('T'), CHAR(84), CHAR('84', 84+32, 84.2); |
ASCII('T') |
CHAR(84) |
CHAR('84', 84+32, 84.2) |
---|---|---|
84 |
T |
TtT |
Exemples d'application et exercices
Ce chapitre a été fort théorique jusqu'à maintenant. Donc pour changer un peu, et vous réveiller, je vous propose de passer à la pratique, en utilisant les données de notre base elevage. Ces quelques exercices sont faisables en utilisant uniquement les fonctions et opérateurs mathématiques que je vous ai décrits dans ce chapitre.
On commence par du facile
1. Afficher une phrase donnant le prix de l'espèce, pour chaque espèce
Par exemple, afficher "Un chat coûte 100 euros.", ou une autre phrase du genre, et ce pour les cinq espèces enregistrées.
1 2 3 4 5 6 7 | SELECT CONCAT('Un(e) ', nom_courant, ' coûte ', prix, ' euros.') AS Solution FROM Espece; -- OU SELECT CONCAT_WS(' ','Un(e)', nom_courant, 'coûte', prix, 'euros.') AS Solution FROM Espece; |
2. Afficher les chats dont la deuxième lettre du nom est un "a"
1 2 3 4 5 | SELECT Animal.nom, Espece.nom_courant FROM Animal INNER JOIN Espece ON Animal.espece_id = Espece.id WHERE Espece.nom_courant = 'Chat' AND SUBSTRING(nom, 2, 1) = 'a'; |
Puis on corse un peu
1. Afficher les noms des perroquets en remplaçant les "a" par "@" et les "e" par "3" pour en faire des perroquets Kikoolol
1 2 3 4 | SELECT REPLACE(REPLACE(nom, 'a', '@'), 'e', '3') AS Solution FROM Animal INNER JOIN Espece ON Animal.espece_id = Espece.id WHERE Espece.nom_courant LIKE 'Perroquet%'; |
Une petite explication s'impose avant de vous laisser continuer. Comme vous voyez, il est tout à fait possible d'imbriquer plusieurs fonctions. Le tout est de le faire correctement, et pour cela, il faut procéder par étape. Ici, vous voulez faire deux remplacements successifs dans une chaîne de caractères (en l’occurrence, le nom des perroquets). Donc, vous effectuez un premier remplacement, en changeant les "a" par les "@" : REPLACE(nom, 'a', '@')
. Ensuite, sur la chaîne résultant de ce premier remplacement, vous effectuez le second : REPLACE(REPLACE(nom, 'a', '@'), 'e', '3')
. Logique, non ?
2. Afficher les chiens dont le nom a un nombre pair de lettres
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | SELECT nom, nom_courant FROM Animal INNER JOIN Espece ON Animal.espece_id = Espece.id WHERE nom_courant = 'Chien' AND CHAR_LENGTH(nom)%2 = 0; -- OU SELECT nom, nom_courant FROM Animal INNER JOIN Espece ON Animal.espece_id = Espece.id WHERE nom_courant = 'Chien' AND CHAR_LENGTH(nom) MOD 2 = 0; -- OU SELECT nom, nom_courant FROM Animal INNER JOIN Espece ON Animal.espece_id = Espece.id WHERE nom_courant = 'Chien' AND MOD(CHAR_LENGTH(nom),2) = 0; |
Le nombre de lettres, c'était facile, il suffisait d'utiliser CHAR_LENGTH()
.
Pour savoir si un nombre est pair, il faut utiliser les modulos : lorsqu'un nombre est pair, le reste d'une division entière de ce nombre par 2 est 0, donc ce nombre modulo 2 vaut 0.
En résumé
- Concaténer deux chaînes de caractères signifie les mettre bout à bout.
- Il ne faut pas hésiter, pour obtenir le résultat voulu, à combiner plusieurs fonctions ensemble.
- Pour savoir si un nombre est multiple d'un autre, on peut utiliser le modulo.