Discussion:
tri tableau
(trop ancien pour répondre)
Jerome
2010-02-04 08:23:48 UTC
Permalink
Bonjour
j'utilise pour la première fois des tableaux en php.

j'ai un premier tableau qui récupère des enregistrements dans la base
d'un ERP

do{
$Date = odbc_result($RECUP_LPV,10);
$anne_pie = substr($Date,0,4);
$mois_pie = substr($Date,5,2);

$ligne=array(
"code" => odbc_result($RECUP_LPV,6),
"quantite" => odbc_result($RECUP_LPV,7),
"mois" => $mois_pie,
"annee" => $anne_pie,
"montant" => odbc_result($RECUP_LPV,8)
);
$tableau[$t]=$ligne;
$t++;
}while (odbc_fetch_row($RECUP_LPV));

Une fois cette récupération faite (j'ai bon ou pas ?), je souhaiterai
obtenir un second tableau ne contenant pour une année donné qu'un
enregistrement pour un même "code".
voilà ce que j'ai écrit :

<?foreach($tableau as $element){
if($element['annee']==$anneeN){ //Si je suis sur l'année N
if($num_mois='00'){ //Si je veux les données sur l'année entière
if ($Firsttime_anneeN){ //pour renseigner la première ligne du
tableau trié
$liste_artN['0'] = $element;
$Firsttime_anneeN=false;
$j++;
}else{
$k=0;
foreach($liste_artN as $toto){
if ($toto['code'] == $element['code']){
$tab=array(
"code" => $toto['code'],
"quantite" =>
$element['quantite']+$toto['quantite'],
"mois" => "*",
"annee" => $element['annee'],
"montant" => $element['montant']+$toto['montant']
);
$liste_artN[$k]=$tab;
break;
}
else{
$liste_artN[] = $element;
}
$k++;
}
$j++;
}
}else{ //Sinon, mettre selectionner les donnée du mois choisi

}
}else{ //Sinon, je suis sur l'année N-1

}
$i++;
}

Je pense que c'est pas terrible vu que je n'obtiens qu'un enregistrement
dans le tableau $liste_artN et que je ne vois pas trop à quoi cela
correspond :-(

Si qqn à une petite idée, je suis preneur.

Merci bcp
Jérôme
Bruno Desthuilliers
2010-02-04 10:17:29 UTC
Permalink
Post by Jerome
Bonjour
j'utilise pour la première fois des tableaux en php.
j'ai un premier tableau qui récupère des enregistrements dans la base
d'un ERP
do{
$Date = odbc_result($RECUP_LPV,10);
$anne_pie = substr($Date,0,4);
$mois_pie = substr($Date,5,2);
$ligne=array(
"code" => odbc_result($RECUP_LPV,6),
"quantite" => odbc_result($RECUP_LPV,7),
"mois" => $mois_pie,
"annee" => $anne_pie,
"montant" => odbc_result($RECUP_LPV,8)
);
$tableau[$t]=$ligne;
$t++;
Tu n'a pas besoin de gérer les indices comme çà. Il suffit d'ajouter "à
la fin" du tableau:

$tableau[] = $ligne;

Accessoirement, "$tableau", c'est pas terrible comme nom.
Post by Jerome
}while (odbc_fetch_row($RECUP_LPV));
Une fois cette récupération faite (j'ai bon ou pas ?),
Tu n'a pas testé ton code ?
Post by Jerome
je souhaiterai
obtenir un second tableau ne contenant pour une année donné qu'un
enregistrement pour un même "code".
<?foreach($tableau as $element){
"$ligne" dans le code précédent, "$element" ici... pourquoi ?
Post by Jerome
if($element['annee']==$anneeN){ //Si je suis sur l'année N
A ce stade, "$anneeN" n'est pas défini. Il manque peut-être un bout de
ton code ?
Post by Jerome
if($num_mois='00'){ //Si je veux les données sur l'année entière
Idem: "$num_mois" n'est pas défini.
Post by Jerome
if ($Firsttime_anneeN){ //pour renseigner la première ligne du
tableau trié
Idem.

Et je note que tu a vraiment un problème avec le nommage. Déjà, évite le
franglais autant que possible, ensuite décide-toi pour une convention de
nommage (all_lower ou mixedCase) et tiens-y toi une bonne fois pour
toute. Ca évite bien des typos, qui sont très pénibles à débugger en PHP.
Post by Jerome
$liste_artN['0'] = $element;
"$liste_artN" non défini.
Post by Jerome
$Firsttime_anneeN=false;
$j++;
"$j" non défini.
Post by Jerome
}else{
$k=0;
foreach($liste_artN as $toto){
(Argh ! Non, pas "$toto" !)

A ce stade, tu a au mieux un élément dans $liste_artN.
Post by Jerome
if ($toto['code'] == $element['code']){
$tab=array(
"code" => $toto['code'],
"quantite" =>
$element['quantite']+$toto['quantite'],
"mois" => "*",
"annee" => $element['annee'],
"montant" => $element['montant']+$toto['montant']
);
$liste_artN[$k]=$tab;
Et si jamais tu avais un élément dans $liste_artN, tu viens de l'écraser.
Post by Jerome
break;
}
else{
$liste_artN[] = $element;
Toujours dans le cas (improbable vu le code que tu montres) où tu aurais
un élément dans $liste_artN[], tu viens de le dupliquer. Accessoirement,
modifier un tableau sur lequel on itère est rarement une bonne idée.
Post by Jerome
}
$k++;
je vois pas trop à quoi ça te sert d'incrémenter $k ici...
Post by Jerome
}
$j++;
Ni à quoi sert "$j" exactement
Post by Jerome
}
}else{ //Sinon, mettre selectionner les donnée du mois choisi
???
Post by Jerome
}
}else{ //Sinon, je suis sur l'année N-1
}
$i++;
Ni à quoi sert "$i", qui est pour le moment indéfini.
Post by Jerome
}
Je pense que c'est pas terrible
Je pense surtout que tu ne comprend pas vraiment ce que tu fais. A vrai
dire, en l'état, moi non plus - j'ai renoncé a essayer de comprendre ton
bout de code.
Post by Jerome
vu que je n'obtiens qu'un enregistrement
dans le tableau $liste_artN et que je ne vois pas trop à quoi cela
correspond :-(
Et oui, c'est le problème de la "programmation accidentelle" (je te
laisse chercher la définition, mais je pense que le terme est assez
parlant !-).
Post by Jerome
Si qqn à une petite idée, je suis preneur.
tes données sont dans une base SQL ? Si oui, apprend à écrire la requête
SQL qui va bien. Regarde du côté des fonctions d'aggrégation et des
clauses "group by" et "having".

Sinon, commence par définir un jeu de données "entrées" pour $tableau,
et le résultat auquel tu devrais arriver à partir de ces données. Ca te
permettra de mettre ton code au point plus facilement, et ça nous aidera
éventuellement à t'aider (si on sais ce que tu a en entrée et ce que tu
dois avoir en sortie, c'est plus facile de réfléchir à comment passer de
l'un à l'autre et de vérifier si on y arrive bien).
Olivier Miakinen
2010-02-04 10:40:20 UTC
Permalink
Post by Bruno Desthuilliers
Et oui, c'est le problème de la "programmation accidentelle" (je te
laisse chercher la définition, mais je pense que le terme est assez
parlant !-).
Le terme est assez parlant en effet. Sinon, une rapide recherche donne
trois utilisations de ce terme, deux par un certain Bruno Desthuilliers,
l'autre par un dénommé bruno modulix.

Je cite ce dernier :

<cit. news:428334fd$0$316$***@news.free.fr>

["programmation accidentelle" :
le programme 'tombe en marche', mais on ne sait pas pourquoi. Ce qui est
certain, c'est qu'un jour il tombera en panne, et on ne saura toujours
pas pourquoi, puisqu'on ne savait pas pourquoi il semblait fonctionner.
]

</cit.>
Bruno Desthuilliers
2010-02-04 11:41:43 UTC
Permalink
Olivier Miakinen a écrit :
(snip)
Post by Olivier Miakinen
Le terme est assez parlant en effet. Sinon, une rapide recherche donne
trois utilisations de ce terme, deux par un certain Bruno Desthuilliers,
l'autre par un dénommé bruno modulix.
<hs>
Se pourrait-il que "bruno modulix" et bruno desthuilliers soient une
seule et même personne ?-)
</hs>

NB : le terme anglo-saxon "programming by accident" donne plus de résultats:

http://www.google.com/search?q=programming+by+accident
Jerome
2010-02-05 11:54:21 UTC
Permalink
Merci Bruno pour ta réponse et ta patience
Post by Bruno Desthuilliers
Post by Jerome
);
$tableau[$t]=$ligne;
$t++;
Tu n'a pas besoin de gérer les indices comme çà. Il suffit d'ajouter "à
$tableau[] = $ligne;
Merci pour cette info je corrige
Post by Bruno Desthuilliers
Accessoirement, "$tableau", c'est pas terrible comme nom.
modifié aussi
Post by Bruno Desthuilliers
Post by Jerome
}while (odbc_fetch_row($RECUP_LPV));
Une fois cette récupération faite (j'ai bon ou pas ?),
Tu n'a pas testé ton code ?
Si je l'ai testé et ça marche je me demandais juste si c'était la bonne
(meilleure) méthode
Post by Bruno Desthuilliers
Et je note que tu a vraiment un problème avec le nommage. Déjà, évite le
franglais autant que possible, ensuite décide-toi pour une convention de
nommage (all_lower ou mixedCase) et tiens-y toi une bonne fois pour
toute. Ca évite bien des typos, qui sont très pénibles à débugger en PHP.
Je vais essayer d'arranger ça
Post by Bruno Desthuilliers
Post by Jerome
$j++;
"$j" non défini.
j'ai nettoyé les variables non utilisées
Post by Bruno Desthuilliers
Post by Jerome
}else{
$k=0;
foreach($liste_artN as $toto){
(Argh ! Non, pas "$toto" !)
A ce stade, tu a au mieux un élément dans $liste_artN.
Post by Jerome
if ($toto['code'] == $element['code']){
$tab=array(
"code" => $toto['code'],
"quantite" => $element['quantite']+$toto['quantite'],
"mois" => "*",
"annee" => $element['annee'],
"montant" => $element['montant']+$toto['montant']
);
$liste_artN[$k]=$tab;
Et si jamais tu avais un élément dans $liste_artN, tu viens de l'écraser.
j'ai enfin compris ça
Post by Bruno Desthuilliers
Post by Jerome
break;
}
else{
$liste_artN[] = $element;
Toujours dans le cas (improbable vu le code que tu montres) où tu aurais
un élément dans $liste_artN[], tu viens de le dupliquer. Accessoirement,
modifier un tableau sur lequel on itère est rarement une bonne idée.
je met ci-dessous un code qui fonctionne après avoir pris en compte tes
remarques. Par contre, j'ai continué à modifier le tableau que j'itère :S

1) ma requete récupère pour les années N et N-1 tous les codes articles
vendus, leurs quantité, la date de vente et le montant.
2) je mets les données dans le tableau $donnees_brutesBDD
3)je veux créer un nouveau tableau $liste_artN qui contiendra les
données agrégées. Cad, une ligne par article avec un cumul des quantités
et des montants.
4)Quand le code pour l'année sera bon, je le dupliquerais pour faire un
second tableau contenant un enregistrement par code ET par mois. pour
ensuite mettre en page des statistiques de vente comparatives (mois par
mois, année par année, ...)

==> le code ci-dessous que j'ai réalisé suite à tes conseils et des
recherches fonctionne enfin, mais est-ce la meilleure méthode ?

do{
$Date = odbc_result($RECUP_LPV,10);
$anne_pie = substr($Date,0,4);
$mois_pie = substr($Date,5,2);

$ligne_article=array(
"code" => odbc_result($RECUP_LPV,6),
"quantite" => odbc_result($RECUP_LPV,7),
"mois" => $mois_pie,
"annee" => $anne_pie,
"montant" => odbc_result($RECUP_LPV,8)
);
$donnees_brutesBDD[]=$ligne_article;
}while (odbc_fetch_row($RECUP_LPV));

foreach($donnees_brutesBDD as $ligne_article)
{
if($ligne_article['annee']==$anneeN){ //Si je suis sur l'année N
($anneeN est initialisé au début du code à l'année en cours soit 2010)
if($num_mois_texte=='00'){ //$num_mois_texte est transmis par un
formulaire , c'est 00 pour obtenir l'année compète, 01 pour le mois de
janvier, 02 pour février ...
if ($premier_enregistrement_anneeN){ //initialisé à true en début de scipt
$liste_artN[] = $ligne_article;
$liste_artN['0']['mois'] = "***";
$premier_enregistrement_anneeN=false;
}else{
foreach($liste_artN as $cle => $ligne_artN)
{
if($ligne_artN['code']==$ligne_article['code']){
$position=$cle;
break;
}else {$position="";}
}
if($position==""){
$tab_intermediare = $ligne_article;
$liste_artN[]=$tab_intermediare;
$liste_artN[count($liste_artN)-1]['mois'] = "*";
}else{
$tab_intermediare=array(
"code" => $ligne_article['code'],
"quantite" =>
$ligne_article['quantite']+$liste_artN[$position]['quantite'],
"mois" => "*",
"annee" => $ligne_article['annee'],
"montant" => $ligne_article['montant']+$liste_artN[$position]['montant']
);
$liste_artN[$position]=$tab_intermediare;
}
}
}else{ //Si $num_mois_texte != '00' alors on fera un tableau cumulant
les article par mois
}
}else //si je ne suis pas sur l'année N (2010) alors je suis sur
l'année N-1 et je remplirai le tableau pour N-1
{
}
}

Merci encore pour ton aide et désolé pour le codage initial *un peu*
brouillon. J'espère que là c'est mieux
@+
Olivier Miakinen
2010-02-05 12:15:07 UTC
Permalink
[...] est-ce la meilleure méthode ?
Bruno t'avait déjà répondu ceci :

<cit. news:4b6a9c4e$0$12192$***@news.free.fr>
tes données sont dans une base SQL ? Si oui, apprend à écrire la requête
SQL qui va bien. Regarde du côté des fonctions d'aggrégation et des
clauses "group by" et "having".
</cit.>

Je pense en effet que c'est ça, la meilleure méthode (quoique je sois
incompétent pour expliquer comment faire).


Soit dit en passant, puisque ton adresse est manifestement invalide, il
serait bienvenu de la signaler correctement comme telle, en la faisant
suivre par les 8 caractères « .invalid » (TLD réservé à cet effet auprès
de l'IANA). Donc :
Jerome <***@ySaPhAoMo.fr.invalid>
Jerome
2010-02-05 17:17:42 UTC
Permalink
Post by Bruno Desthuilliers
[...] est-ce la meilleure méthode ?
tes données sont dans une base SQL ? Si oui, apprend à écrire la requête
SQL qui va bien. Regarde du côté des fonctions d'aggrégation et des
clauses "group by" et "having".
</cit.>
Je pense en effet que c'est ça, la meilleure méthode (quoique je sois
incompétent pour expliquer comment faire).
J'interroge la BDD via un driver ODBC spécifique à l'ERP.
Or il s'avère que ce driver est d'une *effroyable* lenteur.
Je préfère donc récupérer en une seule fois toutes mes données dans
l'ordre où elles arrivent (dans l'exemple dont il est question, je
récupère uniquement les enregistrement des années N et N-1).
Car même avec access, la fonction groupby me fait planter le traitement!

Et ensuite utiliser php pour trier et mettre en forme.
Post by Bruno Desthuilliers
Soit dit en passant, puisque ton adresse est manifestement invalide, il
serait bienvenu de la signaler correctement comme telle, en la faisant
suivre par les 8 caractères « .invalid » (TLD réservé à cet effet auprès
Merci de l'info et de la réponse

@+
Bruno Desthuilliers
2010-02-08 15:55:15 UTC
Permalink
Post by Jerome
Post by Bruno Desthuilliers
[...] est-ce la meilleure méthode ?
tes données sont dans une base SQL ? Si oui, apprend à écrire la requête
SQL qui va bien. Regarde du côté des fonctions d'aggrégation et des
clauses "group by" et "having".
</cit.>
Je pense en effet que c'est ça, la meilleure méthode (quoique je sois
incompétent pour expliquer comment faire).
J'interroge la BDD via un driver ODBC spécifique à l'ERP.
Or il s'avère que ce driver est d'une *effroyable* lenteur.
Mmm... Que quelqu'un m'arrête si je dis une connerie (je ne suis pas un
pro d'ODBC), mais PAQJS, le driver ODBC ne sert que d'intermédiaire
entre le SGBDR et le langage hôte ? Si oui, ses performances propres ne
devraient pas impacter le temps de traitement de la requête par le
SGBDR, seulement les temps de connexion, d'envoi de la requête, et de
récupération des résultats ?
Post by Jerome
Je préfère donc récupérer en une seule fois toutes mes données dans
l'ordre où elles arrivent (dans l'exemple dont il est question, je
récupère uniquement les enregistrement des années N et N-1).
Ca fait quel volume de données ? Avec les données de prod, je veux dire...
Post by Jerome
Car même avec access, la fonction groupby me fait planter le traitement!
???

Pour quelle définition de "planter" ? Encore une fois, je ne suis pas un
pro de ODBC, mais j'ai du mal à croire que le driver soit responsable.
Comment se comporte ta requête en la lançant directement (pas via PHP) ?
Bruno Desthuilliers
2010-02-05 17:17:42 UTC
Permalink
Jerome a écrit :
(snip)
Post by Jerome
1) ma requete récupère pour les années N et N-1 tous les codes articles
vendus, leurs quantité, la date de vente et le montant.
2) je mets les données dans le tableau $donnees_brutesBDD
3)je veux créer un nouveau tableau $liste_artN qui contiendra les
données agrégées. Cad, une ligne par article avec un cumul des quantités
et des montants.
Et tu t'emmerdes pour rien à réinventer la roue carrée. C'est
typiquement un truc qui se fait en _une seule_ requête SQL, en utilisant
(entre autres, mais essentiellement) SUM() et GROUP BY.

Sérieusement, fais-toi une faveur : jette ce code, et apprend SQL. C'est
très exactement à ça que ça sert.
Post by Jerome
4)Quand le code pour l'année sera bon, je le dupliquerais pour faire un
second tableau contenant un enregistrement par code ET par mois.
Idem.
Post by Jerome
pour
ensuite mettre en page des statistiques de vente comparatives (mois par
mois, année par année, ...)
PHP ne devrait te servir ici qu'à communiquer avec la base et formatter
le résultat - pas à faire tous ces calculs.
Post by Jerome
==> le code ci-dessous que j'ai réalisé suite à tes conseils et des
recherches fonctionne enfin, mais est-ce la meilleure méthode ?
réponse ci-dessus.
Post by Jerome
do{
$Date = odbc_result($RECUP_LPV,10);
$anne_pie = substr($Date,0,4);
$mois_pie = substr($Date,5,2);
$ligne_article=array(
"code" => odbc_result($RECUP_LPV,6),
"quantite" => odbc_result($RECUP_LPV,7),
"mois" => $mois_pie,
"annee" => $anne_pie,
"montant" => odbc_result($RECUP_LPV,8)
);
$donnees_brutesBDD[]=$ligne_article;
}while (odbc_fetch_row($RECUP_LPV));
foreach($donnees_brutesBDD as $ligne_article)
{
if($ligne_article['annee']==$anneeN){ //Si je suis sur l'année N
($anneeN est initialisé au début du code à l'année en cours soit 2010)
if($num_mois_texte=='00'){ //$num_mois_texte est transmis par un
formulaire , c'est 00 pour obtenir l'année compète, 01 pour le mois de
janvier, 02 pour février ...
if ($premier_enregistrement_anneeN){ //initialisé à true en début de scipt
$liste_artN[] = $ligne_article;
$liste_artN['0']['mois'] = "***";
pourquoi '0' ?

Ah, au fait, y a un truc un peu piégeux avec les "tableaux" de PHP:

<?php
$t = array(
'0' => "zero",
'1' => "un",
'2' => "deux",
);

$t[0] = "gotcha";

echo "<pre>";
var_dump($t);
echo "</pre>";
?>
Post by Jerome
$premier_enregistrement_anneeN=false;
}else{
foreach($liste_artN as $cle => $ligne_artN)
{
if($ligne_artN['code']==$ligne_article['code']){
$position=$cle;
break;
}else {$position="";}
}
Bel effort pour le nommage, mais ton formattage est une abomination, je
n'arrive même pas à comprendre où commencent et finissent les blocs.

(snip le reste)

Bon, je répète: jette ce code et apprend à utiliser correctement une
base SQL. Je ne sais pas quels volumes de données tu t'attends à gérer,
mais ta solution est quadruplement inefficace:

1/ il y a peu de chance que du code PHP dupliquant des fonctionalités de
base d'un SGBDR - fonctionnalités implémentées dans un langage de bas
niveau et hautement optimisées - montre les mêmes performances

2/ d'autant moins quand tu dois commencer par charger toutes les données
en mémoires

3/ et encore moins quand tu fais des recherches séquentielles (cf le
bout de code ci dessus) au lieu d'utiliser un index... (heu, attend,
indexer, c'est un truc de SGBDR, non ?)

Est-ce que tu imagine ce que ça va donner avec quelques centaines de
milliers d'enregistrement dans la base ?

Ah oui, et pour le point 4/ : la requête SQL KiVaBien(tm) prend
probablement moins de temps à écrire qu'il ne m'en a fallu pour essayer
de lire ton code !-)
Continuer la lecture sur narkive:
Loading...