Problème de tri sur une rubrique de type chaine

Résolu
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009 - 30 avril 2008 à 15:15
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 - 29 juin 2008 à 10:23
Bonjour à tous,

Je viens vous demander un coup de main pour une requête toute simple mais qui me prend la tête.
Au passage, dites-moi si ce que je cherche à faire est possible ou complètement loufoque svp ?

En gros, j'ai une table qui contient certains champs (table référençant des pièces d'un produit) dont une des rubriques est de type VARCHAR.
Pour éditer cette liste de pièces, j'ai fait une requête (pas difficile en soi) qui est la suivante :

SELECT rel_pie_pla.pipl_repere, pi.pie_id, pi.pie_code, pi.pie_numchassisapplication, pi.pie_libelle_fr as libelle, pi.pie_prix_unit_ht, rel_pie_pla.pipl_qte, (SELECT COUNT(*) FROM planches WHERE pla_idpiecereference = pi.pie_id) as ssens
FROM pieces pi LEFT OUTER JOIN rel_pie_pla ON pi.pie_id = rel_pie_pla.pipl_idpiece
WHERE NULL IS NULL AND rel_pie_pla.pipl_idplanche = 324
ORDER BY rel_pie_pla.pipl_repere, CAST(REPLACE(rel_pie_pla.pipl_repere, '-', '0') AS SIGNED), pi.pie_code

Cette requête fonctionne dans 80% des cas, sauf lorsque la rubrique "rel_pie_pla.pipl_repere" (qui correspond au repère de la pièce sur un dessin) contient des valeurs du genre "1-1", "1-10", "1-10-2".

En effet, voici un exemple de résultat de cette requête :
pipl_repere     pie_id          pie_code
1                    5673            27.2.142
1-1                3874            27.2.158
1-1-1            3875            27.2.159
1-1-2            3876            27.0.549
1-1-3            3877            27.2.550
1-1-4            3878            27.0.550
1-10              3866            27.2.165
1-11              3864            27.2.464
1-12              3865            27.2.144
1-2                3858            27.2.143
1-2-1             2291            27.0.173
1-2-2             3860            27.2.153
1-2-3             3859            27.2.152
1-2-4             3861            27.2.155
1-2-5             3862            27.2.156
1-2-6             3863            27.2.151
1-3                3870            27.0.552
1-4                3873            27.2.161
1-5                3872            27.2.162
1-6                3871            27.2.160
1-7                3869            27.2.508
1-8                3868            27.2.164
1-9                3867            27.2.163
2                   2920            27.0.526
3                   3879            27.2.157

Or, la logique voudrait que les pièces en 1-10, 1-11, 1-12 viennent se placer après la pièce 1-9 ?? (dites-moi si je me trompe ...)

J'ai essayé pas mal de choses (conversions, complétions avec des 0, ...) mais rien n'y fait, c'est pour cela que je fais appel à vous pour essayer de me donner un coup de main.
A savoir que je souhaite le plus possible faire ce tri en SQL (sans algo de traitement après) car la base est utilisée par plusieurs applications que j'ai faites (au nombre de 4) dans différents langages (2 en Windev, 1 en ASP.NET et une autre en PHP) et j'ai pas trop envie de me repalucher le code dans chaque langage. D'autant que cette requête est exécutée dans plusieurs écrans de chaque application ....

Merci d'avance si vous pouvez au moins me donner une orientation, sinon une solution.

A bientôt

19 réponses

Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
28 juin 2008 à 04:09
Tu as reçu ici de mauvais conseils et c'est de ta faute. Les noms des tes tables et de tes champs sont absolument affreux, ne refait plus jamais ça ! Mieux vaut avoir des noms trop longs que des noms aussi difficiles à lire, je te le garantie, crois en mon expérience. Si un jour tu te replonges là-dedans pour y faire une modification après avoir délaissé ce code, il y a de fortes chances pour que tu t'en tires avec une sérieuse migraine. Ne parlons même pas de devoir confier des modifications à un autre développeur. Du coup les gens n'ont pas compris ton code s'ils ont cherché à lire et n'ont pas compris ce que tu voulais faire. Ils croient que le problème est que tu veux un tri numérique alors que ton champs est alphabétique et n'ont absolument pas vu que tu as remédié à cette difficulté technique.

Donc, je désapprouve totallement les conseils qu'on t'a donné ici !!!</gras>

Ne modifie surtout pas la structure de ta table car le code de ton ORDER BY est simplement incorrect, et je peux t'expliquer pourquoi.

ORDER BY rel_pie_pla.pipl_repere, CAST(REPLACE(rel_pie_pla.pipl_repere, '-', '0') AS SIGNED), pi.pie_code

Le second argument du tri est excellent et permet de faire fonctionner ta requête comme tu le désires, mais il est incompatible avec le premier argument. Respectivement, ce sont des tris numérique et alphabétique. Le premier que tu utilises va simplement prendre le pas sur l'autre qui deviendra donc simplement inutile. Essaye donc cette syntaxe :

ORDER BY CAST(REPLACE(rel_pie_pla.pipl_repere, '-', '0') AS SIGNED), pi.pie_code

Je mettrai ma main au feu que ta requête va fonctionner parfaitement sans aucune modification de ton script ni de ta base de données.

Encore une fois, on ne peut pas blâmer celui qui a voulu t'aider pour ses conseils désastreux parce que ton code est illisible, moi-même j'ai failli tomber dans le panneau parce que mon cerveau n'avait aucune envie de décoder ce paté informe. Tu as de la chance que j'ai voulu faire cet effort. La prochaine fois essaye d'utiliser des noms de table et de champs lisibles et compréhensibles, améliorer ton identation qui est déjà pas mal,  colorise ton code quand il est si consistant, débarasse-le des détails inutiles, et surtout explique les points particuliers que tu as développé pour que ton code marche.

Quant à [auteur/NHERVAGAULT/84425.aspx nhervagault], puisque tu as compris comme moi où se trouvait la difficulté technique, il serait sympa à l'avenir d'aller lire la partie du code concernée avant de raconter n'importe quoi, parce que là, tu imposes un gros travail complètement inutilement à ce pauvre garçon .

D'avance merci à tous d'améliorer la qualité de l'entraide en fournissant des codes clairs bien commentés et en imaginant des solutions qu'après être certains d'avoir identifié le problème. Je rappelle que la rigueur est la qualité la plus importante pour un développeur après bien sûr un esprit logique.
3
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
28 juin 2008 à 08:22
Excuse

je me trompes peut être mais ca ne semble pas fonctionner
ce que tu indique farfadh j'ai essayé avec 3 niveau et je pense ce qui est demandé c'est
que 1-1-1 soit avant 1-9
et que 1-1 soit avant 2 et 1-1
que 1-10 soit apres 1-1-1

Ce que la requete suivante ne respecte pas (désolé c'est sous sql server)

select CAST(REPLACE(col1, '-', '0') AS int),* from t1 order by CAST(REPLACE(col1, '-', '0') AS int)

convert      original
1              1        
2              2        
3              3        
101          1-1      
109          1-9      
1010        1-10     
10101      1-1-1    
10102      1-1-2    

ce que pense qui est attendu (en lisant le message)
1
1-1
1-1-1
1-1-2
1-9
1-10
2
3
3
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
28 juin 2008 à 09:29
Bonjour à tous,

Merci Farfadh pour tes conseils mais je suis aux regrets de te dire que tu viens de perdre ta main (elle brule :) :) ).
En effet, la suggestion que tu m'a donnée qui consiste à sortir mon champ pipl_repere du tri ne règle pas le problème, voire le résultat est même pire sans (je confirme la réponse de [auteur/NHERVAGAULT/84425.aspx nhervagault]) ... Bonne tentative ...

Du coup, je confirme que j'ai mis en place la solution avec le numéro d'ordre (personnellement je préfère une petite modification de structure qu'un traitement lourd qui surcharge la base ...).

Par contre, je suis d'accord avec toi sur le fait que j'aurai pu faire un effort sur la présentation du code de la requête pour qu'elle soit plus lisible mais, je te rassure, dans mon programme, elle est parfaitement lisible.
Ensuite, tes remarques concernant la dénomination de mes champs, qui ne sont fondées que sur le principe de dire : "mieux vaut des champs longs que des champs illisible !", relèvent plus du fait que la lecture d'une requête aussi simple à 4 h du matin est plus hasardeuse qu'à des heures normales ;) :).
Personnellement, cela fait un peux plus de dix ans que je nomme mes champs de cette manière (en respectant au minimum les préconisation "merisiennes") et je n'ai aucune difficulté à relire mes sources, même si je n'y ai pas touché après plusieurs mois.
Mes collègues ne s'en sont jamais plaint et ont même adopté mes spécifications sans hésiter. Et comme m'a dit mon patron, pour écrire un manuel de développement, c'est plus rapide d'écrire "rel_pie_pla.pipl_repere" que "relationpieceplanche.repere" (hou !! ça me fait penser à ce qu'écrivent les stagiaires qui essaient de créer une bdd sous ACCESS :) ptdr :).
Enfin, proner la qualité de l'entraide ne veut pas forcément dire qu'il faut assassiner le pékin moyen que je suis pour un problème de compréhension des nom des qu'il utilise mais plutôt lui prodiguer des conseils et lui expliquer pourquoi les solutions qu'il choisi ne sont pas bonnes ...

En tout cas merci à tous de vos conseils et à bientôt
3
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
30 avril 2008 à 15:21
Pardon à tous, petite modif :

La requête : SELECT rel_pie_pla.pipl_repere, pi.pie_id, pi.pie_code FROM pieces pi LEFT OUTER JOIN rel_pie_pla ON pi.pie_id rel_pie_pla.pipl_idpiece WHERE NULL IS NULL AND rel_pie_pla.pipl_idplanche 324
ORDER BY CAST(rel_pie_pla.pipl_repere AS SIGNED), CAST(REPLACE(rel_pie_pla.pipl_repere, '-', '0') AS SIGNED), pi.pie_code

et le résultat :
pipl_repere        pie_id        pie_code
1         5673    27.2.142
1-1      3874    27.2.158
1-2      3858    27.2.143
1-3      3870    27.0.552
1-4      3873    27.2.161
1-5      3872    27.2.162
1-6      3871    27.2.160
1-7      3869    27.2.508
1-8      3868    27.2.164
1-9      3867    27.2.163
1-10    3866    27.2.165
1-11    3864    27.2.464
1-12    3865    27.2.144
1-1-1   3875    27.2.159
1-1-2   3876    27.0.549
1-1-3   3877    27.2.550
1-1-4   3878    27.0.550
1-2-1   2291    27.0.173
1-2-2   3860    27.2.153
1-2-3   3859    27.2.152
1-2-4   3861    27.2.155
1-2-5   3862    27.2.156
1-2-6   3863    27.2.151
2          2920    27.0.526
3          3879    27.2.157

Or Normalement, il faudrait que les "1-1-x" soient après la pièce "1-1" mais avant la pièce "1-2" ??

Merci
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
1 mai 2008 à 09:37
Salut,
en effet complexe comme problème, voici une solution, si personne en trouve

Il te reste plus qu'a faire une colonne temporaire, qui s'alimente avec un tigger insert et qui permet de faire
un tri

1--> 1000
1-1 --> 10100
1-10 --> 1100

Et apres tu fais tes tri sur cette colonne.

Bon coding
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
1 mai 2008 à 10:12
Salut,

Merci pour l'info mais ta solution risque d'être un peu difficile à mettre en place du fait que la base est actuellement en cours d'utilisation, qu'elle contient déjà un paquet d'enregistrements et que les triggers réagissent à une action sur les données (ajout, modif, suppr). Il faudrait donc que je demande aux utilisateurs de repasser sur tous les enregistrements pour que cette colonne se mette à jour ... Ca me paraît difficile.

Par contre, comme je ne voyais vraiment pas de solution (frustration quand tu nous tiens), j'ai pris la décision de rajouter effectivement une colonne qui contient un numéro d'ordre qui me permettra de faire les tris correctement et je suis en train d'écrire une procédure de mise à jour de cette colonne en fonction du numéro de repère. (en fait c'est un peu la même solution que ce que tu me donnes, mais je n'ai pas l'intention d'utiliser un trigger, d'autant qu'il s'agit d'une base MySQL et que les trigger ne sont pas, à mon goût, encore au top ...).

Merci encore mais n'hésitez pas, si quelqu'un trouve une solution en SQL pur, ça  m'intéresse.

Une petite question, peut-être une piste que je vais essayer de creuser : n'y aurait'il pas un moyen de faire le tri sur un "codage" de la colonne repère, par exemple un cast en binaire ou en hexa, ou encore un hash ??? à voir ....
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
1 mai 2008 à 10:26
Tu mets a jour avec un update la colonne une fois,
le calcul dois bien etre testé
et apres cette fonction de calcul peut etre utilisée pour le calcul d'une clé sur les insertion

apres il faut savoir la cle est updatable ou pas?
dans ce cas il trouver une solution aussi sur les updates

et ensuite sur un insert la valeur est calculée par un trigger (si my sql ne gere pas les triggers)
il faut le mettre dans chaque insert le calcul du numero de tri.

Le probleme de ton numero d'ordre est une mauvaise solution

Exemple

1-10-9 | 5
1-11    | 6

Quand tu inseres 1-10-10 comment tu fais pour le numero d'ordre.
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
1 mai 2008 à 13:55
Salut,

Remarque très pertinente ...
La gestion du numéro d'ordre est, à mon sens, la solution la plus simple car j'ai fait en sorte que toutes mes applications travaillent avec un tableau pour présenter la liste des pièces.
Du coup, lorsque l'utilisateur fait une modification, mon numéro d'ordre correspond simplement au numéro de ligne dans le tableau. Du même coup, ça me permet de proposer aux utilisateurs la possibilité (par le biais de 2 boutons) de trier les éléments comme ils le souhaitent et je n'ai qu'une colonne à gérer pour avoir le bon ordre.
Ensuite, étant donné que les utilisateurs sont obligés de passer par ces tableaux, j'ai  uniquement un parcours du tableau à faire sur la fermeture de la fenêtre pour mettre à jour le numéro d'ordre.

Merci pour les infos et surtout de t'intéresser à mon cas.

A bientôt
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
1 mai 2008 à 14:10
Oui,

Mais il faut enregistrer tous les numéros d'ordre dans la base de données

soit n (nb element) requetes pour mettre a jour les numeros d'ordre de tes n elements.

une requete update par ligne

avec ma solution une grosse requete pour renseigner la colonne
et ensuite un calcul de valeur pour l'insertion
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
1 mai 2008 à 19:31
Re,

C'est vrai, mais pour ta solution, le problème est le même.
D'autant que je ne vois pas quelle requête je peux faire pour arriver aux exemples que tu m'as donnés :
1--> 1000
1-1 --> 10100
1-10 --> 1100

pour le 1 ok je RPAD avec '0' sur une longueur de 4, idem pour le 1-10 mais en faisant un replace du '_'.
Par contre, pour le 1-1, je vois pas comment traiter des cas différents dans une même requête ?? ou alors j'ai pas compris tes exemples, ce qui est possible aussi.

Dis m'en plus stp.
0
nhervagault Messages postés 6063 Date d'inscription dimanche 13 avril 2003 Statut Membre Dernière intervention 15 juillet 2011 37
1 mai 2008 à 19:55
Oui,
L'algo n'est pas evident,
tu peux le faire dans ton langage de predilection a la place et le faire en SQL,
il faire faire une fonction

Exemple
function long calculNoPieceTri(string nopiece)

tabNumeroPiece = nopiece.split('-");
part1 = tabNumeroPiece[0];
part2 = tabNumeroPiece[1];
part3 = tabNumeroPiece[2];

return part1 * 10000 + part2 *100 + part3

C'est surement faisable en SQL, mais un peu plus complexe car le split n'existe pas, et les calculs seront moins rapide
car le SQL n'est pas optimisé pour des calculs de chaine de caracteres.

Et donc pour avoir le numero de piece
exemple :
2-25-2 --> 22520
2-1-30 --> 21030

Il faudra faire une fonction pour la mise a jour de toutes les pieces.

Voila
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
2 mai 2008 à 09:27
Salut,

merci pour les explications.
Maintenant, je vais voir si cela vaut plus le coup que la mise en place du numéro d'ordre.
Parceque le problème est également que le repère n'est pas forcément que sur 3 parties, il peut y en avoir jusqu'à 5 donc 1-1-1-1-1. Je pense que l'algo à mettre en place pour le calcul risque d'être plus coûteux que celui du numéro d'ordre.

Je vais étudier cela et je te tiens au courant quand j'aurai fini.

Merci en tout cas de ton aide.
0
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
28 juin 2008 à 11:34
Autant pour moi, mais encore une fois, j'ai été bluffé par le manque de clarté du sujet initial. A essayer de comprendre la source, le détail du deuxième message m'a échappé. Je pensais que le tri se faisait dans l'autre sens. Et de toute manière, maintenant que j'y réfléchi, il y a des cas où ça fonctionnait mal. Toutes mes excuses, j'ai l'art et la manière de me comporter comme un crétin quand je suis fatigué et ce n'est pas comme si c'était la première fois que je le faisais. Vous êtes autorisés à me charrier.

En tout cas, cela confirme ma théorie qu'il faut éviter à tous prix de cumuler plusieurs valeurs dans un même champs. Du coup, je propose de scinder ton champs texte en cinq entiers et de faire des tris successifs. Là où tu ne mettais pas de valeur, tu peux utiliser le zéro qui ne te servait pas ici sauf nouvelle erreur de ma part.

Ainsi ton champ (pipl_repere VARCHAR) deviendrait (pipl_repere1 TINYINT UNSIGNED, pipl_repere2 TINYINT UNSIGNED, pipl_repere3 TINYINT UNSIGNED, pipl_repere4 TINYINT UNSIGNED, pipl_repere5 TINYINT UNSIGNED). Bien sûr, j'ai choisi TINYINT parce que dans l'exemple, aucune valeur ne semble dépasser la barre de l'octet, mais si c'est le cas tu peux utiliser un entier plus grand bien entendu.

Une valeur ('1-3-4') deviendrait (1, 3, 4, 0, 0).

Le tri pour ces repères deviendrait tout simplement pipl_repere1, pipl_repere2, pipl_repere3, pipl_repere4, pipl_repere5.

Donc, sauf si je suis encore à l'ouest, tu obtiens un système où tu n'as plus à faire utiliser des fonctions de chaînes, un tri beaucoup plus naturel entièrement en SQL, donc plus rapide et plus portable, une meilleure clarté de ta table, plus aucune nécessité de scinder les données dans tes scripts où tu pourras reconstruire ta chaîne à loisir en ignorant les champs à partir de celui qui a la valeur zéro si nécessaire. En plus, cette succession d'entiers est moins gourmande en stockage, cinq fois le nombre d'octets utilisés par l'entier : dans le cas où tu n'as besoin que de TINYINT, cela fait cinq octets alors que l'équivalent en chaîne fait respectivement jusqu'à 15 et 20 octets pour des valeurs ne dépassant pas 99 et 255. Que des avantages.

Quand à la mise à jour de la table, je comprend que ça puisse être problématique, mais ce n'est pas le plus gros du boulot. Il suffit d'ajouter les champs et de les remplir avec un script qui ne servira qu'une fois pour la mise à jour, vérifier éventuellement à l'aide d'un deuxième script qui parcoure la table pour vérifier que les valeurs correspondent bien, puis de supprimer l'ancien champ quand c'est fait. Le plus chiant, c'est qu'il faut mettre à jour tous les scripts qui écrivent dans la table pour qu'ils remplissent les nouveaux champs au lieu de l'ancien ou bien faire du trigger, et qu'il faut mettre tous les scripts utilisant cette base hors service pour éviter que quelqu'un écrive dedans pendant ce temps-là. Mais à mon avis, au vu de la solution que tu cherches, ça vaut le détour.

Vos solutions ne font que contourner le problème d'une table mal pensée.
- Il est bien sûr possible de créer un champs d'ordre mais laisser les utilisateurs le gérer, c'est courir un risque certain d'utilisation incorrecte. Et si tu dois modifier la table, mieux vaut carrément la mettre à jour comme je l'ai suggeré, c'est du travail, c'est sûr, mais ça a le mérite de régler le problème une fois pour toutes.
- Une autre solution consiste comme l'a suggéré [auteur/NHERVAGAULT/84425.aspx nhervagault] de faire le tri au niveau des scripts mais là, c'est tout aussi lourd car il va falloir modifier tous les scripts qui accèdent à la table, et esuite ça bouffe des ressources dans tous les sens.
- Sinon il est également possible d'écrire le tri de sorte à ce qu'il fasse bien le travail en modifiant la chaîne. Avec la fonction LOCATE,  tu connais la position d'un tiret à partir d'une position et donc avec quelques calculs de la longueur du premier nombre, et tu peux remplacer ce tiret par le nombre de zéros que tu souhaites avec les fonction REPEAT, LEFT, MID et RIGHT (pas moyen de remplacer juste la première occurence d'une chaîne dans une autre). Avec la fonction GREATEST, il est possible de définir un nombre maximum de zéros dans le cas de l'abscence d'une valeur. Mais l'expression serait d'une complexité sans précédent et le calcul très lourd pour SQL.
- Une dernière solution du même genre consiste effectivement à scinder le texte, mais la difficulté et la complexité est du même ordre.

J'espère que je me suis rattrapé avec une réponse cohérente ce coup-ci, et je m'excuse encore pour ma mauvaise compréhension. Je relis les messages pour vérifier... Et oui, malheureusement, la solution la plus viable semble être la réorganisation de la table. Désolé.

Sans rancune j'espère.
0
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
28 juin 2008 à 12:14
Oh, je persiste pour tout ce que j'ai dit au sujet de la lisibilité, même si on a bien entendu le droit de ne pas être d'accord avec moi. J'ai essayé des tas d'écritures avant d'en arriver à ces conclusions. J'ai des écritures très particulières que tu trouverais sans doute très étranges. Le fait est que sauf dans les cas où on est limité en taille des noms par des progiciels mal pensés, mieux vaut avoir des variables les plus claires possibles. J'ai quelques codes datant à peu près de la même époque où j'hésitais justement entre les deux solutions. Et bien le résultat est probant. Quand j'ai voulu les réutiliser ou les modifier plusieurs mois après, j'ai vu clairement la différence entre les deux cas de figure. Dans le cas où j'ai utilisé des abréviations dans les noms de variable, j'ai constaté que je mettais tellement de temps à relire mon propre code que j'ai fini par tout réécrire car c'était plus rapide, ce qui en dit long sur la lisibilité. Et pour la petite histoire, on était une petite vingtaine parmis les centaines d'élèves de notre promotion à l'université à être suffisement calé en développement pour que les sujets des devoirs sur table ne pose aucun problème. J'ai été le seul à avoir accompli un sans faute sur un semestre. On pourrait croire que j'ai été le seul à avoir répondu correctement à toutes les colles, mais après comparaison des copies, il s'est avéré que ce n'était pas le cas. Mes concurrents avait eux-aussi répondu correctement mais la différence entre leurs copies et les miennes, c'était la clarté dûe à l'indentation, à la mise en évidence de la structure par l'alignement des notions similaires, aux noms de fonctions et de variables particulièrement transparents et sans équivoque, et bien sûr à des commentaires réguliers et précis. Ce n'est pas que les correcteurs aient voulu noter la présentation, mais quand on se retrouve à devoir lire de copies de codes par dizaines, on a vite tendance à pénaliser ce qu'on ne comprend pas au bout de quelques minutes, même si c'est correct.

L'heure n'avait rien à voir avec le rejet de ton code par mon cerveau, je m'étais levé dans la soirée, je suis travailleur indépendant et je vis au rythme qui me chante, et là je vais bientôt faire une sieste. Par contre je venais de me prendre la tête sur un code qu'avait développé un de mes collaborateurs, affreux au passage. Il ne marchait qu'en apparence et aux moindres circonstances non-standards, il se mettait à buguer dans tous les sens. J'ai voulu le corriger mais il était vraiment trop pénible à lire, genre les accolades des blocs qui ne sont ni sur la même ligne, ni sur la même colonne, ce qui fait qu'on ne voyait même pas comment les blocs étaient imbriqués. Et comme le gars était de mauvaise foi, j'ai passé mon temps à faire quelque chose d'aussi chiant qu'inutile, à savoir fabriquer une liste impressionnante et pourtant non-exhaustive des circonstances dans lesquelles ça ne marchait pas pour lui envoyer avec son code bidon. Ma seule consolation c'est d'imaginer sa prise de tête à lui pour rectifier ce merdier. Et tant pis pour lui, par contrat, si son code ne fonctionne pas, je n'ai pas à l'acheter ni à le dédomager pour le temps qu'il a passé dessus.
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
28 juin 2008 à 14:36
Re bonjour tout le monde,

Merci pour les précisions et la nouvelle solution possible, cependant, dans le cas ou je dois gérer un niveau de repères illimité, cela signifierai que je devrai prévoir de rajouter un champ le jour où je rajoute un niveau .. dommage ...

Pour la solution que j'ai mise en place finalement, c'est-à-dire le numéro d'ordre, non seulement cela me simplifie énormément le travail mais en plus, les utilisateurs qui gèrent l'ordre d'apparition des pièces sont des utilisateurs d'un bureau d'étude, doc qui savent ce qu'ils font, et sont avertis qu'avec cette liberté, ils en sont complètement responsables. A eux donc de faire attention à ce qu'ils font. Je ne prétend en aucun cas avoir les facultés suffisantes pour me permettre de prévoir tous les cas possibles dans mon traitement.

Et, heu, au fait, tu n'as pas à nous autoriser de te charrier car tu as la décence de répondre et d'amener ton opinion, tu n'est pas à blâmer pour cela.

En tout cas merci à tous et bon courage à tous.
0
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
29 juin 2008 à 01:28
Dans ce cas, au lieu d'aller imposer de mettre un numéro d'ordre, je vais te donner une solution équivalente mais invisible pour les utilisateurs, ce qui pourrait te plaire et résoudre très simplement ton problème.

Puisque ta solution implique d'aller de toute manière aller modifier le traitement des formulaires et de mettre la base de données à jour (ne serait-ce qu'en forçant aux utilisateurs à retoucher tous leurs enregistrements, ce qui n'est pas top et va leur réclamer plus de travail que ça ne te prendrait à toi pour modifier la totalité des enregistrements), autant modifier ton champ existant de manière à ce qu'un ordre alphabétique simple fonctionne.

Voici un tutorial en 7 étapes simples pour bien expliquer le fonctionnement de ma solution :

1. Détermine la valeur maximale d'un nombre de ton champs, et du coup du nombre de chiffres maximum d'un nombre. Dans mon exemple je vais supposer que ça va jusqu'à 999 et que ça occupe au maximum 3 chiffres.

2.A l'instar de l'option UNSIGNED ZEROFILL de SQL, quand tu entres un nombre dans ton champs tu mets les zéros non significatifs. Pour cela transforme le nombre en chaine de caractères que tu fais précéder d'un certain nombre de zéros, déterminé par le nombre maximum de chiffres moins le nombre de chiffres significatifs dans ton nombre. Dans mon cas de figure, au lieu d'entrer '3', il faut entrer '003'. Exemple de code PHP pour illustrer :
    function strzerofill($entier, $taille= 3)
    // génère une chaine de caractères représentant un nombre entier sur 3 chiffres par défaut avec zéros non significatifs
    {
        $chaine= is_string($entier)? $entier: strval($entier); // conversion de l'entier en chaine si nécessaire
        $zerofill= str_repeat('0', $taille- strlen($chaine)). $nombre_chaine; // ajout des zéros non significatifs
        return ($zerofill);
    }

3. Pour créer la chaine finale à entrer dans ton champ, concatène tout simplement tous les nombres qui doivent s'y trouver, sans les tirets qui deviennent inutiles puisque tu sais sur combien de caractères est stocké un nombre. Donc au lieu de mettre '1-2-3' dans ton champs, il faut y mettre '001002003'. Exemple de script PHP :
    function nouveau_pipl_repere($ancien_pipl_repere, $taille = 3)
    // convertit une chaine $pipl_repere de l'ancien format (suite de nombres séparés par des tirets) vers le nouveau (suite de nombres avec zéros non significatifs sans séparateur, d'une $taille de 3 caractères par nombre par défaut) ; bien sûr, tu n'es pas obligé de passer par l'ancienne valeur et tu réécrire la fonction en te passant de la première instruction, mais je me sers de cette fonction plus loin dans ce tutorial
    {
        $chaines= explode($ancien_pipl_repere, '-'); // scinde sans un tableau la chaine $pipl_repere en utilisant le tiret comme séparateur
        $tailles= array_fill(0, count($chaines), $taille); // tableau contenant plusieurs fois la taille spécifiée, à l'usage de 'array_map'
        $zerofills= array_map('strzerofill', $chaines, $tailles); // ajoute les zéros non significatifs aux valeurs
        $nouveau_pipl_repere= implode($zerofills);  // concatène les valeurs sans séparateur
        return ($nouveau_pipl_repere); // renvoie le résultat ainsi obtenu
    }

4.Modifie tous les traitements de formulaire pour qu'ils fonctionnent de cette manière. Applique simplement la dernière fonction ou son
équivalent à la variable contenant la valeur que tu insères dans le champ 'pipl_repere' avant d'effectuer une requete INSERT ou UPDATE.

5.Met à jour la base de données avec un script qui va convertir ce champ dans tous les enregistrements. Exemple de script PHP :
    // je suppose que 'pie_id' est la clé primaire de type entier de la table 'rel_pie_pla'
    $requete = 'SELECTpie_id, pipl_repereFROMrel_pie_pla'; // préparation de la requête en vue d'obtenir tous les enregistrements
    $resultat= mysql_query($requete); // effectue la requête
    if ($resultat) // si la requête est un succes
    {
        while($enregistrement = mysql_fetch_array($resultat)) // tant qu'il reste des enregistrements
        {
            $pie_id= $enregistrement['pie_id']; // recopie la valeur de la clé
            $pipl_repere= nouveau_pipl_repere($enregistrement['pipl_repere']); // recopie et convertit la valeur du repère            $update" UPDATE rel_pie_pla<gras>SETpipl_repere</gras> ' $pipl_repere ' WHEREpie_id = $pie_id"; // prépare la mise à jour
            if (!mysql_query($update)) // effectue la mise à jour pour cet enregistrement
                echo("Echec MAJ : $update
"); // en cas d'échec, le signale et affiche la requête qui a échoué
         }
    }
    else
    {
          echo("Echec MAJ : $requete
"); // en cas d'échec, le signale et affiche la requête qui a échoué
    }

6.Garde ce script sous la main au cas où un enregistrement serait inséré avec l'ancienne méthode après la mise à jour, on ne sait jamais, personne n'est à l'abri d'un bête oubli ou d'un bug improbable. N'oublie pas non plus que si ta table est très grande que le script doit avoir le temps de s'exécuter et que tu dois retirer le "timeout" si nécessaire dans ton langage.

7.Pour lire les nouvelles données du champs, c'est simple, tu connais le nombre de chiffres de chaque valeur. Exemple de script PHP :
    function ancien_pipl_repere($nouveau_pipl_repere, $taille = 3)
    // convertit une chaine $pipl_repere
de du nouveau format vers l'ancien
; bien sûr, tu n'es pas obligé de créer l'ancienne valeur et réécrire la fonction en te passant de la dernière instruction

    {

        $zerofills= str_split($nouveau_pipl_repere, $taille); // scinde dans un tableau la chaine $pipl_repere en chaines d'entiers d'une $taille donnée avec zéros non significatifs
        $entiers= array_map('intval', $zerofills); // convertit les chaines en entiers dans le tableau
        $ancien_pipl_repere= implode('-', $entiers); // concatène les entiers séparés par un tiret dans une chaine pour retrouver l'ancien format de données au besoin
        return($ancien_pipl_repere); // renvoie le résultat ainsi obtenu

    }

Voila. Je ne sais pas ce que tu penses de cette solution, mais je la trouve simple et rapide. Elle a le mérite de ne pas ennuyer l'utilisateur et de permettre un tri alphabétique basique sur SQL sans aucune complication ni possibilité d'erreur humaine à la saisie. Deux remarques à ce sujet :

- Si une fonction ou une notion PHP que j'ai utilisé ne connait pas d'équivalent dans ton langage et que tu as du mal à écrire un code similaire, donne-moi le nom du langage. Même si je ne le connais pas, je serai sous doute capable de t'aider assez vite.

- Si la taille des données te gène puisque les valeurs du champ 'pipl_repere' seront plus longues, sache qu'il est possible de les encoder de manière octale (comme un entier non signé est codé par la machine dans la mémoire) sans que ça nuise au tri alphabétique. Si ça t'intéresse et que tu ne sais pas le faire, demande-moi, c'est très simple à encoder et à décoder via des fonctions généralement appelées 'asc' et 'chr' dans la plupart des langages et en utilisant des masques ainsi que des décalages de bits.
0
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
29 juin 2008 à 01:32
Arf, elle est lourdingue la boîte de texte avec mise en forme à buguer
comme ça, et du coup ne pas respecter les espaces et les sauts de
ligne.
0
satanik_mike Messages postés 28 Date d'inscription mercredi 6 juin 2001 Statut Membre Dernière intervention 3 mars 2009
29 juin 2008 à 08:28
Lol,

Merci pour les infos.
Cependant, je te rassure, j'ai  fait une petite routine qui calcule le numéro d'ordre en fonction du repère et l'utlisateur n'a rien à faire.
Il a juste deux bouton Monter et Descendre.

Ensuite, pour ta solution, c'est difficilement faisable car une liste de planches est accompagnée d'une photo des pièces sur laquelle apparaissent les repères donnés par le Bureau d'Etude.
Du coup, je ne dispose pas de tout ce que je peux sur ce champs de repère.

Merci quand même.
0
Farfadh Messages postés 68 Date d'inscription dimanche 1 avril 2007 Statut Membre Dernière intervention 7 juillet 2008 4
29 juin 2008 à 10:23
Euh, je n'ai pas bien compris la difficulté que tu rencontres, ni la situation que tu me présentes. Tant que tu as tes repères comme tu nous les as présenté, tu peux les stocker au format que tu souhaites, non ?

Quant au numéro d'ordre, si c'est une équivalence du repère, c'est que nos solutions sont équivalentes au détail près qu'avec un champ de plus tu as de la redondance de données. Sinon, s'il s'agit d'un index de tri, comme l'a dit [auteur/NHERVAGAULT/84425.aspx nhervagault]il faut recalculer tous tes numéros d'ordre de tous les enregistrements présents dans la table à chaque insertion ou mise à jour d'un seul enregistrement, ce qui est un travail autant laborieux en développement pour toi qu'en calcul pour ton script ainsi qu'en traitement pour SQL, tout ça pour pas grand chose.

Si tu as déjà mis en place ta solution et qu'elle marche, tant mieux. Mais si un jour il s'avère qu'elle pose problème ou que tu dois mettre en place un système équivalent pour une autre table, je te conseille vraiment d'opter pour la mienne. C'est la même que celle de [auteur/NHERVAGAULT/84425.aspx nhervagault], au détail près qu'elle peut accueillir autant de valeurs dans le repère qu'il sera nécessaire, et la même que la tienne à part que tu peux te passer de créer un champ qui demande des opérations de calcul et de traitement à priori autrement plus complexes.

Par curiosité, pourrais-tu nous montrer la routine que tu utilises pour calculer les numéros d'ordre ? J'ai du mal à croire que tu n'utilises qu'une seule requête et que tu utilises moins d'instructions que nous pour le calcul préalable à l'écriture dans la table. Surtout qu'ordonner tes repères dans leur état d'origine sans passer par une largeur fixe de tes nombres - que ce soit en mode texte ou octal - ne se fait pas simplement puisqu'il faut comparer tous les nombres des repères successivement. Et si tu passes par là, c'est ça qu'on te suggérait de stocker dans la base de données pour ne pas se retrouver avec un nombre arbitraire qui n'est pas réutilisable dans un champ supplémentaire.
0
Rejoignez-nous