Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

tri tableau

8 réponses
Avatar
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++;
}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

8 réponses

Avatar
Bruno Desthuilliers
Jerome a écrit :
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.

}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 ?

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){



"$ligne" dans le code précédent, "$element" ici... pourquoi ?

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 ?

if($num_mois='00'){ //Si je veux les données sur l'année entière



Idem: "$num_mois" n'est pas défini.

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.

$liste_artN['0'] = $element;



"$liste_artN" non défini.

$Firsttime_anneeNúlse;
$j++;



"$j" non défini.

}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.

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.

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.

}
$k++;



je vois pas trop à quoi ça te sert d'incrémenter $k ici...

}
$j++;



Ni à quoi sert "$j" exactement

}
}else{ //Sinon, mettre selectionner les donnée du mois choisi



???

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

}
$i++;



Ni à quoi sert "$i", qui est pour le moment indéfini.

}




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.

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 !-).

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).
Avatar
Olivier Miakinen
Le 04/02/2010 11:17, Bruno Desthuilliers a écrit :

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$

["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.>
Avatar
Bruno Desthuilliers
Olivier Miakinen a écrit :
(snip)
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
Avatar
Jerome
Merci Bruno pour ta réponse et ta patience

Bruno Desthuilliers a écrit :

);
$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;



Merci pour cette info je corrige

Accessoirement, "$tableau", c'est pas terrible comme nom.



modifié aussi


}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



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

$j++;



"$j" non défini.



j'ai nettoyé les variables non utilisées

}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.

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



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úlse;
}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
@+
Avatar
Olivier Miakinen
Le 05/02/2010 12:54, Jerome a écrit :

[...] est-ce la meilleure méthode ?



Bruno t'avait déjà répondu ceci :

<cit. news:4b6a9c4e$0$12192$
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
Avatar
Jerome
Olivier Miakinen a écrit :
Le 05/02/2010 12:54, Jerome a écrit :

[...] est-ce la meilleure méthode ?



Bruno t'avait déjà répondu ceci :

<cit. news:4b6a9c4e$0$12192$
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.


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


Merci de l'info et de la réponse

@+
Avatar
Bruno Desthuilliers
Jerome a écrit :
(snip)

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.

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.

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.

==> 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.

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>";
?>



$premier_enregistrement_anneeNúlse;
}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 !-)
Avatar
Bruno Desthuilliers
Jerome a écrit :
Olivier Miakinen a écrit :
Le 05/02/2010 12:54, Jerome a écrit :

[...] est-ce la meilleure méthode ?



Bruno t'avait déjà répondu ceci :

<cit. news:4b6a9c4e$0$12192$
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 ?

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...

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) ?