Oracle : Restriction sur une requete

Oracle : Restriction sur une requete - SQL/NoSQL - Programmation

Marsh Posté le 13-01-2012 à 11:29:30    

J'ai une base Oracle contenant plusieurs milliers de références et je fais une recherche sur quelques champs :
 
nudemande | nupatient | lesion
(int)          | (int)        | (txt)
 
Je veux sélectionner les demandes qui ont une lesion de type "UR0700 ET UR 7700", donc si je fais un :
"and lesion in ('UR0700', 'UR7700')"
ça me sort bien les demandes qui ont ces deux lésions...
 
MAIS, cette demande en question peut avoir une troisième, voire 4ème lésion :
(exemple sorti avec 3 lésions)
 
1748494 | 1835519 | UR0713
1748494 | 1835519 | 7700
1748494 | 1835519 | UR0700
 
Comment faire pour filtrer dans une seule requête, les demandes qui ont ces lésions présentes et uniquement ces deux là... (pas une seule, ni les 2 + 1 différente, etc).
J'imagine qu'il faudrait pouvoir imbriquer deux requêtes mais j'ai du mal à voir comment.
 
Je pensais à une première requête qui me sorte la liste des n° de demande, et après je fais une vérification pour voir si ces n° de demande contiennent bien 2 lésions et seulement 2...


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 11:29:30   

Reply

Marsh Posté le 13-01-2012 à 12:16:33    

C'est pas clair. Ton premier exemple ne fait pas ce que tu demandes dans la suite...
Il te faut quoi, les demandes qui ont exactement les lésions spécifiées?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 14:32:24    

Ah oui effectivement, mon exemple porte sur :
1) lésions ayant comme n° de demande '1748394' (pour vérifier le nombre de lésions = en l'occurence, 3, la UR0713 est en trop)
 
2) La requête portant sur les 2 lésions que je cherche (version simplifiée) :
select *
from demande, codelesion
where codelesion in ('7700','UR0700')
 
Mais avec cette requête (2), je peux avoir un patient qui a 5 lésions dont les 2 que je cherche, alors que ce que je souhaite ce sont les patients n'ayant QUE les 2 lésions recherchées (aucune autre et pas une seule...)
 
ça semble plus clair ? [:cerveau quest]


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 14:37:11    

Oui, c'est plus clair...mais plus compliqué à faire! :D
Il peut y avoir plusieurs fois la même lésion sur une demande?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 15:08:19    

c'est bien pour ça que je galère :D
On part du principe qu'il n'y a qu'une fois la même lésion sur une demande :)
 
Dans l'idée, je partais sur une combinaison de requêtes :
 
select numdemande, etc
from tables...
where numdemande in (
select unique (demande)
from tables...
where lesion in ('bla')
)
...
 
et là je bloque...
 
J'aurai voulu faire une liste des demandes contenant les 2 lésions (ou plus), et à partir de cette liste de demande, vérifier le nombre de lésions totales par demande (si =2 alors il n'y a bien que ces 2 lésions). Si je peux avoir une correspondance :
numdem | nombrelesions
ce serait déjà pas mal.


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 15:14:39    

Ce genre de choses doit pouvoir marcher, à défaut d'être joli?
 
select numdemande, count(*)
from tables
where lesion in (1,2,3,4)
group by numdemande
having count(*) = 4;
 
Pour chaque demande on compte le nombre de lésions qui font partie de la liste qu'on cherche, et on ne garde que celles qui ont le nombre exact?


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 15:30:07    

Oui pour ta dernière question, par contre la requête ne fonctionne pas...
 
En fait, ils vont tous sortir "2".
Le having count va se baser sur les résultats liés à la condition "lesion in ('','')", et cette condition renvoie bien 2 résultats, mais cela ne veut pas dire que la demande n'en a pas 3 ou 4...


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 15:35:05    

Excellente remarque.:D
Dans ce style alors?

 
Code :
  1. SELECT t1.numdemande, count(*)
  2. FROM TABLE t1
  3.      LEFT OUTER JOIN TABLE t2 ON t1.numdemande = t2.numdemande AND t1.lesion IN (1,2,3,4) AND t2.lesion NOT IN (1,2,3,4)
  4. WHERE t2.numdemande IS NULL
  5. GROUP BY t1.numdemande
  6. HAVING count(*) = 4;
 

Idem qu'avant sauf qu'on fait une auto-jointure externe pour pouvoir sortir ceux qui ont des lesions en-dehors de la liste voulue...:D


Message édité par skeye le 13-01-2012 à 15:37:09

---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 15:58:56    

La jointure externe me semble une bonne idée, j'ai tenté mais c'est pas encore ça :
 

Code :
  1. select d.nuddeext, count(*)
  2. from demande d, examencodifadi ad1 left outer join examencodifadi ad2
  3.                                     on ad1.nudde = ad2.nudde
  4.                                     and ad1.lesion in ('UR0700', '7700')
  5.                                     and ad2.lesion not in ('UR0700', '7700')
  6. where d.nudde = ad1.nudde
  7. and   d.datenreg > TO_DATE('01012010','DDMMYYYY')
  8. and   d.datenreg < TO_DATE('31122011','DDMMYYYY')
  9. and   ad1.modprel = 'B'
  10. and   ad1.typtech = 'H'
  11. and   ad1.organe = 'UR'
  12. and   ad1.lesion in ('UR0700', '7700')
  13. group by d.nuddeext
  14. having count(*)=2;


 
J'ai encore des résultats qui ont 3 lésions, mais j'ai l'impression qu'on est pas loin ^^ (p'tre la formulation de ma jointure qui coince un peu)


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 16:05:31    

Tu as oublié ad2.nudde is null dans le where, si je ne bigle pas.


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 16:05:31   

Reply

Marsh Posté le 13-01-2012 à 16:43:58    

ou un truc du genre
 
select user, count(*)
from table
where user not in ( select user from table where lesion in (unwanted,list) )
group by user
having count(*)=2

Reply

Marsh Posté le 13-01-2012 à 16:47:45    

ah ouais, ça fonctionne bien avec :)
 
Il sert à quoi ? (juste pour ma culture g :) )


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 16:48:52    

robbyone a écrit :

lesion in (unwanted,list)


 
Le souci c'est que cette "unwanted list" est trop longue et trop complexe à retrouver, il y a beaucoup trop de possibilités/combinaisons.


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 13-01-2012 à 17:02:00    

KevinTran a écrit :

ah ouais, ça fonctionne bien avec :)

 

Il sert à quoi ? (juste pour ma culture g :) )

 

C'est une astuce toute bête pour remplacer des "not in"/"not exists" : une jointure externe avec un critère qu'on ne veut pas (ici, le lesion not in...), et ensuite on prend toutes les lignes pour lesquelles cette table ne retourne rien (donc null pour tous les champs de cette table).


Message édité par skeye le 13-01-2012 à 17:03:02

---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 17:03:47    

Une autre façon de faire serait celle-ci :

Code :
  1. SELECT ...
  2. FROM TABLE t1
  3. WHERE lesion IN (1,2,3,4)
  4. AND NOT EXISTS (SELECT 1 FROM TABLE t2 WHERE t1.id = t2.id AND t2.lesion NOT IN (1,2,3,4))


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 17:04:03    

...enfin là il manque le compte, mais tu vois l'idée...


Message édité par skeye le 13-01-2012 à 17:04:09

---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 17:28:13    

KevinTran a écrit :


 
Le souci c'est que cette "unwanted list" est trop longue et trop complexe à retrouver, il y a beaucoup trop de possibilités/combinaisons.


 
me semble que cette liste est constituée de toutes les lésions sauf les 2 que tu cherches ... => select * not on (1,2) ...

Reply

Marsh Posté le 13-01-2012 à 17:35:34    

robbyone a écrit :


 
me semble que cette liste est constituée de toutes les lésions sauf les 2 que tu cherches ... => select * not on (1,2) ...


c'est bien trop lourd à mettre en place...


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 13-01-2012 à 17:39:24    

Merci beaucoup :)


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 24-01-2012 à 12:10:03    

KevinTran a écrit :

Merci beaucoup :)


 
Et les opérateurs ensemblistes ?
 

Code :
  1. select
  2.     *
  3. from
  4.     TABLE
  5. where
  6.     COL in ('1', '2')
  7. minus
  8. select
  9.     *
  10. from
  11.    TABLE
  12. group by
  13.    ID
  14. having count(COL) > (select count(*) from TABLE where COL in ('1', '2'));


 
Avec un with, pas d'impact sur les perfs et la syntaxe serais plus simple (en principe).


---------------
| AMD Ryzen 7 7700X 8C/16T @ 4.5-5.4GHz - 64GB DDR5-6000 30-40-40 1T - AMD Radeon RX 7900 XTX 24GB @ 2680MHz/20Gbps |
Reply

Marsh Posté le 24-01-2012 à 13:52:29    

Intéressant, c'est possible de détailler un peu plus l'utilité du "minus" ?
 
J'ai vu par la suite (pour une autre requête) que je pouvais aussi utiliser une union, je ne sais pas si ça aurait marché dans ce cas là.


---------------
http://www.kevintran.fr
Reply

Marsh Posté le 24-01-2012 à 14:05:54    

C'est la soustraction de deux ensemble :
- celui des lignes qui réponde aux lessions recherchées
- celui des lignes qui réponde aux lessions recherchées mais qui ont un nombre de lessions supérieur au nombre de lessions recherchées
 
Après c'est qu'une piste, car je ne pense pas que ma requete marche telle quelle.


---------------
| AMD Ryzen 7 7700X 8C/16T @ 4.5-5.4GHz - 64GB DDR5-6000 30-40-40 1T - AMD Radeon RX 7900 XTX 24GB @ 2680MHz/20Gbps |
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed