MySQL : Problème de liste récursive

MySQL : Problème de liste récursive - SQL/NoSQL - Programmation

Marsh Posté le 20-10-2006 à 17:42:04    

Bonjour,
 
Je précise que j'utilise MySQL v4 et PHP 4.
 
Voilà j'expose mon problème : j'ai une table "clients" dans ma base de données, dont le schéma simplifié serait le suivant :
 
cli_id : id du client
cli_nom : raison sociale du client
cli_cli_id : id du client parent
 
Le champ cli_cli_id permettant d'indiquer si le client dépend d'un autre client. Si le client dépend d'un autre, ce champ prend la valeur du cli_id du client père. Dans le cas contraire, le champ est à 0 (ou null..)
 
On est donc en présence d'une liste récursive.
 
Mon problème, c'est comment faire pour afficher la liste complète des clients, triés dans l'ordre de leur récursivité ? Après avoir essayé infructueusement plusieurs techniques, j'en suis arrivé à la plus moche de toutes : à chaque client je fais une requête pour voir s'il a des "enfants", et ainsi de suite.
 
Je suis preneur de toute solution permettant de soulager le pauvre MySQL qui galère évidemment à faire toutes ces requêtes en boucle (s'il faut passer par des tables temporaires, je n'ai rien contre).
 
Par avance merci pour votre aide !  :jap:

Reply

Marsh Posté le 20-10-2006 à 17:42:04   

Reply

Marsh Posté le 20-10-2006 à 19:39:19    

En utilisant un autoid pour numéro de client. Puis en triant par autoid.

Reply

Marsh Posté le 20-10-2006 à 19:55:24    

... saleté de forum, de claviers et de doigts de polio :o
j'ai encore paumé mon message :cry:
 
bon je recommence :
Pas de solution "simple" avec MySQL, et encore moins avec cette version. Avec la 5, tu disposerais de bidouilles en faisant des PS afin de t'en sortir sans trop de bobo.
Si la profondeur de récursivité est limitée et figée, alors tu peux t'en sortir avec des auto-jointures.
 
Sinon, seuls PostGreSQL et Oracle (le premier est GNU, et le second existe en version gratuite) ont des fonctions intégrées qui permettent de parcourir des tables récursives de façon native (instruction "connect by" ).
 
Exemple de CONNECT BY (non applicable à ta version de MySQL donc) :
http://forum.hardware.fr/hardwaref [...] m#t1459324
 
Exemple avec des autojointures (applicable à ta version de MySQL, uniquement si ton niveau de récursivité est connu et assez bas) :
http://forum.hardware.fr/hardwaref [...] m#t1448106
 
(fait bien gaffe aux #xxxx qui indiquent le post exact)

Reply

Marsh Posté le 21-10-2006 à 10:43:26    

Bonjour,
 
Va voir cet article :
http://sql.developpez.com/arborescence/
 
Ci-dessous, un petit exemple :

Code :
  1. CREATE TABLE `client` (
  2.   `cli_id` tinyint(1) unsigned NOT NULL auto_increment,
  3.   `cli_nom` char(25) NOT NULL default '',
  4.   `cli_id_pere` tinyint(1) default NULL,
  5.   `bg` tinyint(1) NOT NULL default '0',
  6.   `bd` tinyint(1) NOT NULL default '0',
  7.   PRIMARY KEY  (`cli_id`)
  8. );
  9. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(1, 'client 1', 0, 1, 2);
  10. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(2, 'client 2', 0, 3, 10);
  11. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(3, 'client 3', 0, 11, 12);
  12. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(4, 'client 4', 0, 13, 14);
  13. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(5, 'client 5', 0, 15, 22);
  14. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(6, 'client 7', 2, 4, 5);
  15. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(7, 'client 8', 2, 6, 7);
  16. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(8, 'client 9', 2, 8, 9);
  17. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(9, 'client 10', 5, 16, 17);
  18. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(10, 'client 11', 5, 18, 19);
  19. INSERT INTO client (cli_id, cli_nom, cli_id_pere, bg, bd) VALUES(11, 'client 12', 5, 20, 21);


 
Et cette simple requête te donnera le résultat que tu cherches :

Code :
  1. select *
  2. from client
  3. order by bg


Reply

Marsh Posté le 23-10-2006 à 01:01:34    

et c'est quoi ce bg ?
 
franchement, ormi le connect by ou une ps, y'a pas de solution "simple".
si faut se faire chier à maintenir un champ en plus juste pour le plaisir, c'est pas gagné. et ça empêche toute gestion d'arbre complexe (avec liens alternatifs ou multiples par exemple)

Reply

Marsh Posté le 23-10-2006 à 10:06:02    

Bonjour,
 
Déjà merci pour vos réponses.
Le connect by c'est une solution qui n'est pas applicable à MySQL.
MagicBuzz j'ai bien regardé ton exemple sur la famille. Admettons que je limite le niveau de récursivité, il me reste quand même un problème : comment afficher tous les clients et les trier dans le bon ordre ? Je voudrais qu'ils soient triés par nom, mais aussi par arborescence, de cette manière :
 
- monsieur A
--- monsieur E fils de monsieur A
- monsieur B
--- monsieur D fils de monsieur B
--- monsieur F fils de monsieur B
- monsieur C
 
Concernant l'idée de faire une PS, peux-tu m'en dire plus ? Je peux éventuellement négocier un passage en v5 de MySQL.
 
jeca, merci j'avais déjà vu la solution concernant le bd et le bg, mais ça m'a l'air assez lourd à mettre à jour. Que se passe-t-il si j'insère un client en haut de la hiérarchie ? Il faut décaler tous les bd / bg pour que ça continue de fonctionner ?

Reply

Marsh Posté le 23-10-2006 à 12:33:19    

Pour le premier point, c'est très simple, tu auras les données sous la forme :
 
Monsieur A
Monsieur A Monsieur E
Monsieur B
Monsieur B Monsieur D
Monsieur B Monsieur F
Monsieur C
 
=> A partir de là, en regardant quelle est la première colonne qui est vide, tu as immédiatement le niveau hiérarchique, et pour le tri, il est trivial. En effet, la solution de l'auto-jointure a pour défaut que ça retourne autant de colonnes qu'il y a de liaisons. Ou alors il faut de lancer dans des traîtements style "DECODE" sous Oracle (pas du tout pareil que sous MySQL, où ça doit être "CASE" ) afin de faire le choix de quel champ afficher en fonction de tests.
 
Pour le coup de la PS, c'est simple : tu fais ton code PHP en PS, et tu stocke le résultat dans une table temporaire. Tu peux faire ça dans une fonction récusrive (mais t'es limité en ittérations réccursives, avec SQL Server par exemple, c'est 30 imbriquations et c'est pas changeable, sous MySQL ça doit être grossomodo pareil)

Reply

Marsh Posté le 23-10-2006 à 12:57:24    

ou alors en utilisant des tableaux php, ça évite bien des emmerdes et c'est loin de bouffer autant de ram que ce qu'on voudrait croire :)


---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 15:03:58    

C'est pas trop un problème de RAM, mais un problème de performances. Un PS c'est compilé dans la base, et les données brutes ne sortent pas de la base. Ainsi, c'est infiniment plus rapide que tout ce que tu peux tenter de faire avec un langage de haut niveau. Je ne suis même pas sûr que tenter de faire la même chose directement en ASM puisse rivaliser de vitesse avec une PS, à cause de ça justement (taille des données à transfèrer au programme plus importantes).
 
Bon, ceci dit, on n'est peut-être pas à quelques dixièmes de seconde près non plus... ;)


Message édité par MagicBuzz le 23-10-2006 à 15:04:26
Reply

Marsh Posté le 23-10-2006 à 15:23:15    

bin le tableau tu le regénère quand t'as des changements dans la base et le reste du temps tu le charge tel quel :)
 
c'est forcément valable seulement si t'as plus de consultations que de modifications (et juste charger le tableau en ram, là la PS peut s'accrocher)


---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 15:23:15   

Reply

Marsh Posté le 23-10-2006 à 15:31:39    

qu'est-ce que tu racontes ?
 
encore un bon truc de porc comme je les aime tiens... faut pas que tu bosses pour une appli de compta toi, sinon tu finis pendu haut et court (d'autant plus que les comptables sont rapias, donc la corde sera vraiment très courte [:magicbuzz] )


Message édité par MagicBuzz le 23-10-2006 à 15:32:25
Reply

Marsh Posté le 23-10-2006 à 15:35:09    

tu fais un cache de la table que tu charge en mémoire
 
c'est au moins aussi porc que de faire des jointures sans savoir jusqu'à quelle profondeur on doit aller ou des PS sur mysql 4 qui ne les supporte pas...
 
la structure reste la même, c'est la manière d'y accéder qui est différente (plus rapide et plus simple) je vois pas où se situe le problème
 
accessoirement j'attends ta réponse sur les entêtes http d'IIS qui forcent l'acceptation de cookies :whistle:

Message cité 1 fois
Message édité par Sh@rdar le 23-10-2006 à 15:36:46

---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 16:19:47    

Salut,
 
Merci pour les réponses, encore une fois.
 
Sh@rdar, l'idée du tableau calculé en PHP est intéressante, ce qui m'embête c'est de récupérer tous les enregistrements pour les trier après au sein d'un script PHP. Sachant en plus que je ne devrai pas tous les afficher (pagination) ça me fait récupérer plus de données que ce dont j'ai réellement besoin.
Après effectivement je peux gérer ça au travers d'un système de cache qui serait mis à jour lors de modifications sur cette table. Mais bon, c'est une solution technique un peu lourde quand même.
 
La logique quand on développe avec une base de données c'est systématiquement de faire travailler en priorité la base de données. Si je veux afficher 20 enregistrements, je m'arrange pour que mon SELECT ne m'en renvoie que 20. Si je veux qu'ils soient triés suivant un ordre particulier, je me débrouille avec l'ORDER BY. La base de données est optimisée pour ce genre de traitement. C'est là tout le sens de ma question. Si je n'ai d'autre choix que de travailler au sein d'un script PHP  sur un jeu d'enregistrements trop volumineux par rapport à mes besoins, je le ferai, mais en dernier recours.
 
Une PS ça va tourner directement sur le serveur de base de données, ça va être optimisé pour des performances accrues, et ça va renvoyer uniquement ce dont j'ai besoin. Mais en ce qui concerne MySQL 5 (version où sont introduites les PS) je crois que c'est pas encore assez mûr pour être vraiment utilisé dans un dev professionnel.
 
MagicBuzz désolé mais je ne comprends pas tout. Comment obtiens-tu le résultat que tu m'as montré ? Que mettre dans l'order by ? Dois-je utiliser des concaténations d'autres champs pour faire mon tri ?  J'essaie d'implémenter ta solution et je m'embourbe.
J'ai écrit un truc de ce genre :

Code :
  1. SELECT c1.cli_id AS id1, c2.cli_id AS id2, c3.cli_id AS id3,
  2. c1.cli_raisonsociale
  3. FROM client c1
  4. LEFT OUTER JOIN client c2 ON c1.cli_id = c2.cli_cli_id
  5. LEFT OUTER JOIN client c3 ON c2.cli_id = c3.cli_cli_id
  6. ORDER BY c1.cli_raisonsociale, c2.cli_raisonsociale, c3.cli_raisonsociale


donc évidemment ça marche pas.
 
Pour le coup de la PS j'avoue que j'ai jamais fait de PS en MySQL (d'ailleurs j'ai jamais fait de PS tout court) donc je vois pas comment mettre ça en place.
 
Par avance merci pour un complément d'infos
 
(edit : ah oui c'est cli_raisonsociale et pas cli_nom mon champ  :ange: )


Message édité par deuspi le 23-10-2006 à 16:20:41
Reply

Marsh Posté le 23-10-2006 à 16:33:41    

l'idée du tableau c'est de dumper toute ton arbo de manière à ce que ça soit facilement exploitable après avec php
 
perso j'utilise ça pour des arbres de catalogues contenant un millier d'entrée (cat / sous cat / filtrage etc) ça bouffe moins de 200Ko de ram et ça prend 2ms à charger (avec niveau + id + nom + id parent)
 
faire le tri ou ne récupérer que X résultats se fait en quelques lignes de codes, sans faire bosser la DB  
 
mais ça reste un choix :jap:


---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 16:37:37    

Sh@rdar a écrit :

tu fais un cache de la table que tu charge en mémoire
 
c'est au moins aussi porc que de faire des jointures sans savoir jusqu'à quelle profondeur on doit aller ou des PS sur mysql 4 qui ne les supporte pas...
 
la structure reste la même, c'est la manière d'y accéder qui est différente (plus rapide et plus simple) je vois pas où se situe le problème
 
accessoirement j'attends ta réponse sur les entêtes http d'IIS qui forcent l'acceptation de cookies :whistle:


le cache en mémoire, c'est pas une question de structure. c'est une question de mise à jour.
si ta base est mise à jour par autrechose que tes pages PHP qui gèrent le cache, tu ne te rends pas compte des modifications et tu affiches des infos foireuses.
c'est ça que je trouve porc.

Reply

Marsh Posté le 23-10-2006 à 16:38:44    

mais non, la page php avec le tableau ne sert qu'à lire / afficher :o
 
à chaque modif de la base tu écrase le fichier avec le tableau et vu qu'il est chargé à chaque page..
 
 
(c'est bien pour ça que je dit que c'est valable quand t'as plus de lectures que de modifications)

Message cité 1 fois
Message édité par Sh@rdar le 23-10-2006 à 16:40:51

---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 16:40:40    

deuspi > à froid, je ne vois pas ce qui cloche dans ta requête. t'as quoi comme résultat ?

Reply

Marsh Posté le 23-10-2006 à 16:42:26    

Sh@rdar a écrit :

mais non, la page php avec le tableau ne sert qu'à lire / afficher :o
 
à chaque modif de la base tu écrase le fichier avec le tableau et vu qu'il est chargé à chaque page..
 
 
(c'est bien pour ça que je dit que c'est valable quand t'as plus de lectures que de modifications)


et je te redemande une seconde fois : comment tu sais que la base a été modifiée ?
si je viens avec mes pattes sur ton serveur, et je lance des requetes à la main pour mettre à jour la base, tu fais quoi ?
si demain on te demande d'écrire une appli pour pluguer un outil d'admin passant par un webservice qui met à jour la base, tu fais comment ?
 
ton machin c'est cool tant que tu restes sur un mini-site amateur. dès que t'as besoin de t'intégrer dans un SI, t'es baisé.

Reply

Marsh Posté le 23-10-2006 à 16:49:57    

et sinon, pour ce qui est de la parano de l'économie des requêtes, faut pas croire que tout le monde est hébergé chez free sur des serveurs mutualisés gavés jusqu'à la gueule.
 
Genre :
http://accessories.euro.gehealthcare.com
 
J'ai laissé les temps de réponse en débug en bas de chaque page.
Chaque libellé que tu vois à l'écran, c'est une requête SQL qui va chercher dans Oracle (soit dans les 50 requêtes par page)
Cette base Oracle est déjà utilisé par environ 3000 personnes à l'aide d'un client d'un ERP (je tape direct dans la base d'un ERP). C'est à dire que le serveur est gavé jusqu'à la gueule de requêtes dans des tables aussi volumineuses que stressées. Chaque session se traduit par des dizaines de locks persistants qui participent fortement au ralentissement de la base.
T'as vraiment l'impression que ça ramme ?
 
Bref, faut arrêter de pondre des usines à gaz de cache PHP qui risquent de foutre en l'air l'intégrité des données, juste pour économiser 3 pauvres requêtes qui prendront à tout péter 10 ms toutes réunies...

Reply

Marsh Posté le 23-10-2006 à 16:57:36    

nan mais t'as raison, je comprends même pas pourquoi tout le monde utilise pas 50 requêtes sql sur de l'oracle pour le moindre site vu que c'est si rapide, d'ailleurs les hébergeurs discount vont bientôt proposer des clusters à 4€ / mois :jap:
 
t'as pas passé l'âge de jouer à qui a la plus grosse ?
 
(sinon c'est con j'étais pas contre ton argument de modifis à la main, mais bon si c'est une caractéristique connue je vois pas ce que ça impose comme contrainte de bêtement regénere le cache après [:spamafote])


Message édité par Sh@rdar le 23-10-2006 à 16:58:34

---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 17:32:47    

je joue pas à qui à la plus grosse.
 
là je suis dans une société qui héberge un site à destination de ses magasins (environ 130 dans le monde). ils ont une pauvre ligne SDSL 512/512 pour ce site plus une version TSE de leur ERP. autant dire qu'il ne reste pas grand chose comme débit.
leur serveur de base de données, qui fait aussi tourner leur ERP, c'est un pauvre xeon 2.2 GHz avec 2 GB de mémoire, soit un truc totalement ridicule pour faire tourner une telle appli, et qui aujourd'hui représente un investissement de moins de 1000 €. j'ai un magasin au téléphone : "on a viré un de nos vendeurs, on veut changer le mot de passe du site".
no soucy, je passe par l'ERP, et zou, je change le mot de passe dans la base.
parceque je ne fais pas des objets de cache à deux balle pour gagner 2 millisecondes, je fais une requête à chaque ouverture de page pour vérifier les infos du login. immédiatement il me dit "ah ben merde, je suis déconnecté". bah ouais :spamafote:
 
sans ça, il aurait fallu que j'aille manuellement redémarrer le service web du serveur http (et pour ça je dois bouger mon cul de ma chaise donc ça me gonfle), ou alors faire une interface d'admin pour le site, qui ferait doublon avec l'ERP.
 
bref, c'est se rajouter du boulot pour une économie qui n'en vaut pas la peine.
 
c'est pas jouer à qui à la plus grosse, mais rester réaliste. une base de données, c'est rapide, et ça doit rester l'unique référentiel pour gérer les données. externaliser les données (et les contraintes), c'est se tirer une balle dans le pied puis foncer droit dans un mur à cloche pied.
 
à côté de ça, (et pour la première fois depuis très longtemps) j'ai eu 100% de retours positifs sur ce site : tout le monde est super content d'avoir un état des stocks à l'instant près, et un temps de réponse aussi rapide -portant avec les 4 Ko/s qu'il doit rester pour l'ensemble des magasin, c'est chaud). preuve que mine de rien, ormis les 25 Mo de Flash à deux balles et qui font chier de toute façon, un PC tout bête sur une cnx perso est amplement suffisant pour héberger un site dans d'excellentes condition. ici c'est un outil vital pour toute une chaîne de magasins, sans le site ils sont incapable de s'engager sur des délais de réappro, c'est quand même plutôt gênant.
 
crois-en mon expérience.
et une dernière fois, je suis désolé si ça te gêne, mais oui, j'estime qu'une personne qui veut héberger un site qui a un temps de réponse correct et offre des garanties d'intégrité des données et d'uptime doit s'en donner les moyens. être hébergé sur un serveur gratuit style free, c'est juste bon à faire une page perso avec la photo de son chien, ou à la limite pour du dev.
si tu veux faire des l'exploitation, désolé, dans le pire des cas ta connexion internet ADSL fera amplement l'affaire.
franchement, si tu veux un hébergementà 4 € par mois, je t'en fait un volontier. tu seras hébergé sur un vrai serveur, et ça me remboursera le tier de mon abo Alice.


Message édité par MagicBuzz le 23-10-2006 à 17:36:15
Reply

Marsh Posté le 23-10-2006 à 17:48:07    

putain tu peux pas t'empécher de raconter ta vie ?
 
OSEF que tes clients soient contents, qu'il y ait 50 requêtes ou 300 et que tu rédémarrre ton serveur ou autre, et j'ai jamais parlé de faire du cache de login t'es complètement à coté de la plaque là [:kiki]  
 
tout ce que tu fais tu peux aussi le faire avec une copie cache des données du moment que tu la régénère à chaque passage c'est aussi simple que ça, l'intégrité qui t'es si chère est préservée et j'ai pas besoin d'un xéon pour supporter 50 requêtes  
 
<MagicBuzz>
mon bête P4 et ses 512Mo de ram sortent les 10Go de traffic mensuel rien que sur 2 sites avec un CA à 6 chiffres avant la virgule une dispo de 99.99%
</MagicBuzz>
 
en attendant, pour du mysql 4 à la base tu donne une solution pour la version 5 et une autre avec uniquement une profondeur limitée, comment on fait pour 25,50 niveaux ?


---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 23-10-2006 à 17:57:10    

De la récursivité en PHP.
 
Je crois que t'as un souci avec le mot cache en fait.  
 

Citation :

tout ce que tu fais tu peux aussi le faire avec une copie cache des données du moment que tu la régénère à chaque passage c'est aussi simple que ça


 
tu le regénères à chaque fois ? qu'est-ce que t'entends par là ? un cache, justement, ça se recharge pas à chaque fois, c'est bien le rôle du cache.
 
donc si ce que tu appelle faire un cache, c'est faire un "select *" dans ta table, le coller en array php et faire des traîtements récursifs dedans, et ce, à chaque chargement de la page, alors y'a pas d'histoire de cache, et la discussion est close.
 
faudrait peut-être déjà que tu t'exprimes correctement.
 
si par contre, comme ce que tu laisses sous entendre, tu gardes ce array php en variable partagée, là il s'agit en effet d'un cache. mais si la base est mise à jour sans que le site ne soit au courant, tu te trimballe des données qui ne sont pas à jour, ce qui pour moi est pire que tout.
 
:spamafote:

Reply

Marsh Posté le 23-10-2006 à 18:17:36    

à chaque modif :o


---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 24-10-2006 à 10:49:03    

MagicBuzz a écrit :

deuspi > à froid, je ne vois pas ce qui cloche dans ta requête. t'as quoi comme résultat ?


 
Les résultats de cette requête ne sont pas triés correctement du tout. Le seul critère de tri conservé c'est le tri par raison sociale 1, c'est-à-dire la raison sociale du client et non de ses parents, et donc les clients sont juste triés par ordre alphabétique en ignorant leur hiérarchie. Etant donné que la raison sociale 1 change à chaque ligne, les autres critères de tri sont ignorés. En fait je pense que je pourrais peut-être m'en sortir avec des CONCAT de furax mais bon...
 
Sinon j'ai compris vos points de vue à tous les deux, inutile de vous faire la guerre :)
La solution de mise en cache peut être intéressante mais comme je l'ai dit je préfèrerais faire travailler la base de données. De plus c'est pas un site hébergé chez Free  :D mais j'ai pas le droit de changer les composants de l'architecture, enfin peut-être un passage en MySQL 5 est-il envisageable si je peux l'argumenter correctement.
Limiter la profondeur de la récursivité ne me gênerait pas énormément, j'ai pas besoin de 25 ou 50 niveaux, je pense que 3 suffiront pour la plupart des cas donc je peux limiter à 3 ou 4 sans trop d'impact. C'est pourquoi je voudrais creuser davantage une solution mettant en oeuvre une requête SQL capable de tourner sur MySQL 4.
 
edit :
Voilà j'ai changé un peu la requête SQL (et changé le sens des jointures, aussi)
 
SELECT  
c1.cli_id AS id1,  
c2.cli_id AS id2,  
c3.cli_id AS id3,  
c1.cli_raisonsociale,  
CONCAT(IFNULL(c3.cli_raisonsociale, ''), IFNULL(c2.cli_raisonsociale, ''), IFNULL(c1.cli_raisonsociale, '')) AS tri  
FROM client c1  
LEFT OUTER JOIN client c2 ON c1.cli_cli_id = c2.cli_id  
LEFT OUTER JOIN client c3 ON c2.cli_cli_id = c3.cli_id  
ORDER BY tri
 
En concaténant les 3 raisons sociales j'arrive à les trier hiérarchie et par raison sociale. Ca me donne une profondeur à 3 niveaux (c1 c2 c3) et ça peut suffire. MagicBuzz est-ce que c'est à ça que tu pensais ? Ca va pas faire souffrir la base de données, un ORDER BY sur une concaténation ? Qu'est ce que tu me conseilles comme création d'index ?

Message cité 1 fois
Message édité par deuspi le 24-10-2006 à 10:59:17
Reply

Marsh Posté le 24-10-2006 à 14:13:02    

Sh@rdar a écrit :

à chaque modif :o


et donc t'as aucun moyen de t'assurer que tu recharges bien à chaque modif.
tu ajoutes un écran dans le site qui fait des modifs dans la table, et t'oublie de flusher le cache, ou alors t'as une autre méthode (outils externe) qui permet de modifier les données...
c'est le mur assuré.
et y'a aucun moyen d'y pallier.

Reply

Marsh Posté le 24-10-2006 à 14:15:04    

deuspi a écrit :

Les résultats de cette requête ne sont pas triés correctement du tout. Le seul critère de tri conservé c'est le tri par raison sociale 1, c'est-à-dire la raison sociale du client et non de ses parents, et donc les clients sont juste triés par ordre alphabétique en ignorant leur hiérarchie. Etant donné que la raison sociale 1 change à chaque ligne, les autres critères de tri sont ignorés. En fait je pense que je pourrais peut-être m'en sortir avec des CONCAT de furax mais bon...
 
Sinon j'ai compris vos points de vue à tous les deux, inutile de vous faire la guerre :)
La solution de mise en cache peut être intéressante mais comme je l'ai dit je préfèrerais faire travailler la base de données. De plus c'est pas un site hébergé chez Free  :D mais j'ai pas le droit de changer les composants de l'architecture, enfin peut-être un passage en MySQL 5 est-il envisageable si je peux l'argumenter correctement.
Limiter la profondeur de la récursivité ne me gênerait pas énormément, j'ai pas besoin de 25 ou 50 niveaux, je pense que 3 suffiront pour la plupart des cas donc je peux limiter à 3 ou 4 sans trop d'impact. C'est pourquoi je voudrais creuser davantage une solution mettant en oeuvre une requête SQL capable de tourner sur MySQL 4.
 
edit :
Voilà j'ai changé un peu la requête SQL (et changé le sens des jointures, aussi)
 
SELECT  
c1.cli_id AS id1,  
c2.cli_id AS id2,  
c3.cli_id AS id3,  
c1.cli_raisonsociale,  
CONCAT(IFNULL(c3.cli_raisonsociale, ''), IFNULL(c2.cli_raisonsociale, ''), IFNULL(c1.cli_raisonsociale, '')) AS tri  
FROM client c1  
LEFT OUTER JOIN client c2 ON c1.cli_cli_id = c2.cli_id  
LEFT OUTER JOIN client c3 ON c2.cli_cli_id = c3.cli_id  
ORDER BY tri
 
En concaténant les 3 raisons sociales j'arrive à les trier hiérarchie et par raison sociale. Ca me donne une profondeur à 3 niveaux (c1 c2 c3) et ça peut suffire. MagicBuzz est-ce que c'est à ça que tu pensais ? Ca va pas faire souffrir la base de données, un ORDER BY sur une concaténation ? Qu'est ce que tu me conseilles comme création d'index ?


essaie simplement
 
SELECT  
IFNULL(c1.cli_raisonsociale, '') AS id1,  
IFNULL(c2.cli_raisonsociale, '') AS id2,  
IFNULL(c3.cli_raisonsociale, '') AS id3,  
c1.cli_raisonsociale
FROM client c1  
LEFT OUTER JOIN client c2 ON c1.cli_cli_id = c2.cli_id  
LEFT OUTER JOIN client c3 ON c2.cli_cli_id = c3.cli_id  
ORDER BY id1, id2, id3
 
On dirait que t'as un souci avec le tri sur la valeur NULL.

Reply

Marsh Posté le 24-10-2006 à 14:25:13    

MagicBuzz a écrit :

et donc t'as aucun moyen de t'assurer que tu recharges bien à chaque modif.
tu ajoutes un écran dans le site qui fait des modifs dans la table, et t'oublie de flusher le cache, ou alors t'as une autre méthode (outils externe) qui permet de modifier les données...
c'est le mur assuré.
et y'a aucun moyen d'y pallier.


 
mais clair, l'arbo est modifiable par tous les utilisateurs alors j'ajoute ce genre de truc 3 fois par jour :jap:
 
en plus pourquoi résoudre le problème de forcer la mise à jour via un objet qui va gérer ça alors qu'on peut laisser tout le monde s'amuser à modifier la base et que c'est toujours pour 400 personnes dans le monde :jap:
 
comme disait l'autre, il n'y a pas plus aveugle que celui que ne veut pas voir :jap:

Message cité 1 fois
Message édité par Sh@rdar le 24-10-2006 à 14:25:56

---------------
La musique c'est comme la bouffe, tu te souviens du restaurant dans lequel t'as bien mangé 20 ans plus tôt, mais pas du sandwich d'il y a 5 minutes :o - Plugin pour winamp ©Harkonnen : http://harko.free.fr/soft
Reply

Marsh Posté le 24-10-2006 à 14:53:01    

MagicBuzz a écrit :

essaie simplement
 
SELECT  
IFNULL(c1.cli_raisonsociale, '') AS id1,  
IFNULL(c2.cli_raisonsociale, '') AS id2,  
IFNULL(c3.cli_raisonsociale, '') AS id3,  
c1.cli_raisonsociale
FROM client c1  
LEFT OUTER JOIN client c2 ON c1.cli_cli_id = c2.cli_id  
LEFT OUTER JOIN client c3 ON c2.cli_cli_id = c3.cli_id  
ORDER BY id1, id2, id3
 
On dirait que t'as un souci avec le tri sur la valeur NULL.


 
Salut,
Merci pour ton aide.
Je viens d'essayer ta requête. Le tri n'est pas bon : tous les clients sont triés par raison sociale, ignorant leur niveau hiérarchique. Et c'est logique : en effet, tu tries en priorité sur "id1", qui correspond à c1.cli_raisonsociale, ce qui contient la raison sociale de chaque client.  
c1 va contenir tous les clients
c2 va contenir uniquement les clients possédant 1 niveau en-dessous
c3 va contenir uniquement les clients possédant 2 niveaux en-dessous
Etant donné que les raisons sociales de c1 sont différentes à chaque ligne, les autres critères de tri sont automatiquement ignorés.

Reply

Marsh Posté le 24-10-2006 à 16:19:47    

Sh@rdar a écrit :

mais clair, l'arbo est modifiable par tous les utilisateurs alors j'ajoute ce genre de truc 3 fois par jour :jap:
 
en plus pourquoi résoudre le problème de forcer la mise à jour via un objet qui va gérer ça alors qu'on peut laisser tout le monde s'amuser à modifier la base et que c'est toujours pour 400 personnes dans le monde :jap:
 
comme disait l'autre, il n'y a pas plus aveugle que celui que ne veut pas voir :jap:


qui te parle d'arbo ?
il s'agit d'un fichier client.
 
alors entre le site rservé au clients pour ajouter de nouveaux filleuls, un CRM utilisé par la hotline, et l'application de gestion du fichier client, ça fait déjà 3 sources possibles pour des modifications dans cette table.
 
c'est qui l'aveugle d'après toi ?

Reply

Marsh Posté le 24-10-2006 à 16:22:12    

deuspi > c'est quoi cette histoire de raison sociale :o
 
tu peux poster un exemple d'une dizaine de lignes de ta table, suivit du résultat attendu (pourtant sur ces 10 lignes) ?
 
ce sera plus simple, parceque là j'ai l'impression que tu mélanges des poireaux avec des navets. encore un peu de choux et de palette de porc et t'as une superbe potée :D
 
 
sinon, en effet, t'as écrit tes jointures à l'envers. order id3, id2, id1 à priori (le premier doit être celui qui est tout le temps rempli -premier niveau-, le second, ses fils, le troisièmes, ses petits-fils, etc.)


Message édité par MagicBuzz le 24-10-2006 à 16:24:34
Reply

Marsh Posté le 24-10-2006 à 16:33:14    

-- /me is confused : je viens de jouer un peu dans une base de test, et en effet, je vois ce qui cloche dans la requête :D --
 
je regarde ça de plus près (y doit manquer un petit truc :D)

Reply

Marsh Posté le 24-10-2006 à 16:53:22    

t'ain chuis la tête dans le pâté, j'y comprends rien
 
tu veux pas plutôt le faire en PHP ton truc ? :D
 
idéalement, avec une PS sous MySQL 5 ce serait quand même mieux, mais pour pour la requête avec jointure, je sais que c'est bête comme choux car je l'ai déjà fait mais... bah... j'y arrive plus là :D

Reply

Marsh Posté le 24-10-2006 à 16:54:53    

Salut,
 
Voici un exemple : (les champs sont dans l'ordre suivant : cli_id, cli_cli_id, cli_raisonsociale)
 
INSERT INTO `client` VALUES (1, NULL, 'B');
INSERT INTO `client` VALUES (2, 1, 'C (fils de B)');
INSERT INTO `client` VALUES (3, 2, 'G (fils de C (fils de B))');
INSERT INTO `client` VALUES (4, 1, 'E (fils de B)');
INSERT INTO `client` VALUES (5, NULL, 'A');
INSERT INTO `client` VALUES (6, NULL, 'D');
INSERT INTO `client` VALUES (7, 6, 'F (fils de D)');
 
Le résultat attendu :
 
5 A
1 B
2 C (fils de B)
3 G (fils de C (fils de B))
4 E (fils de B)
6 D
7 F (fils de D)
 
Le résultat obtenu avec la requête que tu m'as fournie :
 
5 A
1 B
2 C (fils de B)
6 D
4 E (fils de B)
7 F (fils de D)
3 G (fils de C (fils de B))
 
On voit ici que les résultats sont triés par ordre alphabétique, sans tenir compte de la hiérarchie.
 
A part ça, merci de chercher avec moi des solutions  :jap: J'espère que c'est plus clair comme ça.

Reply

Marsh Posté le 24-10-2006 à 16:55:06    

ps: ton fichier client est volumineux ?
car le mieux serait quand même, par rapport à ta solution actuelle, de charger toutes les colonnes dont du as besoin dans un array, puis faire un traîtement récursif dedans, plutôt que de refaire plein de requêtes. mais évidement, si t'as des milliers de lignes ça va pas trop être possible...

Reply

Marsh Posté le 24-10-2006 à 16:57:44    

MagicBuzz a écrit :

t'ain chuis la tête dans le pâté, j'y comprends rien
 
tu veux pas plutôt le faire en PHP ton truc ? :D
 
idéalement, avec une PS sous MySQL 5 ce serait quand même mieux, mais pour pour la requête avec jointure, je sais que c'est bête comme choux car je l'ai déjà fait mais... bah... j'y arrive plus là :D


OK pour la solution PS sous MySQL 5 je veux bien tenter d'imposer la migration, mais tu pourrais m'aider à l'implémenter ? Je dispose d'un serveur 5 pour tester si nécessaire. Je n'ai aucune expérience en création de PS donc j'aurais vraiment besoin d'aide sur ce coup-là.
Le faire en PHP bah comme j'ai dit ce sera en dernier recours... Je suis pas vraiment fan de cette solution... Mais c'est certain, elle a l'avantage de fonctionner.
Mais je crois que ma requête fonctionne bien (celle où je fais des CONCAT) mais j'ai peur qu'elle ait un impact négatif sur les perfs. Qu'en penses-tu ?

Reply

Marsh Posté le 24-10-2006 à 16:58:11    

normal, car tu dois trier que par les ID.
par contre, en effet, t'auras plus de tri par raison sociale au sein d'un même noeud.
 
il te reste que la solution bourrin en php et la solution par ps (qui revient au même, mais évite de charger toutes les données dans le PHP)

Reply

Marsh Posté le 24-10-2006 à 16:59:24    

deuspi a écrit :

OK pour la solution PS sous MySQL 5 je veux bien tenter d'imposer la migration, mais tu pourrais m'aider à l'implémenter ? Je dispose d'un serveur 5 pour tester si nécessaire. Je n'ai aucune expérience en création de PS donc j'aurais vraiment besoin d'aide sur ce coup-là.
Le faire en PHP bah comme j'ai dit ce sera en dernier recours... Je suis pas vraiment fan de cette solution... Mais c'est certain, elle a l'avantage de fonctionner.
Mais je crois que ma requête fonctionne bien (celle où je fais des CONCAT) mais j'ai peur qu'elle ait un impact négatif sur les perfs. Qu'en penses-tu ?


je vais tenter de voir si j'ai la tête qui sors du pâté là, sinon je te fais ça demain (ce sera une PS pour SQL Server par contre, car j'ai pas de MySQL : vade retro ;))

Reply

Marsh Posté le 24-10-2006 à 17:10:23    

MagicBuzz a écrit :

ps: ton fichier client est volumineux ?
car le mieux serait quand même, par rapport à ta solution actuelle, de charger toutes les colonnes dont du as besoin dans un array, puis faire un traîtement récursif dedans, plutôt que de refaire plein de requêtes. mais évidement, si t'as des milliers de lignes ça va pas trop être possible...


 

MagicBuzz a écrit :

je vais tenter de voir si j'ai la tête qui sors du pâté là, sinon je te fais ça demain (ce sera une PS pour SQL Server par contre, car j'ai pas de MySQL : vade retro ;))


OK merci beaucoup pour ton aide ! Grâce à toi je vais connaître peut-être enfin les PS, du coup...
 
Sinon la volumétrie de ma table client est située entre 600 et 700 lignes, et est amenée à évoluer, mais pas de manière significative (on ajoute pas des clients tous les jours dans cette application)
 
Par contre sur le vade retro, je suis d'accord sur le fond, un serveur SQL Server ou Oracle ou DB2 est forcément plus performant qu'un serveur MySQL, ça tombe sous le sens... Mais c'est pas moi qui décide de l'architecture. On me demande du LAMP, je fais du LAMP.
 
A+  :hello:

Reply

Marsh Posté le 24-10-2006 à 17:38:08    

C'est pas trop un problème de performances (MySQL est un des SGBD au contraire, parmis les plus performants, et ce, à partir d'une machine modeste).
Nan, c'est plutôt au niveau fonctionnalités, que MySQL est très loin derrière la concurrence. Parmi les GNU notamment, on peut noter PostGre qui est très largement suppérieur à MySQL.
 
Ensuite, niveau architecture, je ne te remets pas en cause (et je peux tout à fait -avec un couteau sous la gorge et toute ma famille en otage ;)- conseiller d'utiliser MySQL. Pour certaines tâches, il est tout à fait suffisant et vu qu'il est plus performant, plus intéressant que d'autres SGBD. Mais disons que c'est un SGBD que je n'aime pas du tout, et pour cette raison, j'ai jamais cherché à apprendre ses spécificités. Donc ne t'attends pas à ce que la PS que je vais tenter d'écrire sous SQL Server soit fonctionnelle "telle quelle" sous MySQL, il faudra certainement au minimim adapter la syntaxe (par chance, MySQL a adopté pas mal de mots clés assez proches de ceux de SQL Server).

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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