Besoin de conseils pour créer une base mysql

Besoin de conseils pour créer une base mysql - SQL/NoSQL - Programmation

Marsh Posté le 10-09-2005 à 19:36:16    

Bonjour à tous.
 
J'ai besoin de quelques conseils concernant la création d'une base de données avec mysql / debian / php / phpmyadmin / apache
C'est surtout au niveau du princique que j'ai besoin d'aide.
Avec apache, j'ai déjà mysql qui fonctionne correctement avec phpmyadmin sur une debian.
 
Voici un exemple de ce que j'aimerai avoir comme base de données :
 
http://mams51.free.fr/photos/base_pain.gif
 
Le but est dans cet exemple de répertorier tous les prix des produits que l'on trouve chez les boulangers. (c'est une idée bizzare mais c'est juste pour avoir un exemple  :D  )
Chaque entrée dans la base correspond à un produit chez un boulanger. Le même produit peux se retrouver plusieur fois chez un même boulanger dans le cas ou il y aurait un changement de prix. A chaque fois j'enregistre la date de la mise à jour du prix.
Je souhaite conserver les anciens prix afin de pouvoir tracer un historique.
 
Le but final de cette base est de pouvoir proposer à un utilisateur de trouver le prix d'une baguette (ou autre) dans sa ville et au meilleur prix.
 
Mon problème est de savoir comment organiser cette base. Je suppose qu'il faut plusieurs tables, des clés étrangères grace à InnoDB.
Vous remarquerez que les villes seront citées plusieur fois, les départements aussi, les enseignes aussi, les types de produits aussi...  faut'il une base pour chacun de ces éléments ?
 
Merci pour vos premiers conseils


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 10-09-2005 à 19:36:16   

Reply

Marsh Posté le 11-09-2005 à 02:12:45    

Typiquement, tu vas avoir trois tables et non une seule !
 
Une table "boulangerie" :
id
enseigne
adresse
ville
département
 
(tu pourrais t'amuser à faire une table supplémentaire pour mettre les villes et les départements à part mais je doute que ce soit très utile)
 
table produit :
id
nom
 
table prix :
id_boulangerie
id_prix
nom_de_la_personne_qui_a_constate_le_prix (tu peux essayer de faire plus long aussi :D)
date
 
tu peux aussi ajouter une 4° table pour sortir la personne ayant constaté le prix dans une table séparée, surtout si des personnes doivent pouvoir indiquer les prix dans la base via un profile

Reply

Marsh Posté le 11-09-2005 à 12:18:06    

Merci, j'y vois un peu plus claire... mais d'autres questions me viennent à l'esprit.
 
 
table "boulangerie"
-id_boulang
-enseigne
-adresse
-ville
-département
 
si je ne fais pas de table spéciale pour les villes, comment je vais pouvoir offrir à l'utilisateur la possibilité de choisir son département et sa ville ?
 
 
 
table "produits"
-id_produit
-nom_produit  
 
utile même si je ne référence que 5 produits maxi ?
 
 
 
table "prix"
-id_prix
-nom_de_la_personne_qui_a_constate_le_prix
-date
-id_boulangerie clé étrangère innodb ?
-id_produit clé étrangère innodb ?
 
Merci de m'apporter quelques précisions   :hello:


Message édité par Mams le 11-09-2005 à 13:18:43

---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 11-09-2005 à 13:26:17    

Soit un champ libre (ce que je te conseille), soit une liste générée à partir d'un "select distinct ville, departement from boulangerie".
 
Ceci dit, tu auras le même problème avec des tables spécifiques ville et departement.
 
Recherche dans le forum "autocomplete script", j'avais fait un contrôle en JS compatible avec n'importe quel langage serveur permettant de faire une liste déroulante saisissable.

Reply

Marsh Posté le 11-09-2005 à 13:29:10    

la table produit me semble très importante en effet, afin de ne pas te retrouver avec des lignes "croissant" et "croissants", ou "pain au chocolat" et "chocolatine".
Il faut savoir qu'outre les fautes de frappe, d'une ville à l'autre les mêmes produits des boulangeries ont des noms différents.
 
Le mieu étant avec les baguettes !
 
En côte d'or :
- Flûte : la toute petit baquette très fine
- Petite baguette
- Grosse baguette
 
A paris :
- Flûte : idem
- Baguette = petite baquette
- Pain = grosse baguette
 
Et dans le nord, ce sera encore différent, dans le sud aussi, à l'ouest... etc.

Reply

Marsh Posté le 11-09-2005 à 13:29:24    

Et oui, les lignes en bleu sont des foreign keys

Reply

Marsh Posté le 12-09-2005 à 10:32:05    

Merci Arjuna pour ton aide précieuse.
Voici les tables que j'ai créées en fonction des tes conseils et des infos que j'ai pu glaner sur quelques sites.
 
table "boulangeries"
-id_boulangerie
-boulangerie (son nom)
-id_enseigne
-adresse
-ville
-departement
-emplacement (pour plus tard - un lien vers Mappy peut-être)
 
table "enseignes"
-id_enseigne
-enseigne
 
table "noms"  (qui collectera le nom et le passe des utilisateurs enregistrants les nouveau prix)
-id_nom
-nom
-passe
 
table "produits"
-id_produit
-produit
 
table "tarifs"
-id_tarif
-tarif
-id_produit
-id_boulangerie
-date
-id_nom
 
Pour info, j'ai laissé tomber les foreign keys puisque j'ai lu dans un article que cela ne servait pas à joindre des données mais juste à aider dans la maintenance.
 
Mon problème maintenant est plus d'ordre technique que d'organisation comme avant.
Je suis parvenu à trouver sur de nombreux sites, comment afficher les infos de 2 tables, notamment avec la commande LEFT JOIN mais je galère pour trouver des infos concernant la jointure de plusieurs tables.
 
Avec mes tables, je dois déjà joindre les boulangeries avec les enseignes et ensuite dans la table tarifs je dois joindre toutes les autres données. Et là, je cale.
Un peu d'aide serait la bienvenue.


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 16-09-2005 à 09:55:48    

Pour info, la solution semblerait se trouver du coté de "NATURAL JOIN".
Cette commande permet de joindre les tables en utilisant les colonnes portants le même nom.
 
Bon maintenant je vais m'attaquer aux liste déroulantes avec PHP... je sens que je vais galèrer du fait des jointures  :pt1cable:


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 16-09-2005 à 10:18:21    

Extrait de la page sur les jointure de la doc de mysql :

Citation :

La clause USING (column_list) recense la liste des colonnes qui doivent exister dans les deux tables. Les clauses USING suivantes sont identiques :  
a LEFT JOIN b USING (c1,c2,c3)a
LEFT JOIN b ON a.c1=b.c1 AND a.c2=b.c2 AND a.c3=b.c3


Message édité par omega2 le 16-09-2005 à 10:18:37
Reply

Marsh Posté le 17-09-2005 à 00:09:37    

Merci pour cette précision, mais maintenant que j'ai réussi à utiliser NATURAL JOIN et que ça fonctionne correctement (il me semble) je n'y touche plus  :D  
 
Bon bah avant d'attaquer les listes déroulantes, je me heurte à un nouveau problème.
 
Voici ma requete :

Code :
  1. $requete = mysql_query("SELECT *
  2. FROM enseignes NATURAL JOIN boulangeries NATURAL JOIN tarifs NATURAL JOIN produits NATURAL JOIN noms
  3. WHERE produits.produit='baguette' AND boulangeries.ville='paris'
  4. ORDER BY tarifs.tarif" );


Le résultat me donne bien la liste des prix dans l'ordre croissant pour les baguettes dans les boulangeries de la ville choisie.
Mais elle me donne tous les prix de chaque mise à jour de prix alors que j'aimerai n'avoir que le prix de la date de mise à jour la plus récente !
 
j'ai tenté  :

Code :
  1. ORDER BY tarifs.date DESC LIMIT 1 ORDER BY tarifs.tarif


mais évidement cela ne fonctionne pas puisque ORDER BY ne peux être utilisé 2 fois.
 
j'ai alors testé un truc du style :
 

Code :
  1. ORDER BY  tarifs.date DESC LIMIT 1, tarifs.tarif


Pas mieux !
Vous avez une idée ?
A savoir que j'ai aussi regardé MAX mais sans trouver de formule adéquate.
Merci d'avance pour votre aide !


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 17-09-2005 à 00:09:37   

Reply

Marsh Posté le 18-09-2005 à 23:13:22    

Je n'avance plus...  :??:  
 
un peu d'aide s'il vous plait !


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 19-09-2005 à 19:46:30    

Quelle version de MySQL ?
 
Sinon, perso, je déteste la notation avec le mot-clé "JOIN" pour faire des jointures. Certains SGBD ne la supportent d'ailleurs pas (les anciennes versions d'Oracle par exemple) et je trouve ça très bien :)
 
Donc ta requête, je ne la ferais pas comme ça mais :
(d'autant plus que le NATURAL JOIN est à éviter, car il se base sur le Foreign Keys : s'il y a deux FK pointant sur la même table, il ne sait pas laquelle prendre et ça peut faire n'importe quoi !)

Code :
  1. SELECT *
  2. FROM noms, enseignes, boulangeries, tarifs, produits
  3. WHERE produits.produit='baguette'
  4. AND tarifs.id_produit = produits.id_produit
  5. AND boulangeries.id_boulangerie = tarifs.id_boulangerie
  6. AND boulangeries.ville='paris'
  7. AND enseignes.id_enseigne = boulangerie.id_enseigne
  8. AND noms.id_nom = tarifs.id_nom
  9. ORDER BY tarifs.tarif


 
Bon, ça, c'est le début.
 
Ensuite, si tu as une version récente de MySQL ( >= 4.1 il me semble) alors tu peux faire :
 
 

Code :
  1. SELECT *
  2. FROM noms n, enseignes e, boulangeries b, tarifs t, produits p
  3. WHERE p.produit='baguette'
  4. AND t.id_produit = p.id_produit
  5. AND t.id_tarifs =
  6. (
  7.    select max(t2.id_tarifs)
  8.    from tarifs t2
  9.    where t2.id_produit = t.id_produit
  10.    and t2.id_boulangerie = t.id_boulangerie
  11.    and t2.id_nom = t.id_nom
  12.    and t2.date =
  13.    (
  14.       select max(t3.date)
  15.       from tarifs t3
  16.       where t3.id_boulangerie = t2.id_boulangerie
  17.       and t3.id_produit = t2.id_produit
  18.       and t3.id_nom = t2.id_nom
  19.    )
  20. )
  21. AND b.id_boulangerie = t.id_boulangerie
  22. AND b.ville='paris'
  23. AND e.id_enseigne = b.id_enseigne
  24. AND n.id_nom = t.id_nom
  25. ORDER BY t.tarif


 
Voilà :)
 
Ca, c'est pour le cas où tu stockes la date uniquement au format "date" et non "datetime" (c'est à dire avec seulement le jour, pas les heures)
 
Explication :
-> Tu fais ta requête initiale
-> Tu la filtre en ne prenant que les tarifs sasis pour chaque triplet (id_boulangerie, id_produit, id_nom) de la ligne en cours, pour lesquels la date de mise à jour est la plus récente. Et vu que si tu ne stockes pas l'heure, tu peux avoir des doublons, tu refiltres sur l'id_tarif le plus grand (donc logiquement le plus récent) afin d'avoir réellement la dernière ligne mise à jour.


Message édité par Arjuna le 19-09-2005 à 19:48:07
Reply

Marsh Posté le 20-09-2005 à 13:18:08    

Merci pour ton aide précieuse Arjuna.
Je viens de mettre à jour ma version de Mysql. J'étais en 3.23  :pfff:  Maintenant je suis en 4.1.11
Mon format de date est "datetime" et je n'utilise pas de "foreign keys".
 
Mon but est d'afficher les prix d'un produit dans l'ordre croissant pour chaque boulangerie d'une ville et uniquement avec la dernière mise à jour.
Ce qui permettra à un utilisateur de trouver le meilleur prix pour sa baguette de pain dans sa ville.
 
En suivant tes explications, j'ai pondu ce code :
 

Code :
  1. $requete = mysql_query("SELECT *
  2. FROM enseignes e, boulangeries b, tarifs t, produits p, noms n
  3. WHERE t.date =
  4. (
  5.  SELECT MAX(t2.date)
  6.  FROM tarifs t2
  7.  WHERE t2.id_nom = t.id_nom
  8.  AND t2.id_produit = t.id_produit
  9.  AND t2.tarif = t.tarif
  10.  AND t2.id_boulangerie =
  11.  (
  12.   SELECT DISTINCT(t3.id_boulangerie)
  13.   FROM tarifs t3
  14.   WHERE t3.id_produit = t2.id_produit
  15.   AND t3.id_nom = t2.id_nom
  16.  )
  17. )
  18. AND b.id_enseigne = e.id_enseigne
  19. AND t.id_nom = n.id_nom
  20. AND t.id_boulangerie = b.id_boulangerie
  21. AND t.id_produit = p.id_produit
  22. ORDER BY t.tarif" );


 
Mais cela ne fonctionne pas  :(  J'ai une erreur lors du "fetch_array"  Je me suis planté où ?


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 20-09-2005 à 14:20:48    

je regarderai ce soir, là je suis au boulot et j'ai pas le temps :)
 
mais je pense à toi ;)

Reply

Marsh Posté le 20-09-2005 à 16:34:09    

Cool, merci  :jap:


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 20-09-2005 à 16:58:48    

si tu es sous php utilise la fonction mysql_error() pour voir l'erreur généré

Reply

Marsh Posté le 20-09-2005 à 17:29:47    

Merci pour l'info, c'est vrai que ça peut aider  :)  
Voici ce que j'ai ajouter juste après "ORDER BY t.tarif" );"

Code :
  1. echo mysql_errno($connexion)." __ ".mysql_error($connexion);


Et voici le résultat : 1242 __ Subquery returns more then 1 row


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 20-09-2005 à 17:53:42    

La sous requete renvoy plus d'un résultat. Cela ne peut pas fonctionner.

Reply

Marsh Posté le 20-09-2005 à 17:57:10    

utiliser un = si la sous requette retourne 1 seule valeur
utiliser "in" si ca en retourne plusieurs.


Message édité par omega2 le 20-09-2005 à 17:57:26
Reply

Marsh Posté le 20-09-2005 à 19:55:48    

Je crois que t'as rien panné à ma requête :o
 
Copie simplement ma requête et regarde ce qu'elle te retourne. Normalement, elle est bonne, j'ai beau chercher, je ne vois pas en quoi elle ne répond pas à ton problème :p (et gère les insertions par lot, genre 2 personnes qui saisissent un prix pour un même produit, une même boulangerie, et au même instant T au quart de pouillème de microseconde près - cas typique lors d'une intégration de fichier notamment)

Reply

Marsh Posté le 20-09-2005 à 19:56:40    

En fait t'as juste à virer mes clauses sur produit et ville, qui ne retournent que les baquettes à paris.

Reply

Marsh Posté le 20-09-2005 à 19:57:25    

quoique non, t'as pas à les virer, puisque c'est par ce couple que tu veux faire tes filtres

Reply

Marsh Posté le 20-09-2005 à 20:01:18    

Citation :

AND t2.id_boulangerie =  
        (  
            SELECT DISTINCT(t3.id_boulangerie)  
            FROM tarifs t3  
            WHERE t3.id_produit = t2.id_produit  
            AND t3.id_nom = t2.id_nom

        )

Je ne vois rien dans cette partie qui limite le résultat à une seule ligne. [:atlantis]
Donc ne pas mettre un = devant ce select.  

Reply

Marsh Posté le 20-09-2005 à 22:41:39    

surtout, la requête ne retournera de toute façon pas ce qu'il veut.
 
j'me tue à vous le dire :o
 
faut utiliser la mienne :p

Reply

Marsh Posté le 20-09-2005 à 22:55:11    

Arjuna > Par expérience, j'ai pas besoin de lire sa requette pour savoir que dés qu'il aura sufisament de données, il aura plus qu'a lancer sa requette et se coucher par ce qu'il aura pas le résultat avant le lendemain.
En plus vu son erreur dans la requette, je suis pas aller jusqu'a regarder si sa requette risquait de lui retourner le bon résultat. ;)

Message cité 1 fois
Message édité par omega2 le 20-09-2005 à 22:56:38
Reply

Marsh Posté le 20-09-2005 à 23:12:00    

Arjuna a écrit :

Je crois que t'as rien panné à ma requête :o

Hi hi, je croyais avoir compris mais vu que je débute, je plane totalement !

omega2 a écrit :

Je ne vois rien dans cette partie qui limite le résultat à une seule ligne. [:atlantis]
Donc ne pas mettre un = devant ce select.

J'ai remplacé "=" par "IN" pour la 2ième sous requete et ça m'a sorti toutes les entrées de la tables tarifs  :??:  
-
-
-
-
-
-
-Plus tard pendant l'écriture de ce message j'ai relu tes explications Arjuna

Arjuna a écrit :

-> Tu la filtre en ne prenant que les tarifs sasis pour chaque triplet (id_boulangerie, id_produit, id_nom) de la ligne en cours, pour lesquels la date de mise à jour est la plus récente

-
-
-
-
-Et je pense avoir compris

Code :
  1. $requete = mysql_query("SELECT *
  2. FROM enseignes e, boulangeries b, tarifs t, produits p, noms n
  3. WHERE t.date =
  4. (
  5.  SELECT MAX(t2.date)
  6.  FROM tarifs t2
  7.  WHERE t2.id_produit = t.id_produit
  8.  AND t2.id_boulangerie = t.id_boulangerie
  9. )
  10. AND b.id_enseigne = e.id_enseigne
  11. AND t.id_nom = n.id_nom
  12. AND t.id_boulangerie = b.id_boulangerie
  13. AND t.id_produit = p.id_produit
  14. AND p.produit = 'baguette'
  15. ORDER BY t.tarif" );

Il me semble que ça fonctionne correctement. Mais il va falloir que je remplisse un peu mes tables pour êtres 100% sur que ce soit Ok.
Un grand merci pour votre aide et plus particulièrement à Arjuna.  :jap:  
 
Je m'attaque donc maintenant aux listes déroulantes PHP. Ne partez pas trop loin, je risque d'avoir besoin de vous d'ici peu de temps  :D  
 
Tchao  :hello:


---------------
Je me lève de bonne humeur
Reply

Marsh Posté le 22-09-2005 à 13:57:40    

omega2 a écrit :

Arjuna > Par expérience, j'ai pas besoin de lire sa requette pour savoir que dés qu'il aura sufisament de données, il aura plus qu'a lancer sa requette et se coucher par ce qu'il aura pas le résultat avant le lendemain.
En plus vu son erreur dans la requette, je suis pas aller jusqu'a regarder si sa requette risquait de lui retourner le bon résultat. ;)


Par expérience (bon, avec Oracle et SQL Server, certes), ce type de requête est très rapide normalement.

Reply

Marsh Posté le 22-09-2005 à 13:59:22    

Le problème des sous-requêtes, c'est quand elle rammènent plusieurs lignes (ici ce n'est pas le cas) et filtrent sur des données différentes de la requête principale (ce n'est toujours pas le cas ici).

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed