problème de mode MySQL

Eléphant du PHP | 377 Messages

06 sept. 2007, 20:04

Hello les gens
J'ai un problème depuis la mise à jour de mon serveur mysql. J'explique :
Je stocke des durées sous la forme d'un champ date (par exemple trois mois = '0000-03-00')
Jusqu'ici, tout marchait très bien sauf que depuis la version 5.0.2, mysql vérifie automatiquement la validité des dates avant de les insérer/traiter (j'utilise MySQL 5.0.27)

donc, par exemple

Code : Tout sélectionner

SELECT MONTH('0000-03-00')
qui me retournait jusqu'à maintenant 3 me renvoie désormais NULL, ce qui fout toute la suite de mon code en l'air

Après quelques recherches, il semblerait qu'on puisse désactiver ce comportement en effectuant un

Code : Tout sélectionner

SET sql_mode='ALLOW_INVALID_DATES'
Sauf que vous vous en doutez bien, ca ne marche toujours pas ^^

Quelqu'un a-t-il une idée?
Petit scarabée deviendra grand

ViPHP
ViPHP | 2144 Messages

07 sept. 2007, 01:48

Deux idées en vrac:
- Changer le type de champs pour utiliser quelques choses de plus naturel : un champ int pour le nombre de mois (en plus ça ferait une économie de place dans la base de donnée)
- Ajouter une année et un jour bidon dans toutes les dates pour qu'elles soient valides (pas très beau comme solution)

Eléphant du PHP | 377 Messages

07 sept. 2007, 11:30

Mouais, sauf que dans l'exemple donné, la durée est de trois mois, mais dans l'enregistrement d'après elle peut etre de 7 jours et dans le suivant d'un an et demi (c'est une table d'abonnements en fait)
Ce que j'ai fait pour l'instant c'est remplacer la date par un varchar et le couper à la main, mais c'est pas beau :(
Donc si d'autres idées passent par ici, je prends :D
Petit scarabée deviendra grand

ViPHP
ViPHP | 2144 Messages

07 sept. 2007, 11:37

Si la plus petite unité, est le jour tu peux stocker un nombre de jours.
Maintenant rien ne t'empêche d'utiliser un timestamp (voir la doc pour plus d'infos)

ViPHP
ViPHP | 1380 Messages

07 sept. 2007, 11:58

Tu dois bien avoir une date de début d'abonnement non? Si oui, il te faudra extraire de ta colonne actuelle la durée de l'abonnement et ensuite faire un calcul de fin avec les fonctions MySQL:

Code : Tout sélectionner

SELECT DATE_ADD('2007-09-05', INTERVAL 3 MONTH); SELECT DATE_ADD('2007-09-05', INTERVAL 150 DAY); SELECT DATE_ADD('2007-09-05', INTERVAL 2 YEAR); SELECT DATE_ADD('2007-09-05', INTERVAL 2 WEEK);
Voir http://dev.mysql.com/doc/refman/5.0/fr/ ... n_date-add

La difficulté va être de récupérer les durées sous son ancien format et de les convertir en nombres de DAY MONTH YEAR etc...

Pas impossible. Donne-nous quelques exemple de ces durées pour voir.
ripat

Eléphant du PHP | 377 Messages

07 sept. 2007, 13:40

@iclo : non, la plus petite unité n'est pas le jour étant donné qu'un abonnement d'un mois pris le 2 février ne fera que 28 jours (voire 29 pour une année bissextile) alors que le même abonnement pris en juillet durera 31 jours...

@ripat : bah la date de début d'abonnement, c'est le jour où on s'abonne...
En fait je définis ma table des abonnements (prix, durée, nom...)
Puis au moment où je choisis mon abonnement je fais ceci :
	$requeteverifvalue=mysql_query("SELECT duree_abonnement,id_abonnement,nb_par_pro 
FROM abonnements WHERE id_abonnement=\"".mysql_real_escape_string($_GET['id'])."\"") or exit(mysql_error());
	if(mysql_num_rows($requeteverifvalue) >0) {
		$r=mysql_fetch_assoc($requeteverifvalue);
		$sql="INSERT INTO pros_abonnements 
SET id_pro='".$_SESSION['id_pro']."', id_abonnement='".$r['id_abonnement']."', date_debut_abonnement=NOW(), 
date_fin_abonnement=DATE_ADD(DATE_ADD(DATE_ADD(NOW(), INTERVAL DAY('".$r['duree_abonnement']."') DAY), 
INTERVAL MONTH('".$r['duree_abonnement']."') MONTH), INTERVAL YEAR('".$r['duree_abonnement']."') YEAR)";
        }
J'ai simplifié un peu, mais c'est l'idée
Donc dans ce cas précis, étant donné que $r['duree_abonnement'] n'est pas une date valide, les fonctions DAY(), MONTH() et YEAR() me renvoient NULL, donc les DATE_ADD() s'affolent et le tout plante :(
Petit scarabée deviendra grand

Eléphant du PHP | 124 Messages

08 sept. 2007, 03:46

Alors inclus un TIMESTAMP !
Et ça se gèrera facilement avec PHP après.

Modérateur PHPfrance
Modérateur PHPfrance | 6373 Messages

08 sept. 2007, 13:28

@iclo : non, la plus petite unité n'est pas le jour étant donné qu'un abonnement d'un mois pris le 2 février ne fera que 28 jours (voire 29 pour une année bissextile) alors que le même abonnement pris en juillet durera 31 jours...
La plus petite unité est donc le jour :)
Ici, 28 ou 31 unités...

À moins qu'on puisse s'abonner pour moins de 24 heures...

Eléphant du PHP | 377 Messages

08 sept. 2007, 15:13

Ce que je veux dire c'est que je ne peux pas prévoir un abonnement différent selon quel jour on s'abonne (je ne sais pas si je me fais bien comprendre :? )
Les abonnements étant (par exemple) du 5/X au 5/Y, selon quels sont X et Y, l'abonnement durera 28, 29, 30 ou 31 jours
Je pense que la solution la plus simple (même si elle ne me plait pas) et de stocker la date en varchar et de la traiter à la main... à moins que quelqu'un sache comment désactiver cette #!@grumpf! de vérification
Petit scarabée deviendra grand

ViPHP
ViPHP | 2144 Messages

08 sept. 2007, 18:29

Je dois avouer que je ne comprends pas bien ce que tu dois stocker comme informations, ni pour quel usage:
La durée de tes abonnements est en mois ? si oui pourquoi ne pas stocker cette durée dans un entier ?
Quitte à stocker la date de début, pour pouvoir calculer la date de fin, si nécessaire.

Eléphant du PHP | 377 Messages

08 sept. 2007, 19:37

La durée est en mois, ou en année, ou en jours (offre promotionnelle d'une semaine par exemple)
J'aurais effectivement la possibilité de stocker dans trois champs différents la durée en années, mois et jours, mais disons qu'avant que ce probleme ne se pose, je trouvais que le fait de stocker ces durées sous un format YYYY-MM-DD était non seulement pratique mais me semblait en plus logique...
Après, j'ai peut etre une logique toute personnelle :lol:
Enfin apparemment il va falloir que je bricole pour arriver au même résultat, j'ai commencé à me faire à l'idée ;)
Petit scarabée deviendra grand

ViPHP
ViPHP | 2144 Messages

08 sept. 2007, 20:06

Si tu as besoin de connaitre la date de fin, pourquoi ne pas la calculer une fois pour toute, à partir de la date de début et de la durée ? (Il y a toutes fonctions de manipulations de date nécessaire pour faire ça simplement)
Pour te proposer une solution adaptée à ton problème, il faudrait surtout qu'on sache à quoi vont te servir ces données, et donc sous quel formes du devra les récupérer.

Je ne vois pas trop de raisons de passer par des solutions bricolées, source de problèmes, et surtout très difficiles à modifier par après, notamment si on veut ajouter de nouvelles fonctionnalités.
Un bonne solution (pour ne pas dire une solution acceptable) doit permettre une certaine souplesse d'évolution dans le futur. (On voit très souvent des dévellopeurs bloqués avec des bases de données bancales, dans l'obligation de modifier de gros volumes de données, suite à une erreur de conception antérieure)

Eléphant du PHP | 377 Messages

08 sept. 2007, 22:07

Si tu as besoin de connaitre la date de fin, pourquoi ne pas la calculer une fois pour toute, à partir de la date de début et de la durée ?
C'est justement ce que je fais! lol
Voici la structure (simplifiée) de ma base :

1) abonnements
id_abonnement
duree

2) abonnes
id_abonne

2) abonnes_abonnements
id_abonne
id_abonnement
date_debut
date_fin

Donc comme je l'ai dit plus haut, au moment de la souscription de l'abonnement, je calcule la date de fin d'abonnement en fonction de la durée

Code : Tout sélectionner

date_fin_abonnement = DATE_ADD(DATE_ADD(DATE_ADD(NOW(), INTERVAL DAY(duree) DAY), INTERVAL MONTH(duree) MONTH), INTERVAL YEAR(duree) YEAR)
sauf que maintenant, duree, qui auparavant était un champ de type DATE, ne peut plus contenir de date invalide...
Donc avec des découpages de varchar je devrais pouvoir m'en sortir...
Petit scarabée deviendra grand

ViPHP
ViPHP | 2144 Messages

09 sept. 2007, 00:51

Oui, mais une durée, est d'une seule unité: X mois ou Y jours, mais pas X mois + Y jours, non ?

Eléphant du PHP | 377 Messages

09 sept. 2007, 09:19

en pratique oui, tu as soit un mois soit une semaine soit un an
mais en théorie, qu'est-ce qui empeche d'avoir un abonnement d'un mois et 3 jours?
Petit scarabée deviendra grand