Le forum (ô combien francophone) des utilisateurs de Powerbuilder.




Bonjour à tous,
Je souhaiterais créer une fonction qui reprend le traditionnel RowsCopy mais en l'améliorant.
En fait celle-ci permettrait de copier les lignes d'une dw vers une autre sans que les 2 aient les memes colonnes.
Pour cela, je compte m'y prendre en utilisant des SetItem mais je ne sais pas comment récupérer les colonnes des 2 dw ni leur position.
De plus, ma fonction doit avoir la meme syntaxe que celle du RowsCopy...à savoir
dw_1.RowsCopy (startrow, endrow, copybuffer, dw_2, beforerow, targetbuffer )
Merci d'avance
Dernière modification par Sebou (28-04-2008 12:13:00)
Hors ligne
va pour les noms de colonnes.
mais il faut que les colonnes soient de meme type.

Hors ligne











Effectivement, il faut que les colonnes soient de même type.
Par contre, tu peux travailler par numéro de colonne, et non par nom de colonne.
En bouclant sur toutes les colonnes, tu peux t'en sortir, à condition que celles-ci soient déclarées dans le même ordre
dans les deux datawindows (et que tu aies le même nombre de colonne dans chaque DW bien sûr)
Hors ligne




oui bien sur, ca c'est bon...c'est juste pour les noms de colonnes et le nombre de celles ci :x
En gros, je suis sur une colonne de la premiere DW, je regarde dans la 2nde si il y a une colonne de meme nom (le type est ok) si c'est le cas, j'insere la valeur de la colonne de la premiere DW dans la 2nde DW.
ET je continue ainsi pour chaque colonne de la 1ere DW ou plutot de la seconde
Hors ligne




foon a écrit:
Effectivement, il faut que les colonnes soient de même type.
Par contre, tu peux travailler par numéro de colonne, et non par nom de colonne.
En bouclant sur toutes les colonnes, tu peux t'en sortir, à condition que celles-ci soient déclarées dans le même ordre
dans les deux datawindows (et que tu aies le même nombre de colonne dans chaque DW bien sûr)
Justement, je n'ai pas le meme nombre de colonnes de chaque coté.
Exemple
DW 1 :
ID Nom Prenom Adresse CP Ville Tel
DW 2 :
Nom Prenom Tel Ville
Je dois faire une copie de la DW 1 dans DW 2 avec uniquement les champs de la DW 2. Sauf que mes colonnes ne sont pas forcément dans le meme ordre...
Hors ligne







Moi j'aurais plutôt opté pour la solution :
Avoir deux même datawindows dont une où l'on cacherait les colonnes que l'on a pas besoin.
Parce que là ton idée aboutira sur un code complètement spécifique a tes deux datawindow ( je ne vois pas comment il pourrait être utilisé sur d'autres datawindow dont la définition des colonnes differerait)
Moi je vois un code dans ce genre (je te le code en version algorithmique):
Pour ligne = startrow jusqu'a ligne = endrow Faire
// 1-
// La colonne n de ma dw_1 que je veux recopier dans la colonne m de ma dw_2
Variable contenu_colonne
contenu_colonne = dw_1.GetItemXXXX(ligne,n,copybuffer)
dw_2.SetItem(beforerow + 1, m, contenu_colonne)
// On incrémente beforerow pour bien alimenter toutes les valeurs à la suite
beforerow = beforerow + 1
// 2-
// Les autres colonnes que je veut alimenter
// Je recopie le 1- en adaptant avec les colonnes qu'il faut et le type de données
// a recopier
Fin Pour
Hors ligne











Pour récupérer le nom de la 1ère colonne:
dw_mydatawindow.Describe("#1.Name")
Pour récupérer le nombre de colonnes:
dw_mydatawindow.Describe("DataWindow.Column.Count")
Hors ligne




Ok merci pour vos reponses
Nephtis, merci pour ton aide mais j'peux pas m'en servir (le boss en veut pas lol)
J'ataque ca a 14h
Hors ligne














Bonjour,
A ce moment-là il faudra être très rigoureux sur les noms et types des colonnes, en bouclant sur les colonnes (produit cartésien) pour identifier les colonnes similaires et en utilisant les scripts de foon
bien sur, il y a matière à optimiser en vérifiant le type de données et en ne recomparant pas les colonnes à chaque ligne => faire d'entrée le produit cartésien et construire un tableau de correspondance col1[ col2 ] puis la boucle sur les lignes avec copie des données.
Hors ligne







Sebou a écrit:
Ok merci pour vos reponses
Nephtis, merci pour ton aide mais j'peux pas m'en servir (le boss en veut pas lol)
J'ataque ca a 14h
Juste par curiosité il (le boss ) ne veut pas le petit algo que j'ai fait ou il ne veut pas passer par une datawindow identique dont certains champs seraient caché?
Dernière modification par Nephtis (08-01-2008 13:23:24)
Hors ligne




Nephtis a écrit:
Sebou a écrit:
Ok merci pour vos reponses
Nephtis, merci pour ton aide mais j'peux pas m'en servir (le boss en veut pas lol)
J'ataque ca a 14hJuste par curiosité il (le boss
) ne veut pas le petit algo que j'ai fait ou il ne veut pas passer par une datawindow identique dont certains champs seraient caché?
Il ne veut pas que je passe par une datawindow dont certains champs seraient cachés...
En plus, quand il a vu que j'étais sur le forum...il me sort "Et ca, c'est du Power Builder ?"...Et béh oui !! Niark ^^ lol
Hors ligne




Bon béh après un peu de reflexion, j'en suis arrivé à ca...Vous en pensez koi ??
long ll_nb_colonne1, ll_nb_colonne2, ll_i, ll_j, ll_valeur, ll_pos_insert, ll_pos, ll_fin string ls_nom, ls_type, ls_coltype1, ls_coltype2, ls_valeur date ldt_valeur time lt_valeur datastore lds_ds, lds_dw_dest lds_ds = CREATE datastore lds_ds.DataObject = "d_util_liste_colonne" lds_ds.SetTransObject(sqlca) lds_dw_dest = CREATE datastore lds_dw_dest.DataObject = "d_util_liste_colonne" lds_dw_dest.SetTransObject(sqlca) // On compte d'abord le nombre de colonnes de chaque dataXXXXX ll_nb_colonne1 = long(p_dw_orig.Describe("DataWindow.Column.Count")) ll_nb_colonne2 = long(p_dw_dest.Describe("DataWindow.Column.Count")) FOR ll_i=1 TO ll_nb_colonne1 ll_pos = lds_ds.insertrow(0) ls_nom = p_dw_orig.Describe("#" + string(ll_i) +".Name") ls_type = p_dw_orig.Describe("#" + string(ll_i) +".Coltype") lds_ds.SetItem(ll_pos, 'num', ll_i) lds_ds.SetItem(ll_pos, 'nom', ls_nom) lds_ds.SetItem(ll_pos, 'type', ls_type) NEXT FOR ll_j=1 TO ll_nb_colonne2 ll_pos = lds_dw_dest.insertrow(0) ls_nom = p_dw_dest.Describe("#" + string(ll_j) +".Name") ls_type = p_dw_dest.Describe("#" + string(ll_j) +"Coltype") lds_dw_dest.SetItem(ll_pos, 'num', ll_j) lds_dw_dest.SetItem(ll_pos, 'nom', ls_nom) lds_dw_dest.SetItem(ll_pos, 'type', ls_type) NEXT ll_fin = lds_ds.RowCount() FOR ll_i = p_deb TO p_fin ll_pos_insert = p_dw_dest.insertrow(p_lig_insert) FOR ll_j=1 TO ll_fin ls_nom = lds_ds.GetItemString(ll_j, "nom") ls_type = lds_ds.GetItemString(ll_j, "type") ll_pos = lds_dw_dest.find("nom = '" + ls_nom + "' AND type = '" + ls_type + "'", 1, lds_dw_dest.RowCount()) // Si elle existe, alors on copie dans DW_dest IF ll_pos > 0 THEN IF upper(left(ls_type, 4)) = "CHAR" THEN ls_valeur = p_dw_orig.GetItemString(ll_i, 'ls_nom', p_buffer, FALSE) p_dw_dest.SetItem(ll_pos_insert, 'ls_nom', ls_valeur) END IF IF upper(left(ls_type, 4)) = "DATE" THEN ldt_valeur = p_dw_orig.GetItemDate(ll_i, 'ls_nom', p_buffer, FALSE) p_dw_dest.SetItem(ll_pos_insert, 'ls_nom', ldt_valeur) END IF IF upper(left(ls_type, 4)) = "DECI" OR upper(left(ls_type, 3)) = "INT" OR & upper(left(ls_type, 4)) = "LONG" OR upper(left(ls_type, 4)) = "NUMB" OR & upper(left(ls_type, 4)) = "REAL" THEN ll_valeur = p_dw_orig.GetItemNumber(ll_i, 'ls_nom', p_buffer, FALSE) p_dw_dest.SetItem(ll_pos_insert, 'ls_nom', ll_valeur) END IF IF upper(left(ls_type, 4)) = "TIME" THEN lt_valeur = p_dw_orig.GetItemTime(ll_i, 'ls_nom', p_buffer, FALSE) p_dw_dest.SetItem(ll_pos_insert, 'ls_nom', lt_valeur) END IF END IF NEXT NEXT
Dernière modification par Sebou (08-01-2008 16:16:41)
Hors ligne











Y'a de l'idée, par contre:
- N'oublies pas d'ajouter un "." devant "Coltype" afin de ne pas avoir de plantage à l'exécution de tes describe
- Dans ta deuxième boucle, tu vas avoir un souci car tu utilises le mauvais compteur (ll_i au lieu de ll_j )
De plus, ce n'est peut-être pas la peine de boucler sur tes DW pour charger des datastores sur lesquelles tu boucle de nouveau:
Autant tout faire en un seul passage
Hors ligne




Merci j'ai corrigé pour le "."
Par contre, dans la 2eme boucle, ce n'est pas une erreur. Il faut bien utiliser ll_i car je veux récupérer ici la valeur de la ligne de ma DW de départ. ll_j sert juste à parcourir ma datastore locale dans laquelle est contenue les différentes colonnes.
Hors ligne











Sebou a écrit:
Par contre, dans la 2eme boucle, ce n'est pas une erreur. Il faut bien utiliser ll_i car je veux récupérer ici la valeur de la ligne de ma DW de départ. ll_j sert juste à parcourir ma datastore locale dans laquelle est contenue les différentes colonnes.
Sauf que ton ll_i sera toujours à... ll_nb_colonne1
Hors ligne




foon a écrit:
Sebou a écrit:
Par contre, dans la 2eme boucle, ce n'est pas une erreur. Il faut bien utiliser ll_i car je veux récupérer ici la valeur de la ligne de ma DW de départ. ll_j sert juste à parcourir ma datastore locale dans laquelle est contenue les différentes colonnes.
Sauf que ton ll_i sera toujours à... ll_nb_colonne1
Bah non, mon ll_i sert d'abord à alimenter la datastore puis je m'en sers pour balayer de p_deb à p_fin
Là je suis en train de modifier, car il y aurait une autre facon de le faire...Ca a l'air bien galere mais bon...
Hors ligne











Je parlais de cette boucle:
FOR ll_j=1 TO ll_nb_colonne2 ll_pos = lds_dw_dest.insertrow(0) ls_nom = p_dw_dest.Describe("#" + string(ll_i) +".Name") ls_type = p_dw_dest.Describe("#" + string(ll_i) +"Coltype") lds_dw_dest.SetItem(ll_pos, 'num', ll_i) lds_dw_dest.SetItem(ll_pos, 'nom', ls_nom) lds_dw_dest.SetItem(ll_pos, 'type', ls_type) NEXT
Hors ligne




Version 2
long ll_nb_colonne1, ll_nb_colonne2, ll_i, ll_j, ll_valeur, ll_pos_insert, ll_pos, ll_fin, ll_colnum string ls_nom, ls_type, ls_coltype1, ls_coltype2, ls_valeur date ldt_valeur time lt_valeur datastore lds_ds, lds_dw_dest lds_ds = CREATE datastore lds_ds.DataObject = "d_util_liste_colonne" lds_ds.SetTransObject(sqlca) lds_dw_dest = CREATE datastore lds_dw_dest.DataObject = "d_util_liste_colonne" lds_dw_dest.SetTransObject(sqlca) // On compte d'abord le nombre de colonnes de chaque dataXXXXX ll_nb_colonne1 = long(p_dw_orig.Describe("DataWindow.Column.Count")) ll_nb_colonne2 = long(p_dw_dest.Describe("DataWindow.Column.Count")) FOR ll_i=1 TO ll_nb_colonne1 ll_pos = lds_ds.insertrow(0) ls_nom = p_dw_orig.Describe("#" + string(ll_i) +".Name") ls_type = p_dw_orig.Describe("#" + string(ll_i) +".Coltype") lds_ds.SetItem(ll_pos, 'num', ll_i) lds_ds.SetItem(ll_pos, 'nom', ls_nom) lds_ds.SetItem(ll_pos, 'type', ls_type) NEXT FOR ll_j=1 TO ll_nb_colonne2 ll_pos = lds_dw_dest.insertrow(0) ls_nom = p_dw_dest.Describe("#" + string(ll_j) +".Name") ls_type = p_dw_dest.Describe("#" + string(ll_j) +".Coltype") lds_dw_dest.SetItem(ll_pos, 'num', ll_j) lds_dw_dest.SetItem(ll_pos, 'nom', ls_nom) lds_dw_dest.SetItem(ll_pos, 'type', ls_type) NEXT ll_fin = lds_ds.RowCount() FOR ll_i = p_deb TO p_fin ll_pos_insert = p_dw_dest.insertrow(p_lig_insert) FOR ll_j=1 TO ll_fin ls_nom = lds_ds.GetItemString(ll_j, "nom") ls_type = lds_ds.GetItemString(ll_j, "type") ll_pos = lds_dw_dest.find("nom = '" + ls_nom + "' AND type = '" + ls_type + "'", 1, lds_dw_dest.RowCount()) // Si elle existe, alors on copie dans DW_dest IF ll_pos > 0 THEN ll_colnum = lds_dw_dest.GetItemNumber(ll_pos, 'num') IF p_buffer = Primary! THEN p_dw_dest.Object.Data[ll_pos_insert, ll_colnum] = p_dw_orig.Object.Data.Primary[ll_i, ll_j] ELSE IF p_buffer = Delete! THEN p_dw_dest.Object.Data[ll_pos_insert, ll_colnum] = p_dw_orig.Object.Data.Delete[ll_i, ll_j] ELSE p_dw_dest.Object.Data[ll_pos_insert, ll_colnum] = p_dw_orig.Object.Data.Filter[ll_i, ll_j] END IF END IF END IF NEXT NEXT
Dernière modification par Sebou (09-01-2008 09:53:55)
Hors ligne




Oops en effet, désolé merci beaucoup
Hors ligne
Comme j’ai conçu une fonction similaire (à la différence que je m’affranchi du problème de correspondance des noms des colonnes en utilisant un computed field qui donne le nom de la colonne a affecter) je peux ajouter que :
upper(left(ls_type, 4)) = "DATE"
présente une ambiguitée entre le type « Date » et « Datetime » qu’il convient de traiter.
et je pense
p_dw_orig.GetItemNumber(ll_i, 'ls_nom', p_buffer, FALSE...
ne passe pas pour le type décimal, il faut utiliser getitemdecimal()
Dernière modification par Dadone (08-01-2008 16:32:01)
Hors ligne




Ah ui merci Dadone pour ta précision...j'suis débutant en PB donc j'commets encore des erreurs grosses comme un éléphant lol
Bon sinon, ma 2eme version est bonne cette fois. Le boss est content :D
(il a meme pas vu les erreurs que vous m'avez indiqué lol)
Hors ligne
[HS]
Coder une telle fonction en moins de 2 heures en étant débutant c'est une performance, tu pourra le dire à ton Boss, c'est un formateur qui te le dit
[HS]
Dernière modification par Dadone (08-01-2008 16:41:47)
Hors ligne




Dadone a écrit:
[HS]
Coder une telle fonction en moins de 2 heures en étant débutant c'est une performance, tu pourra le dire à ton Boss, c'est un formateur qui te le dit
[HS]
Merci
Hors ligne




Je me suis permis de repasser le post en NON RESOLU car un nouveau problème s'offre à moi.
J'ai créé un objet non visuel qui rassemble un paquet de fonctions "pratiques" donc mon rowscopy perso. J'ai décliné ce RowsCopy en 2 versions : une pour copier d'une DW vers une DW (celle présentée plus haut) et une pour copier d'une DS vers une DW. Le seul paramètre qui change est donc le premier, à savoir DW remplacé par DS.
J'ai voulu donc utilisé cette fonction de mon objet mais je ne peux pas. Je me retrouve avec un joli "bad argument list".
Quelqu'un a une idée ?? Serait ce une confusion sur le type ? Pourtant j'ai déja créé 2 fonctions avec le meme nom ayant juste des parametres différents et ca marchait nikel chrome
Hors ligne











Bonjour,
Le type de paramètre en entrée est bien "datastore" pour ta deuxième fonction?
Hors ligne