Sur les différents SGBD, il y a une multitude de fonctions :
« Enseigner, ce n’est pas remplir un vase, c’est allumer un feu » Une phrase qui ne date pas d’hier puisqu’elle est de Montaigne …
L’objectif n’est pas de les voir toutes mais d’en utiliser certaines (si possible les plus pertinentes), pour voir les différences entre SGBD et en retenir quelques une.
SELECT CURDATE(); -- fonction sur MYSQL (juste la date)
SELECT GETDATE(); -- fonction transactSQL de SQLSERVER
SELECT SYSDATE(); -- fonction sur ORACLE
SELECT CURRENT_TIMESTAMP; -- norme SQL : fonction "système" pas de paramètres
-- (fonctionne sur MYSQL et PostGreSQL , mais pas sur ORACLE et SQLSERVER)
SELECT NOW(); -- fonction sur MYSQL (date+heure)
Quelles sont les fonctions pour obtenir la date d’aujourd’hui sur les principaux SGBDR ?
Indiquer si ces fonctions tiennent compte du fuseau horaire et le format de la date retournée.
DROP TABLE IF EXISTS telephone;
CREATE TABLE telephone
(INTEGER AUTO_INCREMENT
idTelephone CHAR(2)
, type_id INTEGER
, marque_id DATE
, date_achat DECIMAL (9,2) /* NUMBER(9,2) sur ORACLE */
, prix INTEGER
, proprietaire_id VARCHAR(25)
, couleur PRIMARY KEY(idTelephone)
,
);
INSERT INTO telephone (idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id,couleur) VALUES (1,'SP' ,1,STR_TO_DATE('15/01/2020', '%d/%m/%Y'),139.99,190120,'ROUGE');
-- il est déconseillé de mettre une valeur à une clé primaire => pour vérification
INSERT INTO telephone (idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id) VALUES (NULL,'SP' ,2,STR_TO_DATE('14/03/2020', '%d/%m/%Y'), 99.99,190215);
INSERT INTO telephone
VALUES
(idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id,couleur) NULL,'CL' ,3,STR_TO_DATE('02/05/2020', '%d/%m/%Y'), 49.11,190001,'NOIR');
(INSERT INTO telephone
VALUES
(idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id,couleur) NULL,'CO' ,4,STR_TO_DATE('25/07/2020', '%d/%m/%Y'), 89.14,190222,'BLANC');
(INSERT INTO telephone
VALUES
(idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id) NULL,'IP' ,5,STR_TO_DATE('30/09/2020', '%d/%m/%Y'),359.49,190561);
(INSERT INTO telephone
VALUES
(idTelephone,type_id,marque_id,date_achat,prix,proprietaire_id,couleur) NULL,'CO' ,5,STR_TO_DATE('01/01/2021', '%d/%m/%Y'), 99.51,122120,'BLANC'),
(NULL,'SP' ,1,'2013-01-15',189,190622,'ROUGE'),
(NULL,NULL ,NULL,'2013-01-15',20,190623,'ROUGE'),
(NULL,NULL ,1,'2013-01-15',NULL,NULL,NULL); (
exemple :
-- MYSQL
SELECT date_achat,
YEAR(date_achat) as Annee,
as "Difference" ,
DATEDIFF(date_achat, CURDATE()) INTERVAL 30 DAY) as Plus30j ,
DATE_ADD(date_achat, INTERVAL 30 DAY) as Moins30j ,
DATE_SUB(date_achat, INTERVAL -30 DAY) as Moins30j2
DATE_ADD(date_achat, FROM telephone;
-- SQLSERVER
SELECT *,
YEAR(date_achat) as Annee,
DAY, date_achat, DateDemandee) as [Difference],
DATEDIFF(DAY, 30, date_achat) as Plus30j,
DATEADD(DAY, -30, date_achat) as Moins30j
DATEADD(FROM telephone;
-- ORACLE
SELECT *,
EXTRACT(YEAR FROM date_achat) as Annee,
- date_achat as "Difference",
DateDemandee + 30 as Plus30j,
date_achat - 30 as Moins30j
date_achat FROM telephone;
-- ADD_MONTHS(date_achat, 2)
fonction FORMAT
documentation datetime timestamp - limite
DROP TABLE IF EXISTS posts;
CREATE TABLE posts (
INT AUTO_INCREMENT
id_post VARCHAR(255) NOT NULL
, title
, content LONGTEXTonline VARCHAR(255) DEFAULT 0
, NOT NULL DEFAULT CURRENT_TIMESTAMP
, dt_created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
, dt_updated_at DATETIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
, ts_created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
, ts_updated_at PRIMARY KEY (id_post)
, );
Dans la documentation, beaucoup de synonymes :
https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html
INSERT INTO posts(title, online) VALUES('titre post1', 0);
INSERT INTO posts(title, online) VALUES('titre post2', 1);
INSERT INTO posts SET title='titre post3' , online=2;
INSERT INTO posts VALUES
NULL, 'titre post4', NULL, 0, '2023-01-01 12:00:00', '2023-01-01 12:00:00', '2023-01-01 12:00:00', '2023-01-01 12:00:00');
(SELECT * FROM posts;
UPDATE posts SET title='titre post1 new' WHERE id_post=1;
SELECT * FROM posts;
ATTENTION à la configuration (localisation) du serveur
SELECT @@global.time_zone, @@session.time_zone;
SET time_zone = '+03:00';
SELECT @@global.time_zone, @@session.time_zone;
INSERT INTO posts(title, online) VALUES('titre post5', 0);
INSERT INTO posts(title, online) VALUES('titre post6', 1);
SELECT * FROM posts;
timestamp nombre de seconde depuis 1970
différence timezone timestamp(=> sauvegarde au format UTC)
date au format UTC (temps universel) : UTC_TIMESTAMP() n’est pas affecté par les fuseaux horaires locaux, ce qui le rend utile pour les scénarios dans lesquels une mesure cohérente du temps est requise sur différents emplacements.
SELECT UTC_TIMESTAMP,UTC_TIMESTAMP();
SELECT UTC_TIMESTAMP()+0;
Pour connaitre la configuation du serveur
SELECT @@global.time_zone, @@session.time_zone;
SELECT TIMEDIFF(NOW(), CONVERT_TZ(NOW(), @@session.time_zone, '+00:00'));
Documentation UTC :
https://fr.wikipedia.org/wiki/Temps_universel_coordonn%C3%A9
: calcul du temps UTC
INSERT INTO posts VALUES(NULL, 'titre post7', NULL, 0, NOW(), NOW(), NOW(), NOW() );
INSERT INTO posts VALUES(NULL, 'titre post8', NULL,1, CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP() , CURRENT_TIMESTAMP(), CURRENT_TIMESTAMP());
INSERT INTO posts VALUES(NULL, 'titre post9', NULL, 0, '2023-03-29 12:00:00', '2023-03-29 12:00:00', '2023-03-29 12:00:00', '2023-03-29 12:00:00');
SELECT * FROM posts;
Il existe beaucoup de fonctions : exemple de fonctions
Exemple : Avec une table et un champ composé du nom et du prénom (pas d’espace dans le nom) récupérer le nom et le prénom des personnes
-- MYSQL
SELECT libelle,
INSTR(libelle, ' '),
LEFT(libelle, INSTR(libelle, ' ')- 1),
INSTR(libelle, ' ')+ 1, 100),
SUBSTRING(libelle, LTRIM(SUBSTRING(libelle, INSTR(libelle, ' '), 100))
FROM marque_tel;
-- SQL SERVER
SELECT libelle,
' ', libelle),
CHARINDEX(LEFT(libelle, CHARINDEX(' ', libelle) - 1),
' ', libelle) + 1, 100),
SUBSTRING(libelle, CHARINDEX(LTRIM(SUBSTRING(libelle, CHARINDEX(' ', libelle), 100))
FROM marque_tel;
-- ORACLE
SELECT libelle,
INSTR(libelle, ' '),
SUBSTR(libelle, 1, INSTR(libelle, ' ')- 1),
SUBSTR(libelle, INSTR(libelle, ' ')+ 1, 100),
TRIM(SUBSTR(libelle, INSTR(libelle, ' '), 100))
FROM marque_tel;
-- pour SQL Server et MySQL
SELECT
idTelephone/ 2 -- attention au trans-typage CAST
, idTelephone
, prixCOALESCE(prix, 0) * 2
, -- CEIL sur ORACLE
, CEILING(prix) FLOOR(prix)
, ROUND(prix, 1)
, FROM telephone;
dateTime : attention à l’heure dans un BETWEEN (ne pas perdre la dernière valeur), pour une valeur entre 2 dates (pour la deuxième date, l’heure vaut 00:00:00)
Si c’est possible : Ne pas utiliser des fonctions compliquées sur des colonnes dans le WHERE => Augmente beaucoup le temps d’exécution des requêtes
SELECT tel.prix AS PRIX
IF(tel.prix <99 ,"premier Prix", IF(tel.prix<259,"prix medium","prix élevé"))
, FROM telephone AS tel
WHERE tel.prix IS NOT NULL;
SELECT tel.date_achat AS ACHAT
AS type
, tel.type_id AS MARQUE
, tel.marque_id AS LIBELLE
, marq.libelle CASE tel.marque_id
, WHEN 1 THEN 'MEILLEURS VENTES'
WHEN 5 THEN 'Très bonnes ventes'
ELSE 'AUTRES ventes'
END AS type_de_vente
FROM telephone tel
INNER JOIN marque_tel AS marq
ON tel.marque_id = marq.idMarque ;
SELECT tel.DATE_ACHAT AS dateAchat
type.libelle AS type
, AS marque
, marq.libelle AS prix
, tel.PRIX CASE
, WHEN tel.PRIX <= 99 THEN 'premier Prix'
WHEN tel.PRIX >= 300 THEN 'Prix élevé'
WHEN tel.PRIX > 49 AND tel.PRIX < 300 THEN 'PRIX MOYEN'
END AS type_PRIX
FROM telephone AS tel
INNER JOIN type_tel AS type
ON tel.type_id = type.idType
INNER JOIN marque_tel AS marq
ON tel.marque_id = marq.idMarque;
– vente d’article (style le bon-coin)
DROP TABLE IF EXISTS offre;
CREATE TABLE offre (
INT AUTO_INCREMENT
id_offre VARCHAR(255)
, article_offre VARCHAR(255)
, ville
, location POINTPRIMARY KEY (id_offre)
, );
INSERT INTO offre VALUES (null, 'article1', 'Belfort, Fr', ST_GEOMFROMTEXT('POINT(6.862100 47.638770)'));
INSERT INTO offre VALUES (null, 'article2', 'Besancon, Fr', ST_GEOMFROMTEXT('POINT(6.025530 47.241268)'));
INSERT INTO offre VALUES (null, 'article3', 'Poitiers', ST_GeomFromText('POINT(0.340196 46.580260)'));
INSERT INTO offre VALUES (null, 'article4', 'Montpellier', ST_GeomFromText('POINT(3.876734 43.611242)'));
SELECT *
FROM offre;
doc mariadb - doc mysql - doc postgre
ST_DISTANCE_SPHERE(g1,g2,[r])
par défaut le radius est
celui de la terre
SELECT ST_DISTANCE_SPHERE( ST_GEOMFROMTEXT('POINT(6.862100 47.638770)'),offre.location )
CONCAT('distance entre BELFORT et ',offre.ville)
, FROM offre;
SELECT
ROUND( ST_DISTANCE_SPHERE( ST_GEOMFROMTEXT('POINT(6.862100 47.638770)'),offre.location )/1000)
CONCAT('distance entre BELFORT et ',offre.ville)
, FROM offre;
SET @distance_max=100;
SET @ma_localisation=ST_GEOMFROMTEXT('POINT(6.862100 47.638770)');
SELECT
ROUND( ST_DISTANCE_SPHERE( @ma_localisation,offre.location )/1000)
CONCAT('distance entre BELFORT et ',offre.ville)
, FROM offre;
SELECT *
FROM offre
WHERE ROUND( ST_DISTANCE_SPHERE( @ma_localisation ,offre.location )/1000) < @distance_max;
possibilité de modéliser un polygon https://www.data.gouv.fr/fr/datasets/contours-des-departements-francais-issus-d-openstreetmap/
https://dev.mysql.com/doc/refman/8.0/en/fulltext-search.html
MATCH (col1,col2,...) AGAINST (expr [search_modifier])
DROP TABLE IF EXISTS article;
CREATE TABLE article (
INT AUTO_INCREMENT
id_article VARCHAR(255)
, nom -- 65,535 characters
, description_courte TEXT -- 16,777,215 characters
, description_longue MEDIUMTEXT PRIMARY KEY (id_article)
,
, FULLTEXT ft_nom_desc_c_desc_long (nom, description_courte, description_longue) );
INSERT INTO article VALUES (null, 'article1'
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut labore et dolore magna aliqua. '
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.');
INSERT INTO article VALUES (null, 'article2 but'
'Lorem ipsum dolor sit amet, but consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut labore et dolore but magna aliqua. but 3'
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut labore et but dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. but Duis aute irure dolor in reprehenderit in but voluptate velit esse
cillum dolore eu fugiat nulla pariatur. but Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum. but 5');
INSERT INTO article VALUES (null, 'article1 info'
'Lorem ipsum dolor info sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut labore et info dolore magna aliqua. info 3'
'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut info labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi info ut aliquip ex ea commodo
consequat. Duis aute irure dolor info in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. info Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum. info 5');
INSERT INTO article VALUES (null, 'article1 but info'
'Lorem ipsum dolor but info sit amet, consectetur adipisicing elit, but info sed do eiusmod
, tempor incididunt ut labore but info et dolore magna aliqua. '
'Lorem ipsum dolor but info sit amet, consectetur adipisicing elit, sed do eiusmod
, tempor incididunt ut but info labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco but info laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in but info reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. but info Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum. but info 5');
SELECT *
FROM article;
CREATE TABLE article;
SHOW
ALTER TABLE article ADD FULLTEXT ft_nom (nom);
ALTER TABLE article ADD FULLTEXT ft_description_courte (description_courte);
ALTER TABLE article ADD FULLTEXT ft_description_longue (description_longue);
CREATE TABLE article;
SHOW
SELECT
nom,'info') AS score_nom,
MATCH(nom) AGAINST('info') AS score_description_courte,
MATCH(description_courte) AGAINST('info') AS score_description_longue
MATCH(description_longue) AGAINST(FROM article;
SELECT
nom,'but info') AS score_nom,
MATCH(nom) AGAINST('but info') AS score_description_courte,
MATCH(description_courte) AGAINST('but info') AS score_description_longue
MATCH(description_longue) AGAINST(FROM article;
SET @recherche_texte='but info';
SELECT
nom,AS score_nom ,
MATCH(nom) AGAINST(@recherche_texte) AS score_description_courte ,
MATCH(description_courte) AGAINST(@recherche_texte) AS score_description_longue ,
MATCH(description_longue) AGAINST(@recherche_texte) * 1
MATCH(nom) AGAINST(@recherche_texte) + MATCH(description_courte) AGAINST(@recherche_texte) * 0.5
+ MATCH(description_longue) AGAINST(@recherche_texte) * 0.1 AS calcul_score
FROM article
WHERE
OR
MATCH(nom) AGAINST(@recherche_texte) OR
MATCH(description_courte) AGAINST(@recherche_texte)
MATCH(description_longue) AGAINST(@recherche_texte)ORDER BY (score_nom+score_description_courte*0.5+score_description_longue*0.1) DESC;
plusieurs modes
SELECT nom
FROM article
WHERE
MATCH (description_courte)'+info -but' IN BOOLEAN MODE);
AGAINST (
SELECT nom , description_courte
FROM article
WHERE
MATCH (description_courte)'inf*' IN BOOLEAN MODE); AGAINST (
SELECT nom , description_courte
FROM article
WHERE
MATCH (description_courte)
AGAINST ('info' WITH QUERY EXPANSION);
expansion aveugle des requêtes : Cela fonctionne en effectuant la recherche deux fois, où la phrase de recherche pour la deuxième recherche est la phrase de recherche d’origine concaténée avec les quelques documents les plus pertinents de la première recherche.
+-------------+-------------------+------------+--------+------------+-------------------+
| idTelephone | libelle | libelle | prix | date_achat | date_fin_garantie |
+-------------+-------------------+------------+--------+------------+-------------------+
| 7 | société SAMSUNG | Smartphone | 189.00 | 2013-01-15 | 2014-01-15 |
| 1 | société SAMSUNG | Smartphone | 139.99 | 2020-01-15 | 2021-01-15 |
| 2 | entreprise SONY | Smartphone | 99.99 | 2020-03-14 | 2021-03-14 |
| 3 | groupe PHILIPS | clapet | 49.11 | 2020-05-02 | 2021-05-02 |
| 4 | marque MOTOROLA | COULISSANT | 89.14 | 2020-07-25 | 2021-07-25 |
| 5 | SOCIETE APPLE | IPHONE | 359.49 | 2020-09-30 | 2021-09-30 |
+-------------+-------------------+------------+--------+------------+-------------------+
+-------------+-------------------+------------+--------+------------+-------------------+
| 7 | société SAMSUNG | Smartphone | 189.00 | 2013-01-15 | 2015-01-15 |
| 1 | société SAMSUNG | Smartphone | 139.99 | 2020-01-15 | 2022-01-15 |
| 2 | entreprise SONY | Smartphone | 99.99 | 2020-03-14 | 2021-03-14 |
| 3 | groupe PHILIPS | clapet | 49.11 | 2020-05-02 | 2021-05-02 |
| 4 | marque MOTOROLA | COULISSANT | 89.14 | 2020-07-25 | 2021-07-25 |
| 5 | SOCIETE APPLE | IPHONE | 359.49 | 2020-09-30 | 2023-09-30 |
+-------------+-------------------+------------+--------+------------+-------------------+
Remise : le magasin désire envoyer un bon de remise à toutes les personnes propriétaires d’un téléphone depuis moins de 5 ans (date d’achat datant de moins de 5 ans)
le prix doit être non “NULL” ainsi que la date d’achat
arrondir les valeurs aux chiffres supérieurs
afficher l’identifiant du propriétaire, le libellé de la marque, le libellé du type, le prix, la date d’achat, le nombre de jours entre aujourd’hui et (la date d’achat + 2 ans). Le résultat est ordonné par date d’achat.
Modifier une date : “UPDATE telephone SET date_achat=”2006-01-15” WHERE proprietaire_id=190215;” et vérifier que la requête précédente fonctionne bien.
+-----------------+-------------------+------------+--------+------------+------------+---------+
| proprietaire_id | libelle | libelle | prix | date_achat | calcul_tmp | remise |
+-----------------+-------------------+------------+--------+------------+------------+---------+
| 190120 | société SAMSUNG | Smartphone | 139.99 | 2020-01-15 | -709 | 9.7993 |
| 190215 | entreprise SONY | Smartphone | 99.99 | 2020-03-14 | -767 | 4.9995 |
| 190001 | groupe PHILIPS | clapet | 49.11 | 2020-05-02 | -816 | 2.4555 |
| 190222 | marque MOTOROLA | COULISSANT | 89.14 | 2020-07-25 | -900 | 4.4570 |
| 190561 | SOCIETE APPLE | IPHONE | 359.49 | 2020-09-30 | -967 | 35.9490 |
+-----------------+-------------------+------------+--------+------------+------------+---------+
objectif : mettre les dates au format JJ/MM/AAAA “strict”, faire une recherche sur la fonction LPAD
+-----------------+-------------------+------------+--------+---------------+
| proprietaire_id | libelle | libelle | prix | DATE_ACHAT_FR |
+-----------------+-------------------+------------+--------+---------------+
| 190622 | société SAMSUNG | Smartphone | 189.00 | 15/01/2013 |
| 190120 | société SAMSUNG | Smartphone | 139.99 | 15/01/2020 |
| 190215 | entreprise SONY | Smartphone | 99.99 | 14/03/2020 |
| 190001 | groupe PHILIPS | clapet | 49.11 | 02/05/2020 |
| 190222 | marque MOTOROLA | COULISSANT | 89.14 | 25/07/2020 |
| 190561 | SOCIETE APPLE | IPHONE | 359.49 | 30/09/2020 |
+-----------------+-------------------+------------+--------+---------------+
les variables (voir PL/SQL) https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/user-variables.html
SET @t1=1, @t2=2, @t3:=4;
SELECT @t1, @t2, @t3, @t4 := @t1+@t2+@t3;
https://docs.oracle.com/cd/E11882_01/server.112/e16604/ch_twelve050.htm#SQPUG133
* sur sqlserver
https://docs.postgresql.fr/8.1/plpgsql-declarations.html
https://www.postgresqltutorial.com/plpgsql-variables/