Si tu veux tenir compte des jours fériés, il n'y a pas d'autre choix que
de passer par une table calendrier.
Il y a diverses façon de le faire, l'une des plus simples consiste à n'y
mettre que les demi-journées ouvrées, et à les numéroter :
DemiJournee Num
===========================
2006-10-23 00:00:00 50
2006-10-23 12:00:00 51
2006-10-24 00:00:00 52
2006-10-24 12:00:00 53
2006-10-25 12:00:00 54
...
Voici par exemple une requête affichant TableX.madate, TableX.maduree,
et madate + maduree :
SELECT T.madate, T.maduree, C2.DemiJournee AS Addition
FROM TableX T
INNER JOIN Calendrier C1 ON T.madate = C.DemiJournee
INNER JOIN Calendrier C2 ON C2.Num = C1.Num + T.maduree
C1 permet de traduite madate en Num ; C2 permet de calculer le décalage
et de traduire le résultat en date.
Cette solution pose deux difficultés :
1/ comment constituer la table calendrier
2/ comment la mettre à jour tout en conservant les Num uniques et dans
l'ordre
Le 2/ se règle facilement avec des triggers : sur un Insert, tous les
Num des DemiJournee postérieurs à new.DemiJournee sont incrémentées de 1
; sur un Delete, ils sont décrémentés de 1.
Le 1/ se fait en deux étapes (rendons à César : c'est la lecture des
oeuvres de Fred Brouard qui m'a appris ces deux méthodes) :
1a/ créer la liste des demi-journées ouvrées
1b/ numéroter les demi-journées
1a/ c'est relativement facile à faire avec Excel, ou bien avec une
boucle PHP ou SQL dynamique ; c'est également possible en simple SQL
statique, c'est la solution que je te propose ici.
Pour cela, il faut d'abord une table contenant les chiffres de 0 à 9.
C'est une table utilitaire qui te re-servira souvent.
CREATE TABLE Chiffres (Num TINYINT UNSIGNED NOT NULL PRIMARY KEY) ;
INSERT INTO Chiffres (Num)
VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);
Supposons maintenant que ton Calendrier doit partir du 01/01/2006 et
couvrir 1000 jours. Il suffit d'ajouter de 0 à 999 jours à la date de
départ. Cela s'obtient par un produit cartésien (toutes les
combinaisons) entre trois instances de Chiffres, pour les Unités,
Dizaines et Centaines.
CREATE TABLE Calendrier (DemiJournee DateTime UNIQUE) ;
-- création des matinées
INSERT INTO Calendrier (DemiJournee)
SELECT '2006-01-01' + INTERVAL U.Num + 10 * D.Num + 100 * C.Num DAY
FROM Chiffres U
CROSS JOIN Chiffres D
CROSS JOIN Chiffres C
WHERE WEEKDAY(
'2006-01-01' + INTERVAL U.Num + 10 * D.Num + 100 * C.Num DAY
) <> 6 ; -- dimanches exclus
-- création des après-midi
INSERT INTO Calendrier (DemiJournee)
SELECT DemiJournee + INTERVAL 12 HOUR
FROM Calendrier
WHERE WEEKDAY(DemiJournee) NOT IN (2, 5) ; -- mercr et samedis exclus
Il ne te reste plus qu'à éliminer les jours fériés, plus ou moins à la
main selon les cas, par ex. :
-- élimination des 14 juillet
DELETE FROM Calendrier
WHERE DemiJournee LIKE '____-07-14%' ;
1b/
Le numéro d'une demi-journée, c'est le nombre de demi-journées qu'il y a
avant elle. Nous allons donc compter les demi-journées précédent chaque
demi-journée, au moyen d'une jointure d'inégalité :
ALTER TABLE Calendrier ADD Num INT UNSIGNED DEFAULT 0 ;
UPDATE Calendrier C1
INNER JOIN (SELECT C2.DemiJournee, COUNT(*) AS Num
FROM Calendrier C2
INNER JOIN Calendrier C3 ON C2.DemiJournee > C3.DemiJournee
GROUP BY C2.DemiJournee
) AS N ON C1.DemiJournee = N.DemiJournee
SET C1.NUM = N.Num
Cette dernière requête est un peu tordue, en théorie on pourrait se
passer de la sous-requête, mais MySQL n'aime pas qu'on lise sur la table
qu'on est en train de modifier...
Et voilà !
--
Antoun
Guide complet MySQL 5, par Antoine Dinimant, éd. MicroApplication
http://www.microapp.com/livre_mysql_7873.html