1
votes

ORA-00920: opérateur relationnel non valide lors de l'utilisation de l'opérateur IN

J'ai une table col où j'ai:

ORA-00920: invalid relational operator 

 entrez la description de l'image ici

I a renvoyé des données en utilisant une requête par année et par dept_id:

SELECT * 
FROM   offc.col 
WHERE  ( dept_id, year, marks ) IN (SELECT dept_id, 
                                           year, 
                                           Max(marks) marks 
                                    FROM   offc.col 
                                    GROUP  BY dept_id, 
                                              year 
                                    ORDER  BY dept_id, 
                                              year); 

Les données que j'ai obtenues étaient:

 entrez la description de l'image ici a>

Ici, il n'y a pas de problème car mon sql fonctionne correctement. Donc, j'avais besoin d'extraire toutes les informations de la table col , donc j'ai utilisé la sous-requête comme: p >

 SELECT dept_id, 
       year, 
       Max(marks) marks 
FROM   offc.col 
GROUP  BY dept_id, 
          year 
ORDER  BY dept_id, 
          year 

Mais, j'ai eu une erreur comme:

select * from offc.col;

J'ai cherché cette erreur sur d'autres pages également, mais je les ai trouvées comme parenthèses mal placées erreur, mais dans mon cas, je ne sais pas ce qui se passe ici?


1 commentaires

L'opérateur IN ne fonctionne pas comme ça. Vous pouvez tester une valeur unique par rapport à une liste ou une sous-requête: DEPT_ID IN (2, 5, 6) ou DEPT_ID IN (SELECT id FROM ... ) .


3 Réponses :


1
votes

Au lieu d'agréger, vous pouvez filtrer avec une sous-requête corrélée:

select c.* 
from offc.col c
inner join (
    select dept_id, year, max(marks) marks 
    from offc.col 
    group  by dept_id, year 
) m 
    on m.dpt_id = c.dept_id
    and m.year = c.year
    and m.marks = m.marks

Un index sur (dept_id, year, marks) accélérerait cette requête.

/ p>

Une autre option consiste à utiliser la fonction de fenêtre row_number():

select *
from (
    select 
        c.*, 
        row_number() over(partition by dept_id, year order by marks desc) rn
    from offc.col c
) x
where rn = 1
order by dept_id, year 

Si vous voulez pour vous en tenir à l'agrégation, vous pouvez alors joindre votre sous-requête avec la table d'origine comme suit:

select c.*
from offc.col c
where marks = (
    select max(marks)
    from offc.col c1
    where c1.dept_id = c.dept_id and c1.year = c.year
)
order by dept_id, year 


2 commentaires

pouvez-vous également m'aider avec la fonction d'agrégation? J'apprends donc j'ai besoin de connaissances de base de base


@KarkiAshwin: la sous-requête corrélée est également une connaissance de base, et elle donne généralement de meilleures performances (et une meilleure lisibilité). Pourtant, j'ai mis à jour ma réponse avec une solution qui utilise l'agrégation.



2
votes

Je suggérerais d'utiliser la fonction analytique dense_rank car elle peut renvoyer deux départements s'ils ont les mêmes notes la même année. (votre logique actuelle est la même que celle-ci)

Row_number ne vous donnera qu'un seul enregistrement aléatoire si deux départements ont les mêmes notes la même année.

SELECT * 
FROM   offc.col 
WHERE  ( dept_id, year, marks ) IN (SELECT dept_id, 
                                           year, 
                                           Max(marks) marks 
                                    FROM   offc.col 
                                    GROUP  BY dept_id, 
                                              year 
                                    -- ORDER  BY dept_id,                                              
                                -- year
); 

De plus, votre requête est correcte, supprimez simplement la commande.

select *
from (
    select 
        c.*, 
        dense_rank() over(partition by dept_id, year order by marks desc nulls last) as dr
    from offc.col c
) x
where dr = 1
order by dept_id, year 

Démo d'erreur avec order by et fonctionne bien sans order by .

Cheers !!


0 commentaires

0
votes

Effectuez un INNER JOIN avec votre sous-requête:

SELECT c.*
  FROM offc.col c
  INNER JOIN (SELECT dept_id, 
                     year, 
                     Max(marks) AS MAX_MARK
                FROM offc.col 
                GROUP BY dept_id, 
                         year) s
    ON s.DEPT_ID = c.DEPT_ID AND
       s.YEAR = c.YEAR AND
       s.MAX_MARK = c.MARKS
  ORDER BY c.DEPT_ID, c.YEAR

Un INNER JOIN ne renvoie que les lignes où la condition de jointure est satisfaite, donc toutes les lignes de OFFC.COL qui n'ont pas la valeur maximale pour MARKS pour un DEPT_ID et un YEAR particuliers ne seront pas renvoyés.


0 commentaires