Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1845 connectés 

  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Help pour une requete

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Help pour une requete

n°2039589
lopotkine
Posté le 02-12-2010 à 11:14:05  profilanswer
 

Bonjour,  
 
je ne connais sans doute pas assez le langage sql pour savoir si ma requete est réalisable ou non  
J'essaie d'expliquer le pb: j'ai une table client (avec un id), et une table facture (avec un id, un client_id, et un magasin appartenant à un ensemble de 3 valeurs possibles: A, B, C). Je peux extraire toutes les factures d'un magasin donné (disons 'A') via:
 
select * from client join facture on (client.id=facture.client_id) where facture.magasin='A';
 
un client donné peut ne pas avoir de factures,
ou des factures d'un seul magasin
ou des factures de deux magasins
ou des factures des trois magasins.
 
Ce que je souhaite obtenir EN UNE SEULE REQUETE:  
requete 1: la liste de tous les clients (SANS DOUBLONS) qui ont des factures dans n'importe quel magasin
requete 2:                                                               qui ont des factures au magasin 'A' mais pas au 'B' ni 'C'
requete 3:                                                               qui ont des factures non effectuées au magasin 'A'
 
Le but étant (entre autre) de compter le nombre de clients en fonction des magasins.
 
Est-ce-possible et si oui comment?
 
Merci d'avance de votre aide.

mood
Publicité
Posté le 02-12-2010 à 11:14:05  profilanswer
 

n°2039613
gelatine_v​elue
Posté le 02-12-2010 à 12:15:10  profilanswer
 

Au pif:
requete 1:
 
Select distinct c.id from clients c, facture f where c.id=f.client_id
 
requete 2:
 
Select distinct c.id from clients c, facture f where c.id=f.client_id and f.magasin='A'
 
requete 3:
Select distinct c.id from clients c, facture f where c.id=f.client_id and f.magasin<>'A'

n°2039651
lopotkine
Posté le 02-12-2010 à 14:13:38  profilanswer
 

Heu, merci, je devais être mal réveillé ce matin...
Je vais vérifier que cela répond bien à mon pb, et vérifier surtout que mon pb est bien celui que j'ai exposé... :)

n°2039661
lopotkine
Posté le 02-12-2010 à 14:56:30  profilanswer
 

Je crois avoir retrouvé la requete qui me posait le pb: comment obtenir les clients qui ont des factures au magasin 'A' ET au magasin 'B'?
Si j'indique magasin='A' OR magasin='B' c'est faux, et si je remplace le OR par un AND, c'est également faux...
Merci encore.

n°2039665
gelatine_v​elue
Posté le 02-12-2010 à 15:09:35  profilanswer
 

Fais une union entre ceux qui ont des factures au magasin A et ceux qui en ont au magasin B

n°2039680
lopotkine
Posté le 02-12-2010 à 15:49:32  profilanswer
 

Je vois bien l'idée, mais pas la syntaxe, peux-tu m'indiquer comment cela s'écrit stp?
Merci.

n°2039688
skeye
Posté le 02-12-2010 à 16:28:51  profilanswer
 

lopotkine a écrit :

Je crois avoir retrouvé la requete qui me posait le pb: comment obtenir les clients qui ont des factures au magasin 'A' ET au magasin 'B'?
Si j'indique magasin='A' OR magasin='B' c'est faux, et si je remplace le OR par un AND, c'est également faux...
Merci encore.

 

Pas besoin d'union.

 
Code :
  1. SELECT DISTINCT c.*
  2. FROM clients c
  3.          JOIN facture f ON c.id = f.client_id AND  f.magasin_id IN ('A', 'B')
 

[edit]

 

Non, j'avais mal compris.
Et c'est pas une union, c'est une intersection, que tu veux.


Message édité par skeye le 02-12-2010 à 16:30:17

---------------
Can't buy what I want because it's free -
n°2039690
skeye
Posté le 02-12-2010 à 16:31:27  profilanswer
 

Code :
  1. SELECT DISTINCT c.*
  2. FROM clients c
  3.        JOIN facture f ON c.id = f.client_id
  4.        JOIN facture f2 ON c.id = f2.client_id
  5. WHERE f.magasin_id = 'A'
  6. AND f2.magasin_id = 'B'


---------------
Can't buy what I want because it's free -
n°2039905
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 16:39:26  profilanswer
 

Si on se fout de ramener les infos des factures mais juste les informations clients, c'est plus propre et peut-être même plus rapide (si correctement indexé) comme ça IMHO :

Citation :


Select c.*
from client c
where exists (select 1
                  from facture f
                  where f.client_id = c.client_id
                  and f.magasin_id = 'A')
and    exists (select 1
                  from facture f2
                  where f2.client_id = c.client_id
                  and F2.magasin_id = 'B')

Message cité 1 fois
Message édité par E-Nyar le 03-12-2010 à 16:40:21

---------------
Don't fuck me, I'm anonymous.
n°2039907
skeye
Posté le 03-12-2010 à 16:41:56  profilanswer
 

E-Nyar a écrit :

Si on se fout de ramener les infos des factures mais juste les informations clients, c'est plus propre et peut-être même plus rapide (si correctement indexé) comme ça IMHO :

Citation :


Select c.*
from client c
where exists (select 1
                  from facture f
                  where f.client_id = c.client_id
                  and f.magasin_id = 'A')
and    exists (select 1
                  from facture f2
                  where f2.client_id = c.client_id
                  and F2.magasin_id = 'B')


 

Plus rapide? 2 sous-requêtes par rapport à deux jointures? [:ula]

 

Et je vois pas non plus pourquoi ce serait plus propre...

Message cité 1 fois
Message édité par skeye le 03-12-2010 à 16:42:47

---------------
Can't buy what I want because it's free -
mood
Publicité
Posté le 03-12-2010 à 16:41:56  profilanswer
 

n°2039914
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 16:53:01  profilanswer
 

skeye a écrit :

 

Plus rapide? 2 sous-requêtes par rapport à deux jointures? [:ula]

 

Et je vois pas non plus pourquoi ce serait plus propre...

 

1 seul passage sur la table client (pas de distinct), pas de multiplication inutile via les jointures, les sous-requêtes seront montées en mémoire avec des bind-variables, si la table facture est bien indexée, 1 seul lecture / client.
Faudrait voir le plan d'exécution, mais d'instinct, je dirais plus rapide... le where doit bien plomber (vu que tu vas aller chercher toutes les combinaison f et f2 et ensuite appliquer ton prédicat sur la combinaison f = A ET f = B)

 

et pour ce qui est du plus propre, c'est juste que ça répond à la question posée, ni plus ni moins.

Message cité 1 fois
Message édité par E-Nyar le 03-12-2010 à 16:55:20

---------------
Don't fuck me, I'm anonymous.
n°2039916
Oliiii
Posté le 03-12-2010 à 16:55:03  profilanswer
 

Le query engine va probablement generer le meme plan pour les 2 query mais les 2 jointures ont l'air bien plus propre et facile a comprendre en 1 coup d'oeuil.
 
Le probleme des "exists" c'est qu'on a trop vite fait de transformer en "not exists" et la c'est la misere totale.

n°2039920
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 17:09:32  profilanswer
 

en testant rapidement avec ce que j'avais sous le coude (departement / commune) :
 
Select c.*
from departement c
where exists (select 1  
                  from commune f
                  where f.iddepartement = c.iddepartement
                  and f.numinsee = '28353')
and    exists (select 1  
                  from commune f2
                  where f2.iddepartement = c.iddepartement
                  and f2.numinsee = '28354');
 
http://hfr-rehost.net/thumb/self/pic/b7a44f91d11e2b23e4aaaa6abbe89afb8f6acdf0.png
 
Cout : 4
 
 
SELECT DISTINCT c.*
FROM departement c
        JOIN commune f ON f.iddepartement = c.iddepartement
        JOIN commune f2 ON f2.iddepartement = c.iddepartement
WHERE f.numinsee = '28353'
AND f2.numinsee = '28354';
 
http://hfr-rehost.net/thumb/self/pic/78e3007d95da464054d37cf622c9edc2b8db0fa7.png
 
Cout : 5
 
C'est le distinct qui plombe la 2ieme.


Message édité par E-Nyar le 03-12-2010 à 17:10:50

---------------
Don't fuck me, I'm anonymous.
n°2039921
skeye
Posté le 03-12-2010 à 17:09:56  profilanswer
 

E-Nyar a écrit :


et pour ce qui est du plus propre, c'est juste que ça répond à la question posée, ni plus ni moins.


 
Euh, et ma version elle répond à quelle question, celle du voisin?[:pingouino]
Je veux les clients

Code :
  1. SELECT c.*
  2. FROM client c


 
qui ont des factures dans le magasin A
 

Code :
  1. JOIN facture f
  2. WHERE f.magasin ='A'


 
et des factures dans le magasin B
 

Code :
  1. JOIN facture f2
  2. WHERE f2.magasin = 'B'


 
 
[:w3c compliant]
 
 
Pour le plan d'exécution je zappe, flemme de tester. Mais au mieux je dirais que ça va donner le même résultat.
 


---------------
Can't buy what I want because it's free -
n°2039924
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 17:17:33  profilanswer
 

skeye a écrit :


 
Euh, et ma version elle répond à quelle question, celle du voisin?[:pingouino]
Je veux les clients

Code :
  1. SELECT c.*
  2. FROM client c


 
qui ont des factures dans le magasin A
 

Code :
  1. JOIN facture f
  2. WHERE f.magasin ='A'


 
et des factures dans le magasin B
 

Code :
  1. JOIN facture f2
  2. WHERE f2.magasin = 'B'


 
 
[:w3c compliant]
 
 
Pour le plan d'exécution je zappe, flemme de tester. Mais au mieux je dirais que ça va donner le même résultat.
 


 
Ça dépend comment on veut répondre à la question, là tu vas chercher les clients et toutes leurs factures dans le magasins A et toutes leurs factures dans le magasins B et tu ne prends que ceux qui ont des factures dans les 2. D'ailleurs petite question pourquoi ne pas remonter le filtre sur magasin A et magasin B directement dans la jointure ? (bon ça change rien au plan d'exécution vu que l'optimiser va les remonter lui-même, mais je trouve ça plus compréhensible si par hasard tu te retrouves avec 4 ou 5 filtres sur les clients par la suite pour pas mélanger les choux et les carottes).
 
 
C'est différent de répondre par "Je vais chercher tous les clients pour lesquels il existe au moins 1 facture dans A et 1 facture dans B


---------------
Don't fuck me, I'm anonymous.
n°2039925
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 17:18:37  profilanswer
 

Oliiii a écrit :

Le query engine va probablement generer le meme plan pour les 2 query mais les 2 jointures ont l'air bien plus propre et facile a comprendre en 1 coup d'oeuil.
 
Le probleme des "exists" c'est qu'on a trop vite fait de transformer en "not exists" et la c'est la misere totale.


 
Le not exists a traduire en jointure c'est pas mal non plus ;)


---------------
Don't fuck me, I'm anonymous.
n°2039928
skeye
Posté le 03-12-2010 à 17:21:51  profilanswer
 

E-Nyar a écrit :


Ça dépend comment on veut répondre à la question, là tu vas chercher les clients et toutes leurs factures dans le magasins A et toutes leurs factures dans le magasins B et tu ne prends que ceux qui ont des factures dans les 2.


 
C'est une manière de l'interpréter.
 

E-Nyar a écrit :

D'ailleurs petite question pourquoi ne pas remonter le filtre sur magasin A et magasin B directement dans la jointure ? (bon ça change rien au plan d'exécution vu que l'optimiser va les remonter lui-même, mais je trouve ça plus compréhensible si par hasard tu te retrouves avec 4 ou 5 filtres sur les clients par la suite pour pas mélanger les choux et les carottes).


 
Par habitude.:D
J'ai des collègues qui en sont encore aux jointures uniquement via la clause where, si je mets autre chose que les identifiants dans le join ils ont tendance à s'y perdre.


---------------
Can't buy what I want because it's free -
n°2039929
skeye
Posté le 03-12-2010 à 17:24:57  profilanswer
 

E-Nyar a écrit :


 
Le not exists a traduire en jointure c'est pas mal non plus ;)


 
mais non, faut juste avoir l'habitude.:D
Par contre il faut vraiment passer la condition dans le JOIN ce coup-ci, les collègues souffrent.:D
 
A mais pas B :
 

Code :
  1. SELECT DISTINCT c.*
  2. FROM clients c
  3.        JOIN facture f ON c.id = f.client_id AND f.magasin_id = 'A'
  4.        LEFT OUTER JOIN facture f2 ON c.id = f2.client_id AND f2.magasin_id = 'B'
  5. WHERE f2.id IS NULL


---------------
Can't buy what I want because it's free -
n°2039931
E-Nyar
I ain't no nice guy after all
Posté le 03-12-2010 à 17:31:26  profilanswer
 

skeye a écrit :

 

mais non, faut juste avoir l'habitude.:D
Par contre il faut vraiment passer la condition dans le JOIN ce coup-ci, les collègues souffrent.:D

 

A mais pas B :

 
Code :
  1. SELECT DISTINCT c.*
  2. FROM clients c
  3.        JOIN facture f ON c.id = f.client_id AND f.magasin_id = 'A'
  4.        LEFT OUTER JOIN facture f2 ON c.id = f2.client_id AND f2.magasin_id = 'B'
  5. WHERE f2.id IS NULL


 

Et si c'est les clients qui n'ont aucune facture dans A ni dans B  [:kunks] (oui je sais double outer join et double is null :o )

 

Bon je pinaille après chacun a ses petites habitudes d'écriture et ça joue à pas grand chose sur les perfs. :jap:

 

P.S. : pour les collègues, ils ont qu'à s'adapter ou mourrir. Viva la Evolution !   [:el che]


Message édité par E-Nyar le 03-12-2010 à 17:32:31

---------------
Don't fuck me, I'm anonymous.
n°2040251
lopotkine
Posté le 06-12-2010 à 12:50:38  profilanswer
 

Heu, merci pour toutes ces infos, mais si j'en reviens à ma question de départ,
je constate que j'ai toujours un soucis sur la requete2.
 
Si j'utilise les solutions vues plus haut basées sur les jointures multiple, cela ne fonctionne pas: .... f1.magasin = 'A' AND f2.magasin != 'B'
(dans ma vraie base, facture.magasin est à remplacer par facture.type et A, B par
ADOM et MAG):
 
mysql> select client_id, type from facture where client_id=2327;
+-----------+------+
| client_id | type |
+-----------+------+
|      2327 | MAG  |
|      2327 | ADOM |
+-----------+------+
 
mysql> select distinct client.id, f1.type, f2.type from client join facture f1 on client.id=f1.client_id join facture f2 on client.id=f2.client_id where f1.type='ADOM' and f2.type!='MAG' and client.id = 2327;
+------+------+------+
| id   | type | type |
+------+------+------+
| 2327 | ADOM | ADOM |
+------+------+------+
1 row in set (0.00 sec)
 
Le distcint est tj là, car j'ai simplement rajouté un filtre sur l'id client, normalement, il me les faut tous de manière unique.

n°2040284
smaragdus
whores, drugs & J.S. Bach
Posté le 06-12-2010 à 14:19:02  profilanswer
 

TU veux compter les clients unique ok mais quand tu as un client qui a des factures dans 2 magasins, tu les comptes comment ?

n°2040286
lopotkine
Posté le 06-12-2010 à 14:29:03  profilanswer
 

Je crois avoir pigé le truc, merci de me confirmer:
 
Requete 1: tous les clients distincts ayant des factures de type 'A':
select distinct ... from client join facture on facture.client_id=client.id and facture.type='A'
 
Requete 2: factures A mais PAS B:
select distinct ... from client join facture on facture.client_id=client.id and facture.type='A' left outer join facture f2 on f2.client_id=client.id and f2.type='B' where f2.id is null
 
Requete 3: clients ayant des factures A ET AUSSI B:
select distinct ... from client join facture on facture.client_id=client.id and facture.type='A' left outer join facture f2 on f2.client_id=client.id and f2.type='B' where f2.id is NOT null
 
J'ai bien tout compris?
D'avance, merci.

n°2040287
skeye
Posté le 06-12-2010 à 14:31:14  profilanswer
 

La dernière te retournera le bon résultat, mais c'est très alambiqué, là, t'as pas besoin de jointure externe! :D
 
select distinct ... from client join facture on facture.client_id=client.id and facture.type='A' join facture f2 on f2.client_id=client.id and f2.type='B'


---------------
Can't buy what I want because it's free -
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  SQL/NoSQL

  Help pour une requete

 

Sujets relatifs
[RESOLU] Récupérer des valeurs par une requête ldap_searchHelp pour requête SQL
Help ! Requete MysQl avec php et html !Requete SQL... Help!!!!
I need help ! Requete MySQL sur plusieurs table[SQL] REQUETE sur laquelle je Seche, Please HELP
Structure de requete compliquée HELP PLEASE[SQL] Erreur #306 sur Requete comparant 2 mémo ! Help plz
[ resolu - sql help ] requete sql not inpb requete help me:)
Plus de sujets relatifs à : Help pour une requete


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR