Vous n'êtes pas identifié(e).
Pages :: 1
Bonjour,
J'utilisais ce code PHP :
[code php]
<?php
// Extrait d'une class
public function IsValide(){
// on récupère la date courante
$DateCourante = time();
// On récupere ce dont on a besoin
$MoisAchat = date("m", strtotime($this->DateAchat));
$AnneeAchat = date("Y", strtotime($this->DateAchat));
// On regarde quelle est l'année de fin de validité
if($MoisAchat > self::MOIS_EFFACEMENT){
$AnneeFin = $AnneeAchat + 1;
}
else{
$AnneeFin = $AnneeAchat;
}
// On compose la date de fin
$DateFin = mktime(0, 0, 0, self::MOIS_EFFACEMENT, self::JOUR_EFFACEMENT, $AnneeFin);
// On teste
if($DateFin > $DateCourante){
$Result = true;
}
else{
$Result = false;
}
return $Result;
}
?>
[/code]
Puis, j'ai décidé de le faire en sql...ce qui donne cette pale copie
[code sql]
SELECT cotisations.id
FROM cotisations
WHERE (
DATEDIFF( MAKEDATE( YEAR( cotisations.date_achat ) + IF( MONTH( cotisations.date_achat ) >7, 1, 0 ) , 180 ) , CURDATE( ) ) >0
)
[/code]
qui me retourne l'id des cotisations valide.
Je suppose que la requête SQL est meilleure, mais je voudrais savoir si on peut encore l'améliorer ?!
On note que la partie PHP n'est pas forcément idéale...
Je précise mon problème à la base :
Une personne achète une cotisation. Cette cotisation est valable jusqu'à la date du 1er juillet suivant (et avant le 1er juillet précédent...). Une carte achetée le 1er septembre 2010 est valide du 1er juillet 2010 au 1er juillet 2011.
Je veux retourner l'ensemble des cotisations valides (par rapport à la date courante).
Ce qui fait que ce que j'ai fait est faux (parce qu'une cotisation achetée le 27 juin 2015 est valide aujourd'hui...(je viens de me relire)
Dernière modification par moijhd (27-06-2010 16:27:17)
Hors ligne
Je crois que cette requête devrait te donner le résultat escompté
Maintenant je ne garantis pas les performances si l'ensemble de la clause WHERE est évalué pour chaque ligne
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Sous la même forme je propose ça :?
[code sql]
SELECT cotisations.id
FROM cotisations
WHERE IF( MONTH( cotisations.date_achat ) >7, CURDATE( )
BETWEEN STR_TO_DATE( CONCAT( YEAR( cotisations.date_achat ) , '0701' ) , '%Y%m%d' )
AND STR_TO_DATE( CONCAT( YEAR( cotisations.date_achat ) +1, '0701' ) , '%Y%m%d' ) , CURDATE( )
BETWEEN STR_TO_DATE( CONCAT( YEAR( cotisations.date_achat ) -1, '0701' ) , '%Y%m%d' )
AND STR_TO_DATE( CONCAT( YEAR( cotisations.date_achat ) , '0701' ) , '%Y%m%d' ) )
[/code]
Dernière modification par moijhd (27-06-2010 17:56:29)
Hors ligne
Sous la même forme, sûrement pas.
La structure CASE WHEN .. THEN .. ELSE .. END est conforme au standard SQL et l'alternative y est complète.
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Sous une forme conforme au standard SQL (:D), je propose ça (le 180 correspondant au 1 juillet environ) :?
[code sql]
SELECT cotisations.id
FROM cotisations
WHERE
CASE WHEN MONTH( cotisations.date_achat ) >7
THEN CURDATE( )
BETWEEN MAKEDATE( YEAR( cotisations.date_achat ) , 180 )
AND MAKEDATE( YEAR( cotisations.date_achat ) +1, 180 )
ELSE CURDATE( )
BETWEEN MAKEDATE( YEAR( cotisations.date_achat ) -1, 180 )
AND MAKEDATE( YEAR( cotisations.date_achat ) , 180 )
END
[/code]
Dernière modification par moijhd (27-06-2010 18:09:55)
Hors ligne
Et si je veux à la place de la section renvoyer un 1 ou 0 suivant que la cotisation et valide ou non ?
[code sql]
SELECT
cotisations.id,
CASE
WHEN MONTH(cotisations.date_achat) > 7
THEN
CASE
WHEN CURDATE() BETWEEN
MAKEDATE(YEAR(cotisations.date_achat), 180) AND
MAKEDATE(YEAR(cotisations.date_achat)+1, 180)
THEN 1
ELSE 0
END
ELSE
CASE
WHEN CURDATE() BETWEEN
MAKEDATE(YEAR(cotisations.date_achat)-1, 180) AND
MAKEDATE(YEAR(cotisations.date_achat), 180)
THEN 1
ELSE 0
END
END AS validite
FROM cotisations
[/code]
Dernière modification par moijhd (27-06-2010 18:19:04)
Hors ligne
Autant utiliser STR_TO_DATE(), puisque plus précis .
Et puis il me semble plus logique de tester que cotisations.date_achat se trouve dans un intervalle que CURDATE().
D'autant qu'en termes de performances les fonctions construites avec CURDATE() ne devraient probablement être évaluées qu'une fois pour toutes les lignes de la requête alors que celles construites sur cotisations.date_achat devront forcément l'être pour chaque ligne.
Si en outre la colonne cotisations.date_achat est indexée, c'est tout bénéfice.
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Ok pour STR_TO_DATE.
Pour ce qui est de la logique, je ne vois pas les choses de la même façon (et je prévois aussi que la date courante peut devenir une date quelconque) : pour moi donc, il s'agit de vérifier que la date courante est bien dans l'intervalle de validité de la cotisation.
En terme de performances, comment fait-on pour évaluer la qualité d'une requête ? Est-il mieux de passer par cette requête ou de traiter par PHP.
Aussi, comment utiliser les variables, par exemple @annee_achat, et les utiliser dans la requête.
Une autre question qui ne rentre pas vraiment dans la contexte, si j'utilise la requête précédente (sans la clause WHERE, mais avec le champ validite), comment est ce que je peux ajouter une clause WHERE validite = 1 ?
Et aussi comment faire retourne true à la requête si au moins une cotisation est valide ?
[code sql]
SELECT
cotisations.id,
cotisations.date_achat,
CASE
WHEN MONTH(cotisations.date_achat) > 7
THEN
CASE
WHEN CURDATE() BETWEEN
STR_TO_DATE(CONCAT(YEAR(cotisations.date_achat),'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(cotisations.date_achat)+1,'0701'),'%Y%m%d')
THEN 1
ELSE 0
END
ELSE
CASE
WHEN CURDATE() BETWEEN
STR_TO_DATE(CONCAT(YEAR(cotisations.date_achat)-1,'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(cotisations.date_achat),'0701'),'%Y%m%d')
THEN 1
ELSE 0
END
END AS validite
FROM
cotisations
WHERE
cotisations.id_eleve = 427
[/code]
Dernière modification par moijhd (27-06-2010 18:53:34)
Hors ligne
Bonjour,
Je pense qu'il faudrait que tu te recentres sur les bases notamment sur l'utilisation de curdate(), et que tu devrais mieux considérer la structure logique de Maljuna.
Que tu ne voyes pas les choses de la même façon que lui, c'est ton droit, mais je ne vois pas en quoi, en ce qui me concerne et dans le code suivant,
chercher à trouver des enregistrements où la date actuelle est comprise dans un intervalle passé soit logique et serve à quelque chose.
Dernière modification par Jc (28-06-2010 10:56:58)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
D'habitude je pose les problèmes d'un façon plus générale. Je vais donc changer un peu celui-ci :
On se donne des enregistrements qui comporte une date d'achat.
On considère deux variables : une date de début de validité (dépendante de la date d'achat) et une date de fin de validité (dépendante de la date d'achat).
On se place à une date quelconque.
On cherche à savoir, par exemple, combien de cotisations étaient valides à cette date.
Peut-être faut-il aussi que je change la strucuture de ma table, mais dans un premier temps, je voudrais juste résoudre ce problème.
Hors ligne
Tu reprends ma requête où tu remplaces tous les CURDATE() par ladite date quelconque.
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Ok
Hors ligne
Hey !
Je reprends le sujet pour répondre un peu au titre ^^
Est ce qu'il faut mieux faire une requête SQL de ce type :
[code mysql]
SELECT
CASE
WHEN eleves.annee >= 3
THEN 30
ELSE 60
END AS prix
FROM
eleves
WHERE
eleves.id = ".$this->IdEleve."
[/code]
ou récupérer l'année puis faire la comparaison en PHP ?
Donnez moi des éléments qui me permettent de décider dans quel cas priviligié l'un par rapport à l'autre !
Merci !
PS : jusqu'à présent, j'utilisais la deuxième méthode
Dernière modification par moijhd (03-07-2010 11:07:10)
Hors ligne
La SGBD doit être privilégié pour les calculs, les classements, les filtrages et, évidemment les jointures entre tables.
Pour te faire une idée plus précise je te conseille de lire tout ce que Frédéric Brouard (alias SQLPro) a pu écrire au sujet desSGBD épais.
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
J'ai lu (plein de choses) : c'est très intéressant, et je suis convaincu. Donc, si j'ai bien compris : SQL l'emporte ?
Hors ligne
Pour aller plus loin, y aurait-il dans ce cas un interet de créer une table avec juste les prix par exemple ?
Hors ligne
Quel cas ?
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Imaginons que je veuille déterminer le prix. A la place de faire le case, je peux préalablement créer une table avec mes différents cas ?
Table MesPrix avec les champ id_prix, prix, annee.
Puis par croisement ou jointure je dois m'en sortir ? A partir de quand un telle structure peut devenir interessante ? Elle sera de toute façon plus facilement utilisable et configurable ?
Supposons aussi que j'ai beaucoup plus de cas...
Hors ligne
De toutes façons tu as toujours intérêt à modéliser ton domaine le plus finement possible et ensuite, via le respect des formes normales, à construire ta base en utilisant toutes les facilités des SGBDR, contraintes, index, clés étrangères...
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Oui, je m'en serais douté ! Cela va changer un peu ma façon de faire les choses. Avant je n'osais pas trop.
Hors ligne
Je poursuis avec cette requête :
[code mysql]
SELECT
wei.*,
CASE WHEN wei.paye = 1
THEN
0
ELSE
130
-
(
CASE WHEN wei.acompte = 1
THEN
30
ELSE
0
END
)
-
(
SELECT
CASE
WHEN COUNT(*) >= 1
THEN 30
ELSE 0
END as nombre
FROM
cotisations
WHERE
CASE WHEN CURDATE() < STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0630'),'%Y%m%d')
THEN cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE())-1,'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d')
ELSE cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE())+1,'0701'),'%Y%m%d')
END AND
cotisations.id_eleve = wei.id_eleve
)
END AS reste
FROM
wei
WHERE
wei.id_eleve = ".$this->IdEleve."
[/code]
La structure de la table wei
[code mysql]
CREATE TABLE wei (
id int(11) NOT NULL AUTO_INCREMENT,
id_eleve int(11) NOT NULL,
bus int(1) NOT NULL DEFAULT '0',
acompte int(1) NOT NULL DEFAULT '0',
paye int(1) NOT NULL DEFAULT '0',
date_acompte datetime NOT NULL,
date_paye datetime NOT NULL,
PRIMARY KEY (id)
)
[/code]
Donc le but est de récupérer toutes les données d'un enregistrement, et de calculer reste...Est ce qu'il faut voir les choses comme je l'ai fait ? Cela me parait...lourd ?
Et si je modélise en passant par une autre table (sur 5 enregistrements cette requête est évaluée à 0.0039 s alors que la précédente est à 0.0008 s) :
[code mysql]
--
-- Structure de la table `wei_prix`
--
CREATE TABLE IF NOT EXISTS `wei_prix` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cotisation` tinyint(1) NOT NULL,
`acompte` tinyint(1) NOT NULL,
`paye` tinyint(1) NOT NULL,
`prix` int(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
--
-- Contenu de la table `wei_prix`
--
INSERT INTO `wei_prix` (`id`, `cotisation`, `acompte`, `paye`, `prix`) VALUES
(1, 0, 0, 0, 130),
(2, 0, 0, 1, 0),
(3, 0, 1, 0, 100),
(4, 0, 1, 1, 0),
(5, 1, 0, 0, 100),
(6, 1, 0, 1, 0),
(7, 1, 1, 0, 70),
(8, 1, 1, 1, 0);
--
-- La requête qui va avec ?
--
SELECT
wei.*,
(
SELECT
prix
FROM
wei_prix
WHERE
wei_prix.cotisation =
(
SELECT
CASE
WHEN COUNT(*) >= 1
THEN 1
ELSE 0
END as nombre
FROM
cotisations
WHERE
CASE WHEN CURDATE() < STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0630'),'%Y%m%d')
THEN cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE())-1,'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d')
ELSE cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE())+1,'0701'),'%Y%m%d')
END AND
cotisations.id_eleve = wei.id_eleve
) AND
wei_prix.acompte = wei.acompte AND
wei_prix.paye = wei.paye
) as reste
FROM
wei
WHERE
wei.id_eleve = ".$this->IdEleve."
--
-- AUtre requête (équivalente en temps) avec des jointures ?
--
SELECT
wei.*,
wei_prix.prix AS reste
FROM
wei
INNER JOIN
wei_prix ON
wei_prix.cotisation =
(
SELECT
CASE
WHEN COUNT(*) >= 1
THEN 1
ELSE 0
END as nombre
FROM
cotisations
WHERE
CASE WHEN CURDATE() < STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0630'),'%Y%m%d')
THEN cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE())-1,'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d')
ELSE cotisations.date_achat BETWEEN
STR_TO_DATE(CONCAT(YEAR(CURDATE()),'0701'),'%Y%m%d') AND
STR_TO_DATE(CONCAT(YEAR(CURDATE())+1,'0701'),'%Y%m%d')
END AND
cotisations.id_eleve = wei.id_eleve
) AND
wei_prix.acompte = wei.acompte AND
wei_prix.paye = wei.paye
WHERE
wei.id_eleve = ".$this->IdEleve."
[/code]
Rien n'est optimisé...
La question que je me pose maintenant : je pourrais à la place de faire la requête sur la cotisation et calculer les dates extrêmes, les enregistrer... ?
Dernière modification par moijhd (10-07-2010 10:15:44)
Hors ligne
On a du mal à suivre.
Plutôt qu'un post fourre-tout comme celui-ci est en train de devenir, repose ta question dans un post tout neuf en prenant le temps de décrire succintement le contexte.
J'interviens //ment sur deux ou trois autres forums, plus ceux de mon boulot, plus mon boulot.
Bref, je ne peux pas mémoriser tous ces tropismes.
Gloire à qui n'ayant pas d'idéal sacro-saint,
Se borne à ne pas trop emmerder ses voisins. G. Brassens Don Juan 1976.
Avĉjo MoKo kantas
La chaîne YouTube MoKo Papy
Hors ligne
Bonsoir,
Je plussoie la proposition de maljuna^^
A bientôt de te lire. Pense à donner un algorithme propre et clair (opti).
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Hors ligne
Pages :: 1