web-dev-qa-db-fra.com

Oracle SQL GROUP BY aide "pas une expression GROUP BY"

J'ai une table some_table comme

+--------+----------+---------------------+-------+
| id     | other_id | date_value          | value |
+--------+----------+---------------------+-------+
| 1      | 1        | 2011-04-20 21:03:05 | 104   |
| 2      | 2        | 2011-04-20 21:03:04 | 229   |
| 3      | 3        | 2011-04-20 21:03:03 | 130   |
| 4      | 1        | 2011-04-20 21:02:09 | 97    |
| 5      | 2        | 2011-04-20 21:02:08 | 65    |
| 6      | 3        | 2011-04-20 21:02:07 | 101   |
| ...    | ...      | ...                 | ...   |
+--------+----------+---------------------+-------+

Et je veux les derniers enregistrements pour les other_id1, 2 et 3. La question évidente que je suis venu avec est

SELECT id, other_id, MAX(date_value), value
  FROM some_table 
 WHERE other_id IN (1, 2, 3) 
 GROUP BY other_id

Cependant, il génère une exception "not a GROUP BY expression". J'ai essayé d'ajouter tous les autres champs (par exemple, id, value) dans la clause GROUP BY, mais cela ne fait que renvoyer le tout, exactement comme s'il n'y avait pas de clause GROUP BY. (Eh bien, cela a également un sens.)

Alors ... je lis le manuel Oracle SQL, et je ne trouve que quelques exemples impliquant uniquement des requêtes à deux ou trois colonnes et quelques fonctions de regroupement i-have-never-seen-before. Comment puis-je aller et revenir

+--------+----------+---------------------+-------+
| id     | other_id | date_value          | value |
+--------+----------+---------------------+-------+
| 1      | 1        | 2011-04-20 21:03:05 | 104   |
| 2      | 2        | 2011-04-20 21:03:04 | 229   |
| 3      | 3        | 2011-04-20 21:03:03 | 130   |
+--------+----------+---------------------+-------+

(les dernières entrées pour chaque other_id)? Je vous remercie.

14
Yanick Rochon
 select id, other_id, date_value, value from
 (
   SELECT id, other_id, date_value, value, 
   ROW_NUMBER() OVER (partition by other_id order BY Date_Value desc) r
   FROM some_table 
   WHERE other_id IN (1, 2, 3) 
 )
 where r = 1
15
Michael Pakhantsov

Vous ne pouvez pas sélectionner une colonne qui ne soit ni un agrégat ni uniquement les colonnes utilisées dans la clause GROUP BY.

Cependant, il y a trois façons de le faire:

  • Vous pouvez utiliser des fonctions analytiques

    SELECT id, other_id, date_value, value
      FROM ( SELECT id, other_id, date_value, MAX(date_value) OVER (partition by other_id) max_date, value
               FROM some_table )
     WHERE max_date = date_value;
    
  • Vous pouvez utiliser une auto-jointure avec une clause «supérieur à» et détecter votre maximum de cette façon.

    SELECT t1.id, t1.other_id, t1.date_value, t1.value
      FROM some_table t1
      LEFT OUTER JOIN some_table t2
                   ON ( t1.other_id = t2.other_id AND t2.date_value > t1.date_value )
     WHERE t2.other_id IS NULL
    
  • Vous pouvez utiliser une sous-requête

      WITH max AS ( SELECT other_id, MAX(date_value) FROM some_table GROUP BY other_id )
    SELECT id, other_id, date_value, value
      FROM some_table
     WHERE ( other_id, date_value ) IN ( SELECT * FROM max )
    
8
Benoit

Probablement c'est le moyen le plus simple

SELECT id, other_id, date_value, value
FROM some_table
WHERE date_value in (SELECT MAX(date_value)
                     from some_table
                     GROUP BY other_id
                     HAVING other_id in (1,2,3));

Testez la requête ci-dessus ici

0
Shivanand