Vous n'êtes pas identifié(e).
Bonjour,
Ce post est en partie la suite de celui-ci : http://forum.phpdebutant.org/viewtopic.php?pid=63882, mais sa connaissance n'est pas requise pour ce qui suit.
Pour une même action, je peux choisir plusieurs requêtes qui me retournent toutes le même résultat. La question de de savoir laquelle est la meilleure, ou d'en proposer une meilleure.
Il a été établi au poste précédent que la requête suivante permet de dire si l'élève est cotisant ou pas (elle peut toujours être critiquée) :
[code mysql]
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 = ".$this->IdEleve."
[/code]
Il s'agit maintenant de déterminer un prix suivant trois facteurs : la cotisation, l'acompte, le paiment.
La table ci-dessous représente les différents cas :
[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);
[/code]
La table dans laquelle sont enregistrés les champ acompte et paye (cotisation étant obtenu avec la première requête) :
[code mysql]
--
-- Structure de la table `wei`
--
CREATE TABLE IF NOT EXISTS `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`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=6 ;
[/code]
Comment composer la meilleure requête ?
Vous trouverez mes propositions ici : http://forum.phpdebutant.org/viewtopic. … 032#p65032. Cependant, dans ces cas, si l'enregistrement n'existe pas, la requête ne renvoit rien alors que je voudrais qu'elle retourne prix = 130.
Merci !
Dernière modification par moijhd (10-07-2010 18:55:07)
Hors ligne
Peux-tu nous expliciter clairement la finalité des colonnes `cotisation`, `acompte` et `paye`de la table `wei_prix` ?
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
Des booleens. Si il y a cotisation et acompte alors le prix est 70 (cas 7).
Cette table n'est pas forcément à utiliser. Elle représente les différents prix suivant la valeur des booleens cotisation, acompte et paye.
Hors ligne
Bonjour,
Juste une info concernant l'utilisation de TINYINT comme valeur booléenne. Sur le principe cela fonctionne au niveau mysql tant sur une clause where ou update (set status=false / set status=true / respectivement 0 et 1 sur mySQL) mais le souci est qu'une telle colonne autorise l'attribution d'autres valeurs que 0 et 1 et que cela peut poser des problèmes de traitement. Sans parler des languages de prog qui considèrent que false=-1 et qui à ce moment là n'est plus gérable niveau requête. Il vaut mieux passer par une définition de champ à mon sens telle que 'T' et 'F' sur un champ ENUM qui rends possible les traitements quels que soient les languages de programmation utilisés et qui protège tes données si une valeur incorrecte de champ est tentée d'être passée via une requête bugée.
PS: si tu ne veux pas passer par un champ de type enum, la seule possibilité est de définir un champ de type BOOL dont TINYINT(1) est l'équivalent et non int(1).
Dernière modification par Jc (11-07-2010 10:45:08)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Re,
Un petit conseil aussi dans ta vision de définition de requête. Tu n'as pas forcément besoin que ta requête te donne le montant du prix pour savoir si il y a eu cotisation et/ou accompte d'autant que dans ta dernière requete tu lui demandes de retourner qu'un seul enregistrement car tu fais une recherche sur ta clé primaire id_eleve=x . Dans ce cas particulier ta clause where case... est obsolète car elle n'aurait d'intérêt que dans le but de filtrer l'ensemble du fichier disponible. De plus dans ce dernier cas, ce genre de filtre en production n'est généralement utilisé que pour générer des alertes client au niveau des consoles d'administration (relances, rappels, ...). Donc ces alertes se font à chaque fois sur un seul critère (cotisation ou accompte).
A moins que ton ton rendu souhaité soit purement un exercice de style théorique, je pense que de recadrer tes requêtes dans un contexte d'exploitation te permettrais une meilleure opti et donc une simplification de tes requêtes.
voilou
Dernière modification par Jc (11-07-2010 10:39:21)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Disons que j'aime beaucoup l'exercice théorique
Revenons à cette requête qui est la version naive du problème (d'après moi...) :
[code mysql]
SELECT
CASE WHEN COUNT(*) = 0
THEN 130
ELSE
CASE WHEN wei.paye = true
THEN
0
ELSE
130
-
(
CASE WHEN wei.acompte = true
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
END AS prix
FROM
wei
WHERE
wei.id_eleve = ".$this->IdEleve."
[/code]
Dernière modification par moijhd (11-07-2010 10:57:15)
Hors ligne
Tout d'abord, tu dois privilégier le tri sur la clé primaire si tu as besoin de recup l'info sur la personne considérée. Tu déclares ensuite les champs cotisation, accompte, paye dans ta clause select et concernant la valeur de prix tu le calcule en fonction des précédents via une clause case. La seule condition que l'on doit trouver dans ta clause where dans ce cas c'est donc "where id_eleve=x."
Dernière modification par Jc (11-07-2010 10:53:27)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
ah j'oubliais, conformément à mes posts précédents, il ne faut pas écrire wei.accompte=1 mais wei.accompte=true, et idem pour le reste.
PS/EDIT : si tu veux savoir en plus si l'eleve en cours à un abo en cours de validité, tu rajoutes une colonne dans select et tu appliques la même methode sur la colonne que pour ta colonne prix.
Dernière modification par Jc (11-07-2010 11:00:06)
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne
Up sur la dernière requête mise à jour en partie :
http://forum.phpdebutant.org/viewtopic. … 192#p65192
Je fais la recherche sur une personne en particulier.
Je prépare une autre requête avec plus d'opérateur logique.
Hors ligne
EN évitant les deux recherches sur la cotisation (je ne sais pas comment faire...) ?
[code mysql]
SELECT
CASE WHEN COUNT(*) = 0
THEN 130
ELSE
CASE WHEN wei.paye = true
THEN
0
ELSE
CASE WHEN
wei.acompte XOR
(
SELECT
CASE
WHEN COUNT(*) >= 1
THEN true
ELSE false
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
)
THEN 100
ELSE
CASE WHEN
wei.acompte AND
(
SELECT
CASE
WHEN COUNT(*) >= 1
THEN true
ELSE false
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
)
THEN 70
ELSE 130
END
END
END
END AS prix
FROM
wei
WHERE
wei.id_eleve = ".$this->IdEleve."
[/code]
Dernière modification par moijhd (11-07-2010 11:10:44)
Hors ligne
Rappel de cette table de vérité :
Il suffirait maintenant de faire une jointure entre la table wei et la table wei_prix dont la clause ON vérifierait la correspondance entre les colonnes `acompte`et `paye` ainsi que l'adéquation entre `cotisation` et la première requê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
?
[code mysql]
SELECT
CASE WHEN COUNT(*) = 0
THEN
130
ELSE
wei_prix.prix
END AS prix
FROM
wei_prix
INNER JOIN
wei ON
wei_prix.acompte = wei.acompte AND
wei_prix.paye = wei.paye AND
wei_prix.cotisation = (
SELECT
CASE
WHEN COUNT(*) >= 1
THEN true
ELSE false
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
)
WHERE
wei.id_eleve = ".$this->IdEleve."[/code]
Dernière modification par moijhd (11-07-2010 11:38:11)
Hors ligne
Je crois que tu la tiens.
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
je dois venir d'un autre monde
j'entrave ketchick :(:
a++
Hors ligne
Ma question dans ce post était de savoir qu'elle était la meilleure méthode : c'est donc celle qui consiste à passer par une table intermédiaire (ma table logique) ? Par rapport à mes soustractions successives ? Par rapport à mes select imbriqués ?
Je pose beaucoup de questions : ce sont mes premières requêtes un peu complexe.
Dernière modification par moijhd (11-07-2010 18:28:42)
Hors ligne
D'après toi ?
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
Et bien, cette structure me permet de bien gérer les données (en particulier les prix), je peux assez facilement la changer si je dois faire évoluer les cas. La requête est assez bien lisible. Je ne sais pas si ce sont les bons arguments pour cette méthode !
Merci !
Et a bientôt pour une nouvelle requête ^^
Hors ligne
Bonsoir,
parfois je me demande si les réponses aux questions sont prises en considération ou si celui qui pose la question fait l'effort de comprendre les réponses. Visiblement vu la dernière réponse de ce post, ca n'a pas l'air de poser de problèmes^^.
Bonne continuation à toi dans ta recherche de requêtes^^.
POO PHP+Ajax en MVC avec PDO et Bases de données épaisses : What else?
Hors ligne