salut à tous,
je tourne en rond depuis quelque temps sur une requête.
Voilà, j'ai une Table 'Localite' dont les champs sont:
-Id_Client.
-Localité.
Chaque Localité peux avoir un ou plusieurs 'Id_Clients'. Des fois Ces 'id' peuvent se suivre ,mais des fois non.
Par exemple :
Dans la même localité Paris, il y a les ID :de 1,2,3,4,5,6,....jusqu'à 200.
Si dans un Etat (comme Report Builder ou autre), la colonne réservée pour les "Id" va prendre beaucoup d'espace non?
-Localité : Paris => Id_Client: de '1' jusqu'à '200' , '65' ,90, de '300' jusqu'à '360'.
je veux le faire comme ça:ID: 1-200 , 65 , 90 , 300-360.
avant de faire la requête, il faut organiser les données.
il y en fait ici deux tables :
- les villes ou communes
- les clients
il faut mettre une relation de 1 à plusieurs entre elles :
table ville
codeville
ville
table client
codeclient
code ville
client
permettant de faire défiler à l'écran les clients par ville choisie.
pour l'édition des clients sur une ville sélectionnée, on peut faire un état sur une requête SQL :
procedure TForm1.DisplayCustomer;
begin
with Query1.SQL do
begin
Clear;
Add('SELECT * FROM client ');
Add('WHERE (codeville =:param ) ');
Query1.ParamByName('param').value := CodeVille;
Query1.Open;
end;
end;
le CodeVille peut-être récupéré par exemple dans une liste déroulante
créée avec deux champs (codeville, ville) etc..
le souci de l'affichage des noms sur une même page est un autre problème
qui peut se résoudre en faisant une impression avec saut de colonne.
@ MAURICIO,
Avant de faire ce poste,j'ai ordonné la table sur id_clients :
Select Localite, ID_Client
From Localite
where ID_Client=:ID_Client
Group by ID_Client
, mais je ne suis pas arrivé à faire le code qui me permet de détecter le début et la fin de série!
@ cantador,
La Table "Localite" contient seulement 2 champs: "ID_Client" et "Localite".
Comment le souci de l'affichage des noms sur une même page est un autre problème
qui peut se résoudre en faisant une impression avec saut de colonne.
J'ignore comment le faire mon ami cantador. , c'est un peu dûr pour moi.
J'ai cette requête à proposer (attention à la consommation... et elle est peut être optimisable...)
J'ai testé sur une table Localite(id) avec les valeurs suivantes pour id : 2 à 5, 9, 12 à 16, 20, 21, 24, 29 à 31, 35. Le résultat présente deux champs DEBUT et FIN avec les valeurs suivantes :
DEBUT | FIN
2 | 5
9 | null
12 | 16
20 | 21
24 | null
29 | 31
35 | null
Select (e1.id) as DEBUT,
(Select min (f1.id)
from Localite f1
Left Outer Join Localite f2 On (f1.id = f2.id - 1)
Left Outer Join Localite f3 On (f1.id -1 = f3.id)
Where (f2.id is null) and (f3.id is not null)
and (e1.ID < f1.Id)
) as FIN
From Localite e1
Left Outer Join Localite e2 On e1.id - 1 = e2.id
Left Outer Join Localite e3 On (e1.id = e3.id - 1)
Where (e2.id is null) and (e3.id is not null)
Union
Select g1.id as DEBUT, g3.id as FIN
from Localite g1
Left Outer Join Localite g2 On (g1.id = g2.id - 1)
Left Outer join Localite g3 on (g1.id - 1 = g3.id)
Where (g2.id is null) and (g3.id is null)
Bonsoir,
je m'y mets aussi. 2 tables, localités et clients
avec pour chaque un datasource et dbgrid dessus
local (
locCode integer, au choix
locNom char(50),
... )
table client (
cliCode integer, au choix
cliNom varchar(50),
cliLoc integer, meme type que locCode,
... )
Evidemment le code localité est dans la table client (pas l'inverse)
car 1 localité/client
Tu veux lier les client sur leur localité. Tu veux clicker sur une localité et avoir en dessous tous ces clients.
Rien dans le code (pas besoin ici), tout en mode conception
LocalQry:
.sql : select * from localité order by cequetuveux
.active : true
ClientQry
.datasource : LocalSource -- pour lier les 2 tables
.sql : select * from client
where cliLoc = :LocCode -- le nom du champ dans la table local
order by cequetuveux
.active = true;
En liant ClientQry.datasource avec celui de local, il mettra à jour le param
tout seul et refreshra clienQry.
et simplement dans ton formcreate ou formshow
if not LocalQry.active then LocalQry.open; // le père d'abord
if not ClientQry.active then ClientQry.open; //
Chaque click sur le dbgrid de localité tu auras les clients de celle-ci.
Effectivement, je m'aperçois que ma requête manque de commentaires... Désolé, je t'explique ça.
Je l'avais testée sur Firebird, je viens de vérifier, elle fonctionne aussi sur Paradox.
Concernant le ID : C'est le nom du champ que j'ai défini pour ton ID_Client. Tu renommes tous les "ID" en "ID_Client".
Les "e1", "f1", etc... sont des alias de tables. Ça permet d'indiquer à paradox à quelle table correspond les champs que tu sélectionnes.
Les infos entre "/*" et "*/" sont des commentaires en SQL. Tu peux les laisser dans ton programmes, ils ne devraient pas interférer.
/* Requête de sélection des suites de n° ID en ne conservant que le premier et le dernier (DEBUT et FIN) de la série
On va prendre tous les ID, que l'on renomme en début (opérateur "as")
*/
Select (e1.id) as DEBUT,
/* Puis, pour chaque DEBUT, on recherche la plus petite valeur (opérateur "Min"), supérieure à la valeur DEBUT (e1.ID), pour laquelle il existe un numéro avant mais pas après (recherche de la borne supérieure de la série)
*/
(Select min (f1.id)
from Localite f1
/* Autojointure sur le n° suivant */
Left Outer Join Localite f2 On (f1.id = f2.id - 1)
/* Autojointure sur le n° précédent */
Left Outer Join Localite f3 On (f1.id -1 = f3.id)
/* Le suivant ne doit pas exister, pour tomber sur la fin de la série */
Where (f2.id is null)
/* Le précédent doit exister, pour s'assurer d'être dans une série */
and (f3.id is not null)
/* On recherche la borne supérieure de la série, donc après la valeur de "DEBUT" */
and (e1.ID < f1.Id)
) as FIN
From Localite e1
Left Outer Join Localite e2 On e1.id - 1 = e2.id
Left Outer Join Localite e3 On (e1.id = e3.id - 1)
Where (e2.id is null) and (e3.id is not null)
Union
/* Ici on va chercher les "id" isolés, c'est à dire ceux qui n'ont pas de précédent ni de suivant
et on les rajoute à la première requête grâce à "union"
*/
Select g1.id as DEBUT, g3.id as FIN
from Localite g1
/* Autojointure sur la même table sur le suivant*/
Left Outer Join Localite g2 On (g1.id = g2.id - 1)
/* Autojointure sur la même table sur le précédent */
Left Outer join Localite g3 on (g1.id - 1 = g3.id)
/* Le précédent et le suivant doivent être nuls, pour qu'on récupère les n° isolés
Where (g2.id is null) and (g3.id is null)
Voilà, c'est un peu chaud à comprendre surtout si tu débutes, mais ça doit fonctionner.
Suis quand même les conseils des autres pour la conception de ta base. Une bonne structure de base de donnée, sans redondance, est essentielle pour faire un bon programme facile à maintenir...
Erratum !
Sur le premier sélect, on ne prend pas tous les ID... (e1.ID)
On ne sélectionne que les ID qui n'ont pas de précédent, mais qui ont un suivant. C'est à dire les têtes de série (ce sont les deux dernières jointures que j'ai oublié de commenter...)
@ solilog:
merci, mais tu parles d'une relation maître détail qui n'est pas le cas dans ce problème.
@ Simon : merci encore pour ta générosité !
Ok ça marche si j'efface: "-1" dans le :
Left Outer Join Objets f3 On (f1.Num_Objet -1 = f3.Num_Objet)
et aussi dans
Union
Select g1.Num_Objet as DEBUT, g3.Num_Objet as FIN
from Objets g1
Left Outer Join Objets g2 On (g1.Num_Objet = g2.Num_Objet - 1)
Left Outer join Objets g3 on (g1.Num_Objet - 1 = g3.Num_Objet)
Where (g2.Num_Objet is null) and (g3.Num_Objet is null)
Si je les efface, ça consomme les resources , j'obtiens le Min(ID_client) et le Max(ID_client) c'est tout.
je ne sais pas si le souci est le "-1" ou non.
Simon, ça marche mais il y a un souci c'est que la requête n'affiche pas les 'Id' qui ne se suivent pas.
ex: 1,2,3,...200 => il m'affiche : 1-200 ça c'est Ok.
Mais s'il s'agit d'un seul chiffre, elle ne m'affiche pas!
ex : 300.la requête l'ignore complètement.
Une question Simon, Comment faire cette requête pour qu'elle me donne la localité avec le 'Id' concernés?
Merci encore
Bizarre ton message d'erreur, j'ai testé ma requête directement sous paradox, elle a bien fonctionné...
Si tu enlèves le "-1", la signification de la requête change (normal...) et du coup, elle ne fera pas ce que tu attends.
- Quelle est la version de delphi que tu utilises ?
- Quels sont les composants de base de données que tu utilises ?
J'aimerais que tu arrives à la faire fonctionner déjà comme ça avant de s'intéresser à l'affichage de la localité...
Est-ce que tu peux me donner la structure exacte de ta base de donnée localité (nom de champs, type de champs), et publier ici le code qui déclenche la violation d'accès ?
//********
Select (e1.ID_Client) as DEBUT,
(Select min (f1.ID_Client)
from Localite f1
Left Outer Join Localite f2 On (f1.ID_Client = f2.ID_Client - 1)
Left Outer Join Localite f3 On (f1.ID_Client -1 = f3.ID_Client)
Where (f2.ID_Client is null) and (f3.ID_Client is not null)
and (e1.ID_Client < f1.ID_Client)
) as FIN
From Localite e1
Left Outer Join Localite e2 On e1.ID_Client - 1 = e2.ID_Client
Left Outer Join Localite e3 On (e1.ID_Client = e3.ID_Client - 1)
Where (e2.ID_Client is null) and (e3.ID_Client is not null)
Union
Select g1.ID_Client as DEBUT, g3.ID_Client as FIN
from Localite g1
Left Outer Join Localite g2 On (g1.ID_Client = g2.ID_Client - 1)
Left Outer join Localite g3 on (g1.ID_Client - 1 = g3.ID_Client)
Where (g2.ID_Client is null) and (g3.ID_Client is null)
//*******
Merci Nabil... Je me doute bien que c'est ma requête qui plante. Ce que je voudrais c'est ton fichier source, ou au moins des infos sur le code. Est-ce que tu mets la requête directement dans le tquery via l'inspecteur d'objet, ou est-ce que tu le fais par le code ?
Oui je mets la requête directement dans le Tquery via l'inspecteur d'objet.Peut-être c'est pour ça que ça plante?!
Sur une fiche,j'ai mis un TQuery , une DataSource et une DBGrid lié à elle.
Le code que tu m'as filé,je l'ai mis directement dans le Query.
J'espère que j'ai répondu à ta question.
merci