ScriptBonjour à tous,
Je dispose d’une base de données dans laquelle j’aimerais créer une nouvelle colonne à partir d’une formule ou d’un script.
Voici un aperçu de la base de données :

- la colonne T représente des opérations à effectuer
- la colonne X_3 représente une particularité
- La colonne op représente des objets
Le but est de créer une colonne « bilan » dans laquelle on ajoute « ko » et le numéro correspondant à « op » lorsque la somme des défauts est différentes d’une ligne à une autre pour un même « obj » (ici valeur égale à A).
Dernière particularité, la colonne bilan doit être remplie pour la numéro des opérations « 3061 ».
Il s’agit ici d’un aperçu de la base de données, la colonne obj vaut « A » mais dans la base de données cette colonne change de valeur.
Merci pour vos réponses !
Automation and ScriptingObjet : ScénarioPourquoi la ligne 6 op 180 n'est-elle pas ajoutée à la dernière colonne ? 0 diffère de 1.
(Vous devriez utiliser des titres de publication plus informatifs qu'un seul mot)
Re: ScriptCar la somme est égale à 0 pour la ligne 6. En fait, c'est plutôt quand la somme des défauts est différente de la valeur 0 alors on renseigne la valeur de "op" dans la colonne "bilan".
Objet : ScénarioAlors est-il nécessaire de vérifier si les valeurs diffèrent entre deux lignes ? Ou êtes-vous simplement intéressé par les lignes qui ont :op autre que 0 ?
Re: Scriptje pense que nous pouvons nous intéresser seulement aux lignes où la valeur de :somme défaut est différente de 0. Car quand la valeur de :somme défaut vaut 0 alors on se renseigne rien dans la colonne bilan.
Re: ScriptMerci pour votre réponse !
En comparant les deux méthodes, il me semble que la seconde est préférable pour mon cas de figure.
Je l’ai adapté à ma base de données, les colonnes ont les mêmes formats sur les deux bases de données et j’obtiens ce type d’erreur :

Objet : ScénarioComme le message d'erreur est en français, je ne le comprends pas. Il se peut que l'erreur soit finalement en vous disant que vous n'avez pas de colonne bilan3. (Il dit qu'il y a un indice invalide mais cela est dû au fait qu'il n'y a pas de colonne bilan3. En effet, dt[input_loc, "bilan3"] renverra [](1, 0) si vous n'avez pas la colonne et que vous essayez ensuite de lui attribuer des valeurs).
Re: ScriptCela provient du fait que la variable "input_loc" est vide. Donc pour l'affectation des nouvelles cellules dans la colonne "bilan3" c'est impossible.
Objet : ScénarioLa valeur "3061" (caractère, pas nombre) est introuvable dans la colonne "T". De plus, la vérification que j'ai implémentée pour gérer input_loc vide est incorrecte, vous devez la modifier en < 1 au lieu de < 0.
Objet : ScénarioCe script fait les deux et fonctionne avec l'exemple fourni. Je vous suggère fortement d'essayer de comprendre ce qu'il fait et de demander s'il y a des parties que vous ne comprenez pas.
Names Default To Here(1);
dt = Open("$DOWNLOADS/AAA.jmp");
dt << New Column("bilan2", Character, Nominal);
dt << New Column("bilan3", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
/* comparing rows */
For Each({unique_object}, unique_objects,
object_rows = Loc(m_obs, unique_object);
values = dt[object_rows, "SOMME DEFAUT"];
values1 = Remove(values, 1);
values2 = Remove(values, N Items(values));
differences = [0] |/ values1 - values2;
ops = dt[object_rows[Loc(differences != 0)], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
input_loc = Loc(dt[object_rows, "T"], "3061");
If(N Items(input_loc) < 0,
continue();
,
dt[input_loc, "bilan2"] = Repeat({result_str}, N Items(input_loc));
);
);
/* zeros */
For Each({unique_object}, unique_objects,
object_rows = Loc(m_obs, unique_object);
values = dt[object_rows, "SOMME DEFAUT"];
ops = dt[object_rows[Loc(values)], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
input_loc = Loc(dt[object_rows, "T"], "3061");
If(N Items(input_loc) < 1,
continue();
,
dt[input_loc, "bilan3"] = Repeat({result_str}, N Items(input_loc));
);
);

Edit : Modification de l'instruction if Si(N éléments(input_loc) ... de < 0 à < 1
Re: ScriptDans la base de données, les valeurs de la colonne :T ne sont pas forcement rangés dans l'ordre croissant pour un même type d'objet. C'est une autre colonne :OPE qui elle, ses éléments sont rangés dans l'ordre croissant. Les colonnes :T et :OPE sont étroitement liées, elles sont uniques pour chaque type d'objet.
Les :OPE qui sont inférieures aux valeurs :OPE correspondantes à la valeur 3061 on ne doit rien mettre dans la colonne bilan.
Lorsque les valeurs de :OPE sont supérieures aux valeurs :OPE correspondantes à la valeur 3061 alors on réalise l'opération déjà décrite dans les premiers messages.
Voir la BD ci-dessous comme exemple :

Merci pour vos réponses !!
Objet : ScénarioAjoutez des vérifications supplémentaires pour les valeurs :OPE. Si la valeur :OPE pour la ligne est inférieure à la valeur :OPE pour "3061", ignorez-la. Il peut être un peu difficile de suivre les différents index et lignes, mais l'ajout d'impressions de débogage aide à cela. De plus, s'il peut y avoir plus d'un "3061" pour un objet, le calcul devient plus compliqué.
Re: ScriptOui je vois ce que vous voulez dire !
J'imagine quelque chose qui ressemble à cela :
If( col = Loc(dt[Row(), :OPE] < Loc(dt[Row(), :T=="3061")),
continue();
,
script...
);
Par contre il est impossible que le même objet possède 2 fois le numéro 3061.
Re: ScriptCela ne fonctionne pas, savez vous comment je peux réaliser un tel script @jthi (les dernières vérifications à faire) ?
Merci encore de votre aide !
Objet : ScénarioObtenez toutes les valeurs :OPE pour unique_object, puis obtenez la valeur :OPE pour la ligne 3061. Après cela, vérifiez dans la liste de toutes les valeurs :OPE les indices qui sont supérieurs à la valeur :OPE pour 3061 (Loc() peut le faire).
Re: ScriptOui c'est ce que je me suis dis, j'ai pensé à quelque chose comme cela mais la difficulté reste de définir les variables a et b.
dt = current data table();
b = // all values :OPE for unique_object
a = // values :OPE for 3061
test = Loc(dt[Row(), b]) > Loc(dt[Row(),a]);
If( test=0 ,
continue();
,
script...;
);
Objet : ScénarioMéthode similaire à celle utilisée pour la variable values qui stocke les valeurs :SOMME DEFAUT pour un objet unique spécifique
values = dt[object_rows, "SOMME DEFAUT"];
ajoutez des impressions de débogage et essayez d'exécuter le script une ligne à la fois en utilisant un seul objet
Re: ScriptOui merci j'ai écris un code comme ceci qui me permet d'avoir les infos dont j'ai besoin :
dt = current data table();
For Each({unique_objects}, unique_objects,
object_rows = Loc(m_obs, unique_objects);
b = dt[object_rows, "OPE"];
show(b);
a = dt << Get Rows Where( :T == "3061");
valeurs_OPE = :OPE[a];
show(valeurs_OPE);
valeurs_OPE_3061_obj = dt[unique_objects, "valeurs_OPE"];
show(valeurs_OPE_3061_obj);
);Cependant je n'arrive pas à avoir les valeurs de OPE correspondantes à la tache 3061 par :obj (variable "valeurs_OPE_3061_obj").
Seulement la variable "valeurs_OPE" regroupe toutes les données de OPE correspondantes à la tache 3061.
Objet : ScénarioIl est plus facile de tester si vous ignorez simplement For Each (pour l'instant). Commencez par quelque chose comme ça
Names Default To Here(1);
// dt = Open("$DOWNLOADS/AAA.jmp");
// dt = Current Data Table();
dt = New Table("AAA(1)",
Add Rows(12),
Compress File When Saved(1),
New Column("obj", Character(16), "Nominal", Set Values({"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "C", "C"})),
New Column("T", Character(4), "Ordinal", Set Values({"3052", "3061", "3082", "3940", "4012", "5010", "2890", "4060", "3061", "3081", "5010", "3061"})),
New Column("OPE", Numeric, "Continuous", Format("Best", 12), Set Values([12, 20, 32, 44, 56, 125, 210, 54, 60, 80, 45, 50])),
New Column("X__3", Character(4), "Nominal", Set Values({"rien", "rien", "incl", "ret", "ret", "rien", "incl", "incl", "ret", "incl", "ret", "rien"})),
New Column("SOMME DEFAUT", Numeric, "Continuous", Format("Best", 12), Set Values([0, 0, 1, 2, 1, 0, 2, 1, 2, 1, 1, 0])),
New Column("op", Character(12), "Nominal", Set Values({"40", "32", "55", "212", "510", "180", "2100", "2240", "2100", "500", "", ""})),
New Column("correct", Character, "Nominal", Set Values({"", "ko - 55 / ko - 212 / ko - 510 / ko - 2100", "", "", "", "", "", "", "ko - 500", "", "", "."}))
);
dt << New Column("bilan", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
unique_object = unique_objects[2];
object_rows = Loc(m_obs, unique_object);
input_loc = Loc(dt[object_rows, "T"], "3061"); // location of 3061 for unique_object
show(input_loc); // index within object_rows
show(object_rows[input_loc]); // real row number
opes = dt[object_rows, "OPE"]; // all OPE values for unique_object
valid_ope_idx = Loc(...//Re: Script
J'ai continué avec le script suivant :
Names Default To Here(1);
dt = current data table();
dt << New Column("BILAN", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
dt = current data table();
For Each({unique_objects}, unique_objects,
object_rows = Loc(m_obs, unique_objects); // lignes pour chaque obj
b = dt[object_rows, "OPE"]; // les différentes opé pour chaque obj
show(b);
input_loc = Loc(dt[object_rows, "T"], "3061"); // localiser 3061 pour chaque objet
z = object_rows[input_loc]; // localiser les lignes OPE 3061 pour chaque obj
value_OPE_3061 = :OPE[z]; // valeur de l'ope 3061 pour chaque obj
show(value_OPE_3061);
//valid_ope_idx = Loc(b > value_OPE_3061);<BR /> //show(valid_ope_idx);
For( i = 1, i <= N Items(b), i++,
If(N Items(input_loc) < 1 & b[i] <= value_OPE_3061,
continue();
,
values = dt[object_rows, "SOMME DEFAUT"];
ops = dt[object_rows[Loc(values)], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
dt[object_rows[input_loc], "BILAN"] = Repeat({result_str}, N Items(input_loc));
);
);
);J'ai d'abord utilisé la fonction Loc() pour déterminer les indices des lignes mais ensuite je ne sais pas comment continuer le script . Alors j'ai essayé avec une boucle "For" et le résultat n'est toujours pas correct. Pouvez-vous m'aider à avancer ?
Merci d'avance pour toute réponse !
Objet : ScénarioIl est inutile d'ajouter For Each Row jusqu'à ce que d'autres parties du script fonctionnent. Vous pouvez continuer avec l'exemple que j'ai fourni jusqu'à ce que la valeur correcte soit définie sur la ligne 9 (en raison de l'utilisation de unique_objects[2] qui est
. Pour obtenir des indices OPE supérieurs à l'OPE des lignes "3061", vous pouvez utiliser Loc comme ceci.
valid_ope_idx = Loc(opes > opes[input_loc]);
Notez qu'il s'agit d'indices dans la matrice opes PAS de lignes de la table de données. Pour les reconvertir en lignes, vous pouvez utiliser ces indices avec object_rows car object_rows est une matrice avec des lignes pour l'objet unique spécifique
Re: ScriptOui je suis d’accord avec vous !
Les valeurs que je trouve avec ma formule sont correctes et je trouve la même chose que vous.
Cependant c’est dans la construction de la suite du script où j’ai plus de mal !
Car je dois retourner les valeurs « ko-..... / ko-... » lorsque :OPE est supérieure à :OPE correspondante à :T = 3061 et lorsque la :SOMME DEFAUT est différente de 0 (comme dans l’exemple).
Objet : ScénarioEux vous continuez avec une idée similaire
- Ajouter vérifier qu'il y a plus de 0 éléments dans valid_ope_idx
- Obtenir toutes les valeurs pour valid_ope_idx
- Ensuite, à partir de cela, obtenez les indices des valeurs supérieures à 0
- Et puis avec cela, vous pouvez enfin obtenir les valeurs de :op pour ces indices spécifiques (n'oubliez pas de les convertir en lignes en premier)
- Concaténer ces valeurs ensemble en utilisant Concat Items()
- Ajouter une valeur à la ligne correcte
Re: ScriptDans ma base de données de test cela marche correctement avec le code suivant :
Names Default To Here(1);
dt = current data table();
dt << New Column("BILAN", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
somme_col = Filter Each( {col_name}, dt << Get Column Names( "String", Continuous ),
Starts With( col_name, "SOMME" )
);
dt = current data table();
For Each({unique_objects}, unique_objects,
object_rows = Loc(m_obs, unique_objects); // lignes pour chaque obj
b = dt[object_rows, "OPE"]; // les différentes opé pour chaque obj
show(b);
input_loc = Loc(dt[object_rows, "T"], "3061"); // localiser 3061 pour chaque objet
z = object_rows[input_loc]; // localiser les lignes OPE 3061 pour chaque obj
value_OPE_3061 = :OPE[z]; // valeur de l'ope 3061 pour chaque obj
show(value_OPE_3061);
valid_ope_idx = Loc(b > value_OPE_3061 & dt[object_rows,somme_col] > 0) ;
show(valid_ope_idx);
if( N items(valid_ope_idx) < 1,
continue();
,
ops = dt[object_rows[valid_ope_idx], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
dt[object_rows[input_loc], "BILAN"] = Repeat({result_str}, N Items(input_loc));
);
);Cependant, dans ma base de données finale, il est possible que pour un même obj plusieurs fois la valeur :T = 3061 est affichée (par contre les valeurs de OPE sont les mêmes !).
Je pense qu’il faut donc modifier encore quelque chose, il faut que la valeur de valeur_OPE_3061 soit unique (et pas par exemple value_OPE_3061 = [ 50 , 50 , 50 ] mais plutôt value_OPE_3061 = [ 50 ]).
Existe-t-il une fonction sur JMP permettant de supprimer les doublons d’une matrice/liste ?
Merci pour vos réponses !
Objet : ScénarioJe pensais plus tôt que vous aviez dit qu'il était impossible qu'il y ait plusieurs valeurs "3061" ?
Une option pour supprimer les doublons consiste à utiliser Associative Array() avec << get keys (ne fonctionne pas si vous avez des flottants), un autre avantage dans ce cas serait d'utiliser Design(<
Re: ScriptJ'ai rajouté cette partie cela fonctionne encore mieux :
Names Default To Here(1);
dt = current data table();
dt << New Column("BILAN", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
somme_col = Filter Each( {col_name}, dt << Get Column Names( "String", Continuous ),
Starts With( col_name, "SOMME" )
);
dt = current data table();
For Each({unique_objects}, unique_objects,
object_rows = Loc(m_obs, unique_objects); // lignes pour chaque obj
b = dt[object_rows, "OPE"]; // les différentes opé pour chaque obj
show(b);
input_loc = Loc(dt[object_rows, "T"], "3061"); // localiser 3061 pour chaque objet
if( N items(input_loc) < 1,
continue();
,
z = object_rows[input_loc]; // localiser les lignes OPE 3061 pour chaque obj
value_OPE_3061 = :OPE[z]; // valeur de l'ope 3061 pour chaque obj
liste={}; // transformer en liste pour supprimer les doublons
for (i = 1, i <= NRows(value_OPE_3061), i++,
for (j = 1, j <= NCols(value_OPE_3061), j++,
InsertInto(liste, value_OPE_3061[i, j]);
);
);
// supprimer les doublons
if( N items(liste) <= 1,
a = liste;
,
a = Left(liste,1);
);
// repasser en matrice pour faire les comparaisons
Mat_3061 = Matrix(a);
show(Mat_3061);
valid_ope_idx = Loc(b > Mat_3061 & dt[object_rows,somme_col] > 0) ;
show(valid_ope_idx);
if( N items(valid_ope_idx) < 1,
continue();
,
ops = dt[object_rows[valid_ope_idx], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
dt[object_rows[input_loc], "BILAN"] = Repeat({result_str}, N Items(input_loc));
);
);
);Effectivement vous avez raison @jthi, mais je parlais que pour une valeur 3061 d'un :obj il ne peut pas y avoir différentes valeurs de la variable :OPE (après dans un obj il peut y avoir 2 fois par exemple la valeur :T égale à 3061 mais la valeur :OPE sera la même).
Au final, en sortie, j'aimerais que l'affichage ne se répète pas lorsqu'il y a plusieurs fois la valeur :T égale à 3061 pour un même :obj.
Exemple :

Avec un script comme celui-ci :
input_loc = Loc(dt[object_rows, "T"], "3061");// localiser 3061 pour chaque objet
liste2={}; // transformer en liste pour supprimer les doublons
for (i = 1, i <= NRows(input_loc), i++,
for (j = 1, j <= NCols(input_loc), j++,
InsertInto(liste2, input_loc[i, j]);
);
);
// supprimer les doublons
if( N items(liste2) <= 1,
c = liste2;
,
c = Left(liste2,1);
);
// repasser en matrice pour faire les comparaisons
loc_3061 = Matrix(c);
Cela fonctionne correctement, je prends le premier indice correspondant à :T égale à 3061.
Mais comme sur la capture ci-dessus, j'aimerais pouvoir enlever les éléments en double sur la même ligne :
ko - 2203 / ko - 2203 --> ko - 2203
Objet : ScénarioVous pouvez simplement choisir le premier index qui a la valeur 3061 pour l'objet.
Objet : ScénarioQuelque chose comme ça, c'est comme ça que j'aurais résolu ce problème. Devrait fonctionner avec les exemples de données
Names Default To Here(1);
// dt = Open("$DOWNLOADS/AAA.jmp");
// dt = Current Data Table();
dt = New Table("AAA(1)",
Add Rows(12),
Compress File When Saved(1),
New Column("obj", Character(16), "Nominal", Set Values({"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "C", "C"})),
New Column("T", Character(4), "Ordinal", Set Values({"3052", "3061", "3082", "3940", "4012", "5010", "2890", "4060", "3061", "3061", "3081", "5010", "3061"})),
New Column("OPE", Numeric, "Continuous", Format("Best", 12), Set Values([12, 20, 32, 44, 56, 125, 210, 54, 60, 60, 80, 45, 50])),
New Column("X__3", Character(4), "Nominal", Set Values({"rien", "rien", "incl", "ret", "ret", "rien", "incl", "incl", "ret", "ret", "incl", "ret", "rien"})),
New Column("SOMME DEFAUT", Numeric, "Continuous", Format("Best", 12), Set Values([0, 0, 1, 2, 1, 0, 2, 1, 2, 2, 1, 1, 0])),
New Column("op", Character(12), "Nominal", Set Values({"40", "32", "55", "212", "510", "180", "2100", "2240", "2100", "2100", "500", "", ""}))
);
dt << New Column("bilan", Character, Nominal);
Summarize(dt, unique_objects = by(:obj));
m_obs = dt[0, "obj"];
For Each({unique_object}, unique_objects,
object_rows = Loc(m_obs, unique_object);
input_loc = Loc(dt[object_rows, "T"], "3061");
If(N Items(input_loc) == 0,
continue();
//Throw("3061 not found");
, N Items(input_loc) > 0,
input_loc = input_loc[1];
);
opes = dt[object_rows, "OPE"];
valid_ope_idx = Loc(opes > opes[input_loc]);
If(N Items(valid_ope_idx) < 1,
result_str = ".";
,
values = dt[object_rows[valid_ope_idx], "SOMME DEFAUT"];
ops = dt[object_rows[valid_ope_idx[Loc(values)]], "op"];
result_str = "ko - " || Concat Items(ops, " / ko - ");
);
dt[object_rows[input_loc], "bilan"] = result_str;
);