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 TD_telephone;
CREATE TABLE TD_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 TD_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 TD_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 TD_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 TD_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 TD_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 TD_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 TD_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 TD_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 TD_telephone;
-- ADD_MONTHS(date_achat, 2)
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 TD_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 TD_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 TD_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 TD_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 TD_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 TD_telephone tel
INNER JOIN TD_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 TD_telephone AS tel
INNER JOIN TD_type_tel AS type
ON tel.type_id = type.idType
INNER JOIN TD_marque_tel AS marq
ON tel.marque_id = marq.idMarque;
– vente d’article (style le bon-coin)
DROP TABLE IF EXISTS TD_offre;
CREATE TABLE TD_offre (
INT AUTO_INCREMENT
id_offre VARCHAR(255)
, article_offre VARCHAR(255)
, ville
, location POINTPRIMARY KEY (id_offre)
, );
INSERT INTO TD_offre VALUES (null, 'article1', 'Belfort, Fr', ST_GEOMFROMTEXT('POINT(6.862100 47.638770)'));
INSERT INTO TD_offre VALUES (null, 'article2', 'Besancon, Fr', PointFromText('POINT(6.025530 47.241268)'));
INSERT INTO TD_offre VALUES (null, 'article3', 'Poitiers', ST_GeomFromText('POINT(0.340196 46.580260)'));
INSERT INTO TD_offre VALUES (null, 'article4', 'Montpellier', ST_GeomFromText('POINT(3.876734 43.611242)'));
SELECT *
FROM TD_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)'),TD_offre.location )
CONCAT('distance entre BELFORT et ',TD_offre.ville)
, FROM TD_offre;
SELECT
ROUND( ST_DISTANCE_SPHERE( ST_GEOMFROMTEXT('POINT(6.862100 47.638770)'),TD_offre.location )/1000)
CONCAT('distance entre BELFORT et ',TD_offre.ville)
, FROM TD_offre;
SET @distance_max=100;
SET @ma_localisation=ST_GEOMFROMTEXT('POINT(6.862100 47.638770)');
SELECT
ROUND( ST_DISTANCE_SPHERE( @ma_localisation,TD_offre.location )/1000)
CONCAT('distance entre BELFORT et ',TD_offre.ville)
, FROM TD_offre;
SELECT *
FROM TD_offre
WHERE ROUND( ST_DISTANCE_SPHERE( @ma_localisation ,TD_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 TD_article;
CREATE TABLE TD_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 TD_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 TD_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 TD_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 TD_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 TD_article;
ALTER TABLE TD_article ADD FULLTEXT ft_nom (nom);
ALTER TABLE TD_article ADD FULLTEXT ft_description_courte (description_courte);
ALTER TABLE TD_article ADD FULLTEXT ft_description_longue (description_longue);
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 TD_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 TD_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 TD_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 TD_article
WHERE
MATCH (description_courte)'+info -but' IN BOOLEAN MODE);
AGAINST (
SELECT nom , description_courte
FROM TD_article
WHERE
MATCH (description_courte)'inf*' IN BOOLEAN MODE); AGAINST (
SELECT nom , description_courte
FROM TD_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 TD_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/