web-dev-qa-db-fra.com

Comment utiliser MAX () sur un résultat de sous-requête?

Je suis nouveau dans Oracle et le monde SQL. J'ai un petit problème avec une requête que je n'arrive pas à comprendre pendant toute ma vie. J'ai passé quelques heures à essayer différentes approches et je ne parviens pas à obtenir le résultat escompté. Alors voici ma requête:

SELECT *
from(Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
    count(membership_history.MEM_TYPE) as membership_count
    from membership_history
    JOIN membership ON membership.mem_type = membership_history.mem_type
    group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
    ) g
WHERE g.membership_count = (select MAX(membership_count) from g); 

La requête interne fonctionne donc parfaitement et renvoie deux résultats. Maintenant que j'ai ces deux valeurs, j'essaie de comprendre comment retourner la ligne avec la valeur maximale de membership_count, c'est-à-dire où je reste bloqué. Dans la requête ci-dessus, j'ai essayé d'utiliser MAX () dans la clause where mais à l'intérieur de cette sélection, je reçois toujours l'erreur 'table non trouvée' (qui signifie 'g'). Ma question est donc la suivante: comment utiliser la fonction MAX () sur les résultats de ma sous-requête? Toutes les pensées ou suggestions seraient grandement appréciées !!!!!

10
user1916441

Vous n'avez pas besoin de la sous-requête qui trouve la valeur maximale.
Au lieu, ; vous avez juste besoin de la première ligne après avoir ordonné les lignes:

select * from (
  select 
    membership.mem_desc,
    membership.mem_max_rentals,
    membership_history.mem_type,      
    count(membership_history.MEM_TYPE) as membership_count
  from membership_history
  JOIN membership ON membership.mem_type = membership_history.mem_type
  group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
  ORDER BY 4 DESC  -- Added this line
) g
WHERE ROWNUM = 1. -- Added this line
12
Bohemian

Ceci est tout bon SQL. 

La meilleure façon de rechercher une valeur de colonne à l'aide de la valeur de colonne max primaire est la suivante: 

SELECT .... from tablename
WHERE ... AND
  (SELECT max(primary key name) FROM tablename WHERE .... ) = primary_key_name

cet exemple renverra une valeur scalaire.

3
user3552157

J'ai eu un problème similaire dans une requête Access ... d'après certains commentaires de ce fil de discussion, devons-nous comprendre que la fonction ACCESS MAX ne doit être utilisée que sur/avec les champs de clé primaire? ... fondamentalement, j'ai un tableau qui définit les adresses relatives à une entité, MAIS, avec une légère torsion; 1) une fois sauvegardé, aucun enregistrement ne peut être supprimé ou modifié (ce qui signifie qu'une entité peut avoir plusieurs enregistrements d'adresse), 2) toute adresse d'entité actuelle peut en avoir un; HOME (1 enregistrement) ou HOME et MAIL (2 enregistrements) ... chaque enregistrement d’adresse a un identifiant (ID) (clé primaire numérotée automatiquement), un identifiant HOME (HID) correspondant à l’enregistrement HOME (ID) (l’IDH n’est n'est PAS unique) et un ID d'entité (EID) ... donc ... lorsque j'essaie d'utiliser une sous-requête pour obtenir la valeur max (HID) d'une entité donnée, je veux uniquement que l'adresse actuelle soit renvoyée ... Ce que j’ai trouvé en utilisant MAX dans une sous-requête, c’est que son exécution échoue car ACCESS pense à tort qu’il a trop d’enregistrements correspondants pour la sous-requête ... ou ... il renvoie incorrectement les lignes qu’il ne devrait pas renvoyer. 

Le seul moyen que j'ai trouvé pour contourner ce problème était de remplacer la sous-requête max par une fonction Max qui renvoie la valeur MAX HID d'une entité (la fonction utilise l'instruction de sous-requête avec la logique DAO dans VBA)

Voici la sous-requête HOME qui fait partie de la requête principale (la requête principale doit renvoyer une ligne par entité sous la forme: EID, Home.Address, Mail.Address). 

Select *
From tbAddresses As tba1
Where tba1.aType = "Home"
  And tba1.HID = (Select MAX(tba2.HID) 
                      From tbAddresses As tba2 
                     Where tba1.EID = tba2.EID)

La requête principale ne fonctionne correctement que lorsque les clauses Where Home et Mail (non illustrées) sont remplacées par la fonction ci-dessous. Si la sous-requête MAX est incluse comme ci-dessus, cela ne fonctionne pas. 

Donc, si la fonction MAX nécessite l'utilisation d'un champ PRIMARY KEY, cela pourrait expliquer pourquoi mes requêtes échouent, bien que cela puisse sembler être une limitation majeure.

Where tba1.HID = fnGetMaxHID(tba1.EID) 

Voici quelques données de test qui ne devraient renvoyer que 3 lignes

ID    HID    EID   aType  Address
 1      1    100   Home   Blah 1
 2      2    101   Home   Blah 2
 3      2    101   Mail   PO Box Blah 0
 4      4    102   Home   Blah 3
 5      5    101   Home   Blah 4

Une dernière note, plusieurs versions de Access Pro; 2002, 2003 et 2016 ont été testés et produisent tous les mêmes résultats. Donc, ce problème est soit une bizarrerie inhérente à la fonction max, soit une sorte de bogue qui a peut-être été ignoré ou passé inaperçu? ... la fonction fonctionne comme une solution de contournement pour moi mais peut ne pas fonctionner pour les autres. Ce serait donc agréable si la fonction MAX était clarifiée.

1
bxdobs

Vous pouvez essayer quelque chose comme

 SELECT membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type, membership_count, rank() over ORDER BY membership_count DESC as ranky
from
(Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
count(membership_history.MEM_TYPE) as membership_count
from membership_history
JOIN membership ON membership.mem_type = membership_history.mem_type
group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
) 
WHERE ranky =1;
0
Scotch

Vous ne pouvez pas utiliser une table dérivée directement dans la clause où elle donnera table or view does not exist erreurso pour obtenir la valeur de comptage maximale, vous pouvez utiliser la clause HAVING ou Analytical Functions ou Rownum comme

select * from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history a
      JOIN membership b ON b.mem_type = a.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
      having count(a.MEM_TYPE) = (Select      
      MAX(count(a.MEM_TYPE)) from membership_history a
      JOIN membership b ON b.mem_type = a.mem_type
      group by (a.mem_type,b.mem_desc,b.mem_max_rentals)));

(OU)

select * from
(SELECT g.*,rank() over (order by membership_count desc) rnk from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history
      JOIN membership ON membership.mem_type = membership_history.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)) g)
WHERE rnk=1;

(OU)

select * from
(SELECT g.*,rownum rn from
      (Select membership.mem_desc,membership.mem_max_rentals,membership_history.mem_type,      
      count(membership_history.MEM_TYPE) as membership_count
      from membership_history
      JOIN membership ON membership.mem_type = membership_history.mem_type
      group by (membership_history.mem_type,membership.mem_desc,membership.mem_max_rentals)
      order by membership_count desc) g)
WHERE rn=1;
0
Aspirant

Je pense que la solution la plus propre consiste à utiliser la condition de comparaison ALL. Il est utilisé pour comparer une valeur à une liste ou à une sous-requête.

SELECT 
  m.mem_desc,
  m.mem_max_rentals,
  mh.mem_type,      
  COUNT(mh.mem_type) as membership_count
FROM membership_history mh
JOIN membership m ON m.mem_type = mh.mem_type
GROUP BY mh.mem_type,m.mem_desc,m.mem_max_rentals
HAVING membership_count >= ALL (
  SELECT count(*)
  FROM membership_history
  GROUP BY mem_type
)   
0
max68