3

J'ai deux tables:Joignez-vous à une deuxième table contenant plusieurs enregistrements, prendre la dernière

person_id | name 
1   name1 
2   name2 
3   name3 

et une seconde table:

person_id | date  | balance 
1   2016-03  1200     ---- \ 
1   2016-04  700      ---- > same person 
1   2016-05  400      ----/
3   2016-05  4000 

Considérant que person_id 1 a trois inscrits à la deuxième table comment puis-je rejoindre le premier en prenant le dernier album? (c'est-à-dire: solde 400, correspondant à la date: 2016-05).

Ex: sortie de la requête:

person_id | name | balance 
1   name1  400 
2   name2  --- 
3   name3  4000 

si elle est possibile préfèrent la simplicité sur la complexité de la solution

+0

Quel moteur DB utilisez-vous? –

+0

AWS Redshift une saveur de postregres avec moins de fonctions (si possibile la requête devrait être compatible avec mysql) –

+0

J'ai supprimé les balises de base de données incompatibles. Veuillez marquer avec la base de données que vous utilisez vraiment. –

Répondre

5

Une requête de travail pour tous les moteurs DB est

select t1.name, t2.person_id, t2.balance 
from table1 t1 
join table2 t2 on t1.person_id = t2.person_id 
join 
(
    select person_id, max(date) as mdate 
    from table2 
    group by person_id 
) t3 on t2.person_id = t3.person_id and t2.date = t3.mdate 
+0

est-ce que cela considère le cas quand un enregistrement n'est pas trouvé dans la 2ème table (comme l'exemple)? Ou dois-je remplacer votre jointure par une jointure à gauche? –

+0

Si vous voulez toujours un 'person_id' vous devez utiliser une jointure gauche –

+0

Non, car lorsque vous groupez, vous ne pouvez sélectionner que les colonnes que vous regroupez ou agréger (avec par exemple max(), min(), ... –

1

La meilleure façon Pour ce faire, dans n'importe quelle base de données qui prend en charge les fonctions de la fenêtre standard ANSI (qui est la plupart d'entre eux) est:

select t1.*, t2.balance 
from table1 t1 left join 
    (select t2.*, 
      row_number() over (partition by person_id order by date desc) as seqnum 
     from table2 t2 
    ) t2 
    on t1.person_id = t2.person_id and seqnum = 1; 
+0

intéressant l'utilisation avec une seule jointure, de toute façon pensez-vous que en utilisant first_value de windows comme ceci http://docs.aws.amazon.com/redshift/latest/dg/r_Examples_of_firstlast_WF.html ce serait un peu simplifié? –

+0

@gio. . . Hélas, 'first_value()' est une fonction de fenêtre, pas une fonction d'agrégation, donc elle ne réduit pas le nombre de lignes. Vous avez toujours besoin d'une sous-requête et d'un filtrage, la réponse est donc équivalente. –

+0

ok merci +1! Quoi qu'il en soit, j'ai étiqueté cette question comme la meilleure par n-groupe, car je pense que c'est fondamentalement la même chose. Malheureusement, tant de questions à ce sujet, quand une simple fonction FIRST() ou LAST() implémentée dans la base de données pourrait résoudre tous les problèmes –