J'essaie de comprendre comment je pourrais faire cela en SQL. J'ai une table avec les colonnes suivantes dans la table Client - (Customer_Id, Gender, Birthday). La question est - je dois trouver le premier et le dernier né, par sexe. Essentiellement Min et Max par différents groupes.
select a.Customer_id, a.gender, b.min_birthday
from(
select gender, min(birthday) min_birthday
from Sales..Customer group by gender) b join Sales..Customer a on b.gender = a.gender
and b.min_birthday = a.birthday
L'ensemble de résultats devrait ressembler à ceci
188 M 2008-09-01 00:00:00.000 123 M 2017-07-05 00:00:00.000 111 F 2000-01-01 00:00:00.000 567 F 2015-02-07 00:00:00.000
Je pourrais faire 4 UNION S et le comprendre de cette façon, mais ce serait inefficace.
Voici ce que j'ai trouvé mais cela ne fonctionnera pas non plus. Comment faire pour MAX groupes également dans une seule requête?
123 M 2017-07-05 00:00:00.000 345 M 2016-08-01 00:00:00.000 555 F 2012-01-09 00:00:00.000 567 F 2015-02-07 00:00:00.000 789 F 2013-01-02 00:00:00.000 111 F 2000-01-01 00:00:00.000 188 M 2008-09-01 00:00:00.000
3 Réponses :
Une méthode utilise des fonctions de fenêtre:
select c.*
from ((select top (1) c.*
from customer c
where gender = 'M'
order by birthday
) union all
(select top (1) c.*
from customer c
where gender = 'F'
order by birthday
) union all
(select top (1) c.*
from customer c
where gender = 'M'
order by birthday desc
) union all
(select top (1) c.*
from customer c
where gender = 'F'
order by birthday desc
)
) c;
Utilisez rank () au lieu de row_number () si vous voulez des liens. p>
Cela dit, avec un index sur (sexe, anniversaire) et (sexe, anniversaire desc) (les deux index peuvent ne plus être nécessaires si l'optimiseur a amélioré), l'approche union all devrait très bien fonctionner:
select customer_id, gender, birthday
from (select c.*,
row_number() over (partition by gender order by birthday) as seqnum_asc,
row_number() over (partition by gender order by birthday desc) as seqnum_desc
from customer c
) c
where 1 in (seqnum_asc, seqnum_desc);
Gordon, merci. La fonction de classement ne me donnera que des anniversaires minimum pour les deux groupes de sexe (car vous ne récupérez que le premier rang). Comment récupérer le nombre maximum d'anniversaires, étant donné que leur classement sera toujours dynamique?
@peppa. . . C'était une faute de frappe. J'ai mis desc dans le nom, mais pas dans la clause order by .
En fait, un UNION ALL suffit :)
select gender, min(birthday), max(birthday) from Sales..Customer group by gender
Mais une meilleure performance serait avec:
select gender, min(birthday) birthday, 'MIN' Aggregate from Sales..Customer group by gender union all select gender, max(birthday), 'MAX' from Sales..Customer group by gender
Mais le résultat sera légèrement différent de celui souhaité.
Vous pouvez le faire avec NOT EXISTS:
> id | gender | birthday > :-- | :----- | :------------------ > 111 | F | 01/01/2000 00:00:00 > 567 | F | 07/02/2015 00:00:00 > 188 | M | 01/09/2008 00:00:00 > 123 | M | 05/07/2017 00:00:00
Voir le démo .
Résultats:
select c.* from Customer c where not exists ( select 1 from Customer where gender = c.gender and birthday < c.birthday ) or not exists ( select 1 from Customer where gender = c.gender and birthday > c.birthday ) order by c.gender, c.birthday