Enregistrements Oracle SELECT TOP 10

144

J'ai un gros problème avec une instruction SQL dans Oracle. Je souhaite sélectionner les 10 meilleurs enregistrements classés par STORAGE_DB qui ne figurent pas dans une liste d'une autre instruction SELECT.

Celui-ci fonctionne bien pour tous les enregistrements:

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
      STORAGE_GB IS NOT NULL AND 
        APP_ID NOT IN (SELECT APP_ID
                       FROM HISTORY
                        WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Mais quand j'ajoute

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Je reçois une sorte de disques "aléatoires". Je pense parce que la limite a lieu avant la commande.

Quelqu'un a-t-il une bonne solution? L'autre problème: cette requête est vraiment lente (10k + enregistrements)

opHASnoNAME
la source

Réponses:

199

Vous devrez mettre votre requête actuelle dans la sous-requête comme ci-dessous:

SELECT * FROM (
  SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC )
WHERE ROWNUM <= 10

Oracle applique le rownum au résultat une fois qu'il a été renvoyé.
Vous devez filtrer le résultat après son renvoi, une sous-requête est donc requise. Vous pouvez également utiliser la fonction RANK () pour obtenir les résultats Top-N.

Pour les performances, essayez d'utiliser NOT EXISTSà la place de NOT IN. Voir ceci pour plus.

Padmarag
la source
NOT EXISTS ne fonctionne pas dans ce scénario (opérateur relationnel invalide) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME
3
Certains peuvent dire que cela est susceptible de désactiver les utilisateurs d'Oracle.
MrBoJangles
2
Vérifiez la FETCH NEXT N ROWS ONLYréponse ci-dessous.
Mohnish
@Padmarag: Quand un classement s'applique-t-il dans une requête comme celle-ci - Sélectionnez * dans SomeTable où someColumn = '123' et rownum <= 3. Est-ce après avoir sélectionné les résultats de [Select * from SomeTable où someColumn = '123']
Shirgill Farhan
55

Si vous utilisez Oracle 12c, utilisez:

FETCH SUIVANT N RANGS SEULEMENT

SELECT DISTINCT 
  APP_ID, 
  NAME, 
  STORAGE_GB, 
  HISTORY_CREATED, 
  TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE  
  FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
      APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009')
  ORDER BY STORAGE_GB DESC
FETCH NEXT 10 ROWS ONLY

Plus d'infos: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

Volpato
la source
2
c'est de l'or comparé à une autre réponse
aswzen
Je suis d'accord avec aswzen
Austin Springer
1
Je veux donner à cette réponse 100 votes positifs! Mais hélas, je n’en ai qu’un à attribuer. C'est un!
eidylon
23

En ce qui concerne la mauvaise performance, il y a un certain nombre de choses que cela pourrait être, et cela devrait vraiment être une question distincte. Cependant, il y a une chose évidente qui pourrait être un problème:

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Si HISTORY_DATE est vraiment une colonne de date et si elle a un index, cette réécriture fonctionnera mieux:

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY')  

En effet, une conversion de type de données désactive l'utilisation d'un index B-Tree.

APC
la source
22

essayer

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
Shaaban
la source
11

Vous obtenez un ensemble apparemment aléatoire car ROWNUM est appliqué avant ORDER BY. Votre requête prend donc les dix premières lignes et les trie.0 Pour sélectionner les dix meilleurs salaires, vous devez utiliser une fonction analytique dans une sous-requête, puis filtrer cela:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
vijaya
la source