2017-06-28 1 views
1

Ma table ressemble à ceci.Comment écrire une requête SQL pour sélectionner des lignes avec une valeur maximale dans une colonne

Id | Name | Ref | Date  | From 
10 | Ant | 100 | 2017-02-02 | David 
10 | Ant | 300 | 2016-01-01 | David 
2 | Cat | 90 | 2017-09-09 | David 
2 | Cat | 500 | 2016-02-03 | David 
3 | Bird | 150 | 2017-06-28 | David 

Ceci est le résultat que je veux.

Id | Name | Ref | Date  | From 
3 | Bird | 150 | 2017-06-28 | David 
2 | Cat | 500 | 2016-02-03 | David 
10 | Ant | 300 | 2016-01-01 | David 

Ma cible est la plus haute Ref par Id, trié par Date de commande desc.

Pourriez-vous s'il vous plaît me parler de la façon d'écrire une requête sql en utilisant pl/sql.

+1

Chaque fois que vous êtes invité à résoudre un problème de "plus haut" ou "plus bas", vous devez penser à des doublons. Que se passerait-il si les deux lignes pour Ant avaient Ref = 300? Lequel des deux est "le plus haut"? Avez-vous besoin d'inclure les deux lignes dans le résultat? Ou prenez juste celui avec la date la plus récente? Ou les doublons ne sont-ils pas possibles dans la colonne Ref? Ensuite, lorsque vous commandez les résultats par date - si deux dates sont égales, comment vous pouvez rompre l'égalité? – mathguy

Répondre

0

Vous pouvez utiliser cette

SELECT 
Id 
,Name 
,Ref 
,[Date] 
FROM(
SELECT 
* 
, ROW_NUMBER() OVER(PARTITION BY ID ORDER BY Ref DESC) AS Row# 
FROM yourtable 
) A WHERE Row# = 1 
ORDER BY A.[Date] DESC 
-1
SELECT Id, Name, Max(Ref) as Ref, Min(`Date`) as `Date` 
From Forge 
Group By Id, Name 
Order by Min(`Date`) desc; 
+3

Cela ne ressemble pas à Oracle - il n'y a pas de backticks dans Oracle. Après avoir corrigé cela, la requête choisira le max (ref) d'une rangée et la min (date) d'une autre - pas ce que l'OP voulait. – mathguy

1

Ce genre d'exigence (où vous avez besoin du maximum ou minimum d'une colonne, regroupés par un autre, mais vous avez besoin de toutes les données de la max ou min ligne) est à peu près ce que fonctions analytiques sont pour. J'ai utilisé row_number - si les liens sont possibles, vous devez clarifier l'affectation (voir mon commentaire sous votre question), et en fonction des détails, une autre fonction analytique peut être plus appropriée - peut-être rank().

with 
    my_table (id, name, ref, dt, frm) as (
     select 10, 'Ant' , 100, date '2017-02-02', 'David' from dual union all 
     select 10, 'Ant' , 300, date '2016-01-01', 'David' from dual union all 
     select 2, 'Cat' , 90, date '2017-09-09', 'David' from dual union all 
     select 2, 'Cat' , 500, date '2016-02-03', 'David' from dual union all 
     select 3, 'Bird', 150, date '2017-06-28', 'David' from dual 
    ) 
-- End of simulated table (for testing purposes only, not part of the solution). 
-- SQL query begins BELOW THIS LINE. 
select id, name, ref, dt, frm 
from  (
      select id, name, ref, dt, frm, 
        row_number() over (partition by id order by ref desc, dt desc) as rn 
      from my_table 
     ) 
where rn = 1 
order by dt desc 
; 

ID NAME REF DT   FRM 
-- ---- --- ---------- ----- 
3 Bird 150 2017-06-28 David 
2 Cat 500 2016-02-03 David 
10 Ant 300 2016-01-01 David 
0

Une autre solution avec une jointure réflexive (idée est venue d'ici: How can I SELECT rows with MAX(Column value), DISTINCT by another column in SQL?):

with 
    my_table (id, name, ref, dt, frm) as (
     select 10, 'Ant' , 100, date '2017-02-02', 'David' from dual union all 
     select 10, 'Ant' , 300, date '2016-01-01', 'David' from dual union all 
     select 10, 'Ant' , 300, date '2015-01-01', 'David' from dual union all 
     select 2, 'Cat' , 90, date '2017-09-09', 'David' from dual union all 
     select 2, 'Cat' , 500, date '2016-02-03', 'David' from dual union all 
     select 3, 'Bird', 150, date '2017-06-28', 'David' from dual 
    ) 
-- End of simulated table (for testing purposes only, not part of the solution). 
-- SQL query begins BELOW THIS LINE. 

select m1.* 
from my_table m1 
left join my_table m2 
on m1.id = m2.id and (
-- this is basically a comparator: order by ref desc, dt desc 
m1.ref < m2.ref or (
    m1.ref = m2.ref and 
    m1.dt < m2.dt 
) 
) where m2.id is null order by m1.dt desc 
; 

     ID NAME  REF DT  FRM 
---------- ---- ---------- --------- ----- 
     3 Bird  150 28-JUN-17 David 
     2 Cat   500 03-FEB-16 David 
     10 Ant   300 01-JAN-16 David 
0

Utilisez le "mieux que" principal SQL:

select a.Id, a.Name, a.Ref, a.Dt, a.frm 
from table_name a 
left join table_name b on a.id = b.id and b.ref > a.ref -- b.ref > a.ref would make b.ref "better" that a 
where b.id is null -- Now check and make sure there is nothing "better" 
group by a.id;