1
votes

Comment SELECT en SQL basé sur une valeur de la même colonne de table?

J'ai le tableau suivant

| id | date       | team |
|----|------------|------|
| 1  | 2019-01-05 | A    |
| 2  | 2019-01-05 | A    |
| 3  | 2019-01-01 | A    |
| 4  | 2019-01-04 | B    |
| 5  | 2019-01-01 | B    |

Comment puis-je interroger le tableau pour recevoir les valeurs les plus récentes pour les équipes?

Par exemple, le résultat ci-dessus table serait des identifiants 1,2,4.


0 commentaires

4 Réponses :


3
votes

Dans ce cas, vous pouvez utiliser les fonctions de fenêtre:

select distinct on (t.team) t.*
from t
order by t.team, t.date desc;

Dans certaines bases de données une sous-requête corrélée est plus rapide avec les bons index (je ne l'ai pas testé avec Postgres): p >

select t.*
from t
where t.date = (select max(t2.date) from t t2 where t2.team = t.team);

Et si vous ne vouliez qu'une seule ligne par équipe, la réponse canonique est:

select t.*
from (select t.*, rank() over (partition by team order by date desc) as seqnum
      from t
     ) t
where seqnum = 1;

Cependant, cela ne fonctionne pas dans ce cas, car vous voulez toutes les lignes de la date la plus récente.


0 commentaires

0
votes

Si votre ensemble de données est volumineux, considérez la fonction analytique max dans une sous-requête:

with cte as (
  select
    id, date, team,
    max (date) over (partition by team) as max_date
  from t
)
select id
from cte
where date = max_date

Notamment, max est O (n ), il devrait donc être assez efficace. Je ne prétends pas connaître l'implémentation réelle sur PostgreSQL, mais je suppose que c'est O (n).


0 commentaires

0
votes

Encore une possibilité, générique:

select * from t join (select max(date) date,team from t
                        group by team) tt
  using(date,team)


0 commentaires

0
votes

La fonction de fenêtre est la meilleure solution pour vous.

| team |  ids   |
|------|--------|
|  A   | [1, 2] |
|  B   | [4]    |

Cette requête renverra cette table:

select team, array_agg(id) ids
from (
  select team, id, rank() over (partition by team order by date desc) as row_num
  from table
) t
where row_num = 1
group by team

Si vous l'obtenez une ligne par équipe, vous devez utiliser array_agg fonction.

| id |
|----|
| 1  |
| 2  |
| 4  |

Cette requête renverra cette table:

select id
from (
  select team, id, rank() over (partition by team order by date desc) as row_num
  from table
) t
where row_num = 1


0 commentaires