2009-03-04 7 views
1

Je viens d'essayer de faire une sous-requête corrélée à la clause FROM d'une déclaration SELECT dans Oracle, mais on m'a donné une erreur indiquant que je ne pouvais pas faire la corrélation (quelque chose à l'effet que Obs.pID n'a pas été reconnu).Oracle sous-requête corrélée dans FROM liste

Est-ce que cela devrait fonctionner?

FROM ml.Person Person 
    JOIN ml.Obs ON Person.pID = Obs.pId 
     JOIN (SELECT ObsMax2.pId, ObsMax2.hdId 
       , MAX(ObsMax2.obsDate) as maxDate 
       FROM ml.Obs ObsMax2 
       WHERE ObsMax2.pId = Obs.pId 
        AND ObsMax2.obsDate < {?EndDate} 
       GROUP BY ObsMax2.pId, ObsMax2.hdId) ObsMax 
      ON Obs.pId = ObsMax.pId 
       AND Obs.hdId = ObsMax.hdId 
       AND Obs.obsDate = ObsMax.maxDate 

Ma solution semble être d'en faire une sous-requête non corrélé, et ajouter des critères à la sous-requête qui l'empêche de courir complètement amok, amok, amu-- OOF Désolé.

Je préférerais à comprendre comment bien corrèle, cependant, si possible - le point de vue qui fonctionne comme ça sous_requête faut pour construire à jamais.

+0

Vous voulez probablement factoriser la requête, non seulement résoudre ce problème que vous utilisez syntactique pour. Pensez à ajouter des éclaircissements à la question sur ce que vous essayez d'accomplir. – Alkini

+1

@ David - « pédant » :-) @Alan - Je ne suis pas sûr à quel point je suis censé parler des entrailles de ce système. En général, j'utiliserais une vue intégrée qui effectue le regroupement par pID/hdID pour obtenir l'observation la plus récente - mais cela échoue si c'est en 2009 et que vous interrogez 2008. – SarekOfVulcan

Répondre

4

Vous pouvez réaliser l'objectif de cette partie de la requête en utilisant une fonction analytique pour identifier le obsDate maximum pour chaque pid et Hdid.

Ce serait quelque chose comme:

select ... 
from (
     SELECT pId, 
       hdId, 
       obsDate 
       MAX(obsDate) over (partition by pId, hdId) maxDate 
     FROM ml.Obs 
     WHERE obsDate < {?EndDate} 
     ) 
where obsDate = maxDate 
/
+0

Le plan d'explication pour cette version était un peu meilleur que celui que j'ai trouvé, et il se sent aussi plus rapide. Je n'avais pas déjà rencontré ça - merci! – SarekOfVulcan

+0

aucun problemos. Les fonctions analytiques sont très cool. –

+1

Vous venez de me montrer comment utiliser PARTITION BY, et résolu mon problème. –

3

sous-requêtes dans la clause FROM ne peut pas se référer à d'autres tables de la même clause FROM. Suppression de la clause ObsMax2.pId = Obs.pId devrait résoudre le problème et de je peux dire vous donnera exactement le même résultat puisque la même clause est dans la condition de jointure. Cependant, comme vous le mentionnez, vous risquez de rencontrer des problèmes de performances avec le paramètre GROUP BY dans la sous-requête. D'après ce que je peux dire, vous essayez d'obtenir les enregistrements individuels pID/hdId de ml.Obs avec le plus grand nombre d'obsDate qui est inférieur à {EndDate}. Dans ce cas, qu'en est-il de déplacer la sous-requête dans la clause WHERE où vous pouvez la corréler? E.g .:

select ... 
from 
    ml.Person Person 
    join ml.Obs on Person.PID = Obs.pId 
where Obs.obsDate = (
    select max(obsDate) 
    from ml.Obs Obs2 
    where Obs2.pId = Obs.pId 
     and obs2.hdId = Obs.hdId 
     and Obs2.obsDate < {EndDate}) 
+0

Si tel est le cas, et surtout si le champ est simplement de type date, veillez à ce que plus d'une personne puisse être renvoyée (en raison de dates en double). – Alkini

+0

Oui, si la combinaison (pId, hdId, obsDate) n'est pas unique, vous pouvez obtenir plusieurs enregistrements par paire (pId, hdId). Je crois que la requête d'origine aurait le même problème cependant. –

+0

Il s'agit d'une requête pour un système EMR (dossiers médicaux). pId est PersonId, hdId identifie une observation médicale (BP, Pulse, LDL, etc.) Par conséquent, vous ne devriez pas vous inquiéter (beaucoup) de la duplication de pid/hdid/date - vous avez une valeur par document. – SarekOfVulcan

0

Vous avez préfixé plusieurs de vos tables avec "ml". mais pas partout (la première jointure, par exemple). En supposant que vous avez besoin que (pour l'utilisateur/autorisations/whatever):.

ml.Obs ON Inscrivez-Person.pID = ** ml ** Obs.pId

ou

REJOIGNEZ ml.Obs obs SUR Person.pID = Obs.pId

Il y a d'autres endroits où cela serait nécessaire aussi.

Si ce n'est pas le cas, les supprimer de votre requête parce qu'ils sont hors de propos et distrayant.