8O nabil je sais, je l'ai bien dis
il y a mieux à faire et aidons notre copain, non!!?:ccool:
Version imprimable
salut,
Pour afficher le résultat de la procédure de Serge et de Ph. B. dans la requête sans passer par une ListBox, faut-il ajouter un champ à la Query (à la conception) ou dans la table et ensuite faire un Select de ce champ qui servira à regrouper ces intervalles des Id_clients ?
Rapellons-nous que l'objectif est :
Localité: les "Id" qui vont avec
@+
NAbil
bon , j'avais du temps libre :lol:
:alerte: essayes quand même de comprendre le code , avant de faire un copier coller bête
@philippe : si tu veux chercher la petite bête , je suis sur que tout n'est pas encore optimum :whistle2:
ici , le résultat sera mis dans un mémo (resultmemo) , une ligne par localité
Code:
1
2 SELECT LOCALITE,NUMERO FROM CLIENTS ORDER BY LOCALITE,NUMERO
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 procedure TForm1.TestBtnClick(Sender: TObject); var wloc : String; // localité en cours wNum: Integer; // numero en cours sNum : Integer; // debut de la suite LigneMemo : String; // resultat pour une localité // mise en forme de la ligne procedure ModifierLigne; var t : integer; // utilisée pour le cas du EOF begin t:=Query1NUMERO.asInteger-Wnum; if Query1.EOF then t:=-1; // force t a -1 case t of 0 : begin if Length(Lignememo)= Length(Wloc) then LigneMemo:=Lignememo+' '+Inttostr(WNum) else LigneMemo:=Lignememo+','+Inttostr(WNum) ; snum:=wnum; end; 1 : Wnum:=Query1NUMERO.asInteger; -1 : if snum<>wnum then lignememo:=Lignememo+'...'+Inttostr(wnum); else begin if snum=wnum then Lignememo:=Lignememo+', ' else Lignememo:=Lignememo+'...'+inttostr(wnum)+', '; wNum:=Query1NUMERO.asInteger; sNum:=Query1NUMERO.asInteger; Lignememo:=Lignememo+Inttostr(WNum); end; end; end; begin Resultmemo.Clear; Query1.Active:=True; wNum:=0; wLoc:=''; while not Query1.Eof do begin if Wloc<>Query1LOCALITE.AsString then begin if WNum>0 then ResultMemo.Lines.Add(LigneMemo); wloc:=Query1LOCALITE.AsString; sNum:=Query1NUMERO.asInteger; wNum:=Query1NUMERO.asInteger; LigneMemo:=wloc; end; ModifierLigne; Query1.Next; end; ModifierLigne; ResultMemo.Lines.Add(LigneMemo); Query1.Active:=false; end;
Taquin ! :lol:
Plus sérieusement, je laisse @NABIL74 travailler un peu et reprendre la piste que j'avais donnée au début de la discussion ou exploiter la votre...
A ce titre, j'ai tendance à ignorer les sollicitations d'assistance de ce type faites par messagerie privée. :zoubi:
Bonjour à tous,
Merci pour le temps que tu as consacré à ce souci !
Oui, j'ai toujours pris note de tes conseils.
Mais là Serge t'es une bête :bravo: :bravo: :ccool::ccool:
Le code fonctionne correctement,c'est ça ce que je voulais.
Une question, est-il possible avec cette procédure d'afficher le résultat de la procédure dans la Query sans passer par un TMemo? Car je dois faire un état qui englobe tout et bien sûr par la suite l'imprimé.
Merci encore.
@+
Nabil
c'est clairement non , sauf a passer par une table temporaire du genre
j'aurais certainement dit autrement s'il s'était agit d'une base Firebird (d'ailleurs je l'ai déjà dit ) Cela aurait été un bon exemple d'utilisation de procédure récursives et d'utilisation de lanction LIST je pense . Si j'ai encore du temps a perdre (et que ce n'est pas déjà fait), je pense que j'essaierai !Citation:
Table TEMP
LOCALITE String
MEMO blob
mais il est toujours possible d'imprimer directement le memo , ou de passer par des evenements de calcul pour chaque Localité . Tout dépend du générateur utilisé
Oui, c'est ça que je voulais éviter avant que je pose ma question. Passer par une Table temporaire et puis insérer les enregistrements et par la suite, faire le traitement voulu (ça serait fait par une requête Sélection + un Union, ou un Left Join je pense).
J'ai déjà crée il y a quelques temps une Table temporaire qui contient les champs: Localite (string [200]), IDS_Clients(Memo).
ça c'est une autre paire de manches Serge.
Mon générateur est ReportBuilder.
Dans mon état, il y a deux colonnes : une pour la localité et l'autre pour les Id_clients.
il faut donc copier à partir de chaque ligne:
les mots de chaque localité (ex:Nantes) dans la 1ère colonnes et les ID correspondant dans la 2ème colonne.
A+
Nabil
évidemment celui là je connais pas !
pour ce qui est de mettre le résultat en table temporaire par contre c'est très facile , il suffit de modifier légèrement le code
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 procedure TForm1.TestBtnClick(Sender: TObject); var wloc : String; // localité en cours wNum: Integer; // numero en cours sNum : Integer; // debut de la suite LigneMemo : String; // resultat pour une localité // mise en forme de la ligne procedure ModifierLigne; var t : integer; // utilisée pour le cas du EOF begin t:=Query1NUMERO.asInteger-Wnum; if Query1.EOF then t:=-1; // force t a -1 case t of 0 : begin if Length(Lignememo)=0 then LigneMemo:=Inttostr(WNum) else LigneMemo:=Lignememo+','+Inttostr(WNum) ; snum:=wnum; end; 1 : Wnum:=Query1NUMERO.asInteger; -1 : if snum<>wnum then lignememo:=Lignememo+'...'+Inttostr(wnum); else begin if snum=wnum then Lignememo:=Lignememo+', ' else Lignememo:=Lignememo+'...'+inttostr(wnum)+', '; wNum:=Query1NUMERO.asInteger; sNum:=Query1NUMERO.asInteger; Lignememo:=Lignememo+Inttostr(WNum); end; end; end; procedure insertligne; begin // Query2 = INSERT INTO TABLETEMP(LOCALITE,LIGNE) VALUES (:LO,:LM) Query2.ParamByName('LO').asString:=wloc; Query2.ParamByName('LM').asString:=LigneMemo; Query2.ExecSQL; end; begin Resultmemo.Clear; Query1.Active:=True; wNum:=0; wLoc:=''; while not Query1.Eof do begin if Wloc<>Query1LOCALITE.AsString then begin if WNum>0 then insertligne; wloc:=Query1LOCALITE.AsString; sNum:=Query1NUMERO.asInteger; wNum:=Query1NUMERO.asInteger; LigneMemo:=''; end; ModifierLigne; Query1.Next; end; ModifierLigne; insertligne; Query1.Active:=false; end;
Salut à tous,
@Serge : sans faire de pub, Report Builder est bon générateur d'état.
Oui, c'est facile de mettre le résultat dans table temporaire et de le récupérer ensuite .
Je n'ai pas Delphi là où je suis(au boulot. eh oui,dimanche c'est le début de semaine chez nous! :)), donc je le testerai sûrement ce soir et je te dirai ce que ça donne mon ami.
Mais c'est vrai Serge, "Paradox" c'est de la merde ,pardon pour ce mot :mouarf:
c'est toujours limité en SQL, il y a plein de trucs qu'on peut pas faire sans parler des index qui sont pas à jour quand les tables sont endommagés. .Avant que je pose ma question sur le forum, j'ai déjà fait une recherche sur le net et j'ai bien sûr trouvé ton poste qui se rapport à la ma question mais sous Firdbird.
enfin bon, merci encore.
Nabil
Bonjour à tous,
@ Serge:
ça marche bien sauf un petit détail dans:
A+Code:
1
2
3
4
5
6
7
8
9
10 begin // Query2 = INSERT INTO TABLETEMP(LOCALITE,LIGNE) VALUES (:LO,:LM) Query2.ParamByName('LO').asString:=wloc; // "wloc" donne bien les Localités mais "LigneMemo" donne "Localité + numéros" alors qu'on a seulement besoin des numéros. :mur: Query2.ParamByName('LM').asString:=LigneMemo; Query2.ExecSQL;
pour table temporaire je préfère Clientdataset, ou le composant proposé par Franck :ccool:, mais aussi on peut imprimer directement dans report buider en utilisant les événements des champs
:ccool:
C'est ok même pour l'insertion .Code:
1
2
3
4
5
6 case t of 0 : begin if Length(Lignememo)= Length(Wloc) then LigneMemo:= Inttostr(WNum) ; // j'ai effacé : Lignememo+' ' // else LigneMemo:= Inttostr(WNum) ; snum:=wnum;
Tu sais Serge, si je n'applique pas un tri des données, la procédure 'collecte' tous les ID_clients avec les localités qui lui correspondent:
Mais quand ce tri est activer, elle loupe quelques IDCode:
1
2
3
4
5 Query1.Active := False; Query1.SQL.Clear; Query1.SQL.Add(SELECT LOCALITE,NUMERO FROM CLIENTS '); Query1.SQL.Add(' ORDER BY LOCALITE,NUMERO'); Query1.Active:=True;
Le DBEdit2 est la Localite.Code:
1
2
3
4
5 Query1.Active := False; Query1.SQL.Clear; Query1.SQL.Add(SELECT LOCALITE,NUMERO FROM CLIENTS WHERE Localite='''+DBEdit2.Text+''' '); Query1.SQL.Add(' ORDER BY LOCALITE,NUMERO'); Query1.Active:=True;
Elle affiche seulement le début d'une série et pas sa fin
Ex: Paris : 1,29-50,120-129,990-1020
Le '1020' le loupe, elle m'affiche seulement '990'.
c'est vraiment incompréhensible non :mur: !
A+
Nabil
holalala ...
pourquoi n'y a t'il pas une table Client et une table Localité ?
Table Clients :
Code:id_client, id_city, ...
Table cities :
Code:id_city, name, ...
1 : on bouffe moins de ressources pour stocker les id_client dans un champs non prévus pour ... au risque de se retrouver avec un champs de 42Peta-octet... :/
2 : on simplifie les requêtes, le tris etc.
Code:
1
2
3
4 SELECT cl.id_client, cl.name, ci.id_city, ci.name FROM clients AS cl, cities AS ci WHERE cl.id_city=ci.id_city AND (autre condition) ORDER BY ci.id_city, cl.id_client ASC
et des group by et des count et des sum etc etc.
ça était comme ça au début.En réalité, J'ai la Table Clients avec les champs: id_client , Nom et prénom, Localité, téléphone,...
Tu n'as pas bien compris mon souci, je veux détecter les trous des ID dans une série entière suivant chaque localité:Nantes : ID: 1,2,3,7 ,8,9,10,11, 25
Je veux faire: 1-3, 7-11,25
A+
Si si j'avais compris, ce que je comprend pas c'est la finalité de trouver ces fameux trous ...
pour moi ça raisonne comme un "se prendre la tête pour un truc inutile parce que mal foutus à la base".
Tu t'embêterai moins a restructurer correctement que de chercher a faire "des trucs" qui te fond tourner en rond pour rien et au risque qu'a la fin d'une longue prise de tête infructueuse avec son lot de solutions improductives tu décide de refaire une structure correcte.
Avec une telle structure, admettons que tu cherche ou est localisé le client 5 (à paris par exemple), et dans paris tu as '2-9,12-32'
Tu fais quoi comme requête ?
à part un truc imbuvable à base fonctions à la noix et de like bancale ?
Et je parle même pas de la mise à jours de ce champs ... le mec qui en est à l'origine mériterais de bruler sur la stèle des sacrifices d'Oracle tiens...
Après, oui, le coté défis est intéressant, pour ma part je ferai un traitement externe à base de delphi.
Mais, ta base actuelle c'est le genre de truc que personne ne voudrais voir en Production.
Bonjour à tous,
@Dr.Who : je t'ai déjà dis que tu n'as pas bien pigé ce que je veux exactement, le but est dans un état de sortie (l'impression).
je ne perd pas la tête pour un truc inutile.Voilà, admettant que dans une localité, j'ai 200 clients et qu'on veut imprimer chaque localité avec les ID_Clients.Tu remarquerais que ces Id vont prendre beaucoup d'espace :de 1 jusqu'à 200!
Alors pourquoi pas les grouper comme :1-200 non?
Pour la recherche d'un client, on a pas besoin de cette procédure.Dans La Table Clients chaque enregistrement affiche un id_Client et sa localité, Un TEdit pour la recherche fera l'affaire.on tape '5' et on se pointe sur ce client.
+A
Nabil
non, cela veut simplement dire que le EOF est mal géré .Citation:
Elle affiche seulement le début d'une série et pas sa fin
Ex: Paris : 1,29-50,120-129,990-1020
Le '1020' le loupe, elle m'affiche seulement '990'.
c'est vraiment incompréhensible non !
c'est encore plus vrai de dire que tes modifications sont responsables de l'erreur. Pour preuve , le dernier code mettant le tout dans un memo donnait le résultat correct.
1- je remarque que tu n'as pas fait la bonne correction
2-
le SQL avec un Where sur la Localité est une honte dans sa forme mais surtout dans le fond
Code:
1
2
3
4
5
6
7 Query1.Active := False; Query1.SQL.Clear; Query1.SQL.Add('SELECT LOCALITE,NUMERO FROM CLIENTS WHERE Localite=:L'); Query1.SQL.Add(' ORDER BY LOCALITE,NUMERO'); Query1.ParambyName('L').asString:=DBEdit2.Text; Query1.Active:=True;
pour le fond : s'il n'y a qu'une seule localité , alors il n'y a pas lieu d'utiliser le test sur le changement de localisation.
3- en général quand on fait une édition ce n'est pas pour n'avoir qu'une seule ligne (donc dans notre cas une seule localité)
je suis d'accord avec Dr Who sur la structure des tables bien que cela ne change rien à l'exercice. Ce genre d'exo était très en vogue en 1983 dans les écoles d'apprentissage a la programmation :roll:, a tel point que je voix encore le schéma de programmation (d'une méthode oubliée) dans ma tête . J'ai déjà également dit que Paradox n'etait certainement pas le meilleur choix bien que ce fut un très bon outil (au siècle dernier) quand les SGBD n'existaient pas encore.
Serge: merci pour tes bonnes remarques.
Oui c'est sûr que le EOF est mal géré car si on ajoute un ID_Client dont la Localité est la même pour la suite de série, il y est!
ex: Paris :1,29-50,120-129,990-1020=> 1,29-50,120-129,990
résultat ok après insertion:
1,29-50,120-129,990[COLOR="rgb(46, 139, 87)"]-1020[/COLOR] , 2025
je n'ai pas fait la bonne correction :oops: :oops:
J'ai essayé hier avec une requête paramétrée ,elle donne le même résultat que
pourOui, je suis tout à fait d'accord avec vous sur le choix de la BD Paradox, d'ailleurs je l'ai déjà dit.Code:WHERE Localite='''+DBEdit2.Text+'''
Au début de ce topic, j'ai dit que je veux améliorer une vieille application faite avec Paradox comme BD.
Oui dans la mesure où on cherche à filtrer la query une une seul localité,
mais dans le cas contraire ,on fait le Select déjà cité:A+Code:
1
2
3
4
5
6 Query1.Active := False; Query1.SQL.Clear; Query1.SQL.Add('SELECT LOCALITE,NUMERO FROM CLIENTS WHERE Localite=:L'); Query1.SQL.Add(' ORDER BY LOCALITE,NUMERO'); Query1.ParambyName('L').asString:=DBEdit2.Text; Query1.Active:=True;