Probleme avec requête

Signaler
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014
-
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
-
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.

comment le faire svp?
Merci


NABIL1974

26 réponses

Messages postés
2106
Date d'inscription
mardi 10 décembre 2002
Statut
Modérateur
Dernière intervention
15 décembre 2014
5
Tu peux ordonner la table sur id_clients puis tu fais un code qui te permet de détecter un début et fin de série!

a+


Composants Cindy pour Delphi
Faites une donation.
Messages postés
4719
Date d'inscription
dimanche 26 février 2006
Statut
Modérateur
Dernière intervention
1 février 2021
14
Bonjour,

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.

cantador
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

Merci pour votre réponses les gars!

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

merci.
A+





NABIL1974
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
Salut,

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)


Simon
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
Désolé pour la mise en page... je n'ai pas trouvé les balises de code SQL...


Simon
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
Tiens c'est marrant, est-ce qu'un "union" applique implicitement un "order by" ? Parce que le résultat est trié...

Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

salut,
Merci Simon.

Je viens de testé ton code Sql, j'ai un message d'erreur :"Nom de champ incorrect : ID". c'est dans le 1er Select.

Mon SGBD c'est Paradox. j'ignore si ça marche avec les requête Paradox!

Petite question: je n'ai pas compris les :e1 ,f1,f2,f3,...

Merci



NABIL1974
Messages postés
273
Date d'inscription
samedi 13 juin 2009
Statut
Membre
Dernière intervention
18 avril 2015
10
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.

Salut.
solilog
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
@Nabil :

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

Simon
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
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...)

Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

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



NABIL1974
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
Et qu'est ce que ça te dit si tu n'enlèves pas le '-1' ?

Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

si je n'enlève pas le '-1' , il m'affiche un msg d'erreur 'violation d'accès à l'adresse 4C60737E dans le module idsql32.dll...'

NABIL1974
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

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

NABIL1974
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
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é...

Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

j'utilise delphi 7 entr.
les composants de base de données sont les TTable et Tquery fournis avec delphi.


NABIL1974
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
Test sur d7 ent, tquery : ok pour moi...

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 ?


Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

Localite:
Champs:
1- Localite : String(200)
2- ID_Client : integer.

Voici le code qui déclenche l'erreur:

//********
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)
//*******

NABIL1974
Messages postés
1284
Date d'inscription
mardi 28 octobre 2003
Statut
Contributeur
Dernière intervention
3 juillet 2015
13
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 ?

Simon
Messages postés
76
Date d'inscription
mardi 18 décembre 2007
Statut
Membre
Dernière intervention
11 mars 2014

Bonjour Simon,

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




NABIL1974