Compte tenu de cet ensemble de données:
ID Name City Birthyear
1 Egon Spengler New York 1957
2 Mac Taylor New York 1955
3 Sarah Connor Los Angeles 1959
4 Jean-Luc Picard La Barre 2305
5 Ellen Ripley Nostromo 2092
6 James T. Kirk Riverside 2233
7 Henry Jones Chicago 1899
J'ai besoin de trouver les 3 personnes les plus âgées, mais seulement une de chaque ville.
Si ce ne sont que les trois plus anciens, ce serait ...
Cependant, puisque Egon Spengler et Mac Taylor sont tous deux situés à New York, Egon Spengler abandonnerait et le prochain (Sarah Connor/Los Angeles) entrerait à la place.
Des solutions élégantes?
Mise à jour:
Actuellement, une variante de PConroy est la solution la meilleure/la plus rapide:
SELECT P.*, COUNT(*) AS ct
FROM people P
JOIN (SELECT MIN(Birthyear) AS Birthyear
FROM people
GROUP by City) P2 ON P2.Birthyear = P.Birthyear
GROUP BY P.City
ORDER BY P.Birthyear ASC
LIMIT 10;
Sa requête d'origine avec "IN" est extrêmement lente avec les grands ensembles de données (abandonnée après 5 minutes), mais le déplacement de la sous-requête vers un JOIN l'accélérera beaucoup. Cela a pris environ 0,15 seconde pendant env. 1 mio de lignes dans mon environnement de test. J'ai un index sur "City, Birthyear" et un second sur "Birthyear".
Remarque: Ceci est lié à ...
Probablement pas la plus élégante des solutions, et les performances de IN
peuvent souffrir sur des tables plus grandes.
La requête imbriquée obtient le minimum Birthyear
pour chaque ville. Seuls les enregistrements qui ont ce Birthyear
sont mis en correspondance dans la requête externe. Ordonner par âge puis limiter à 3 résultats vous permet d'obtenir les 3 personnes les plus âgées qui sont aussi les plus âgées de leur ville (Egon Spengler abandonne ..)
SELECT Name, City, Birthyear, COUNT(*) AS ct
FROM table
WHERE Birthyear IN (SELECT MIN(Birthyear)
FROM table
GROUP by City)
GROUP BY City
ORDER BY Birthyear DESC LIMIT 3;
+-----------------+-------------+------+----+
| name | city | year | ct |
+-----------------+-------------+------+----+
| Henry Jones | Chicago | 1899 | 1 |
| Mac Taylor | New York | 1955 | 1 |
| Sarah Connor | Los Angeles | 1959 | 1 |
+-----------------+-------------+------+----+
Modifier - ajouté GROUP BY City
à la requête externe, car les personnes ayant les mêmes années de naissance renverraient plusieurs valeurs. Le regroupement sur la requête externe garantit qu'un seul résultat sera retourné par ville, si plus d'une personne a ce minimum Birthyear
. La colonne ct
indiquera si plus d'une personne existe dans la ville avec cette Birthyear
Ce n'est probablement pas la solution la plus élégante et la plus rapide, mais cela devrait fonctionner. J'attends avec impatience les solutions des vrais gourous de la base de données.
select p.* from people p,
(select city, max(age) as mage from people group by city) t
where p.city = t.city and p.age = t.mage
order by p.age desc
Quelque chose comme ca?
SELECT
Id, Name, City, Birthyear
FROM
TheTable
WHERE
Id IN (SELECT TOP 1 Id FROM TheTable i WHERE i.City = TheTable.City ORDER BY Birthyear)
@BlaM
MIS À JOUR vient de trouver qu'il est bon d'utiliser USING au lieu de ON. il supprimera le résultat des colonnes en double.
SELECT P.*, COUNT(*) AS ct
FROM people P
JOIN (SELECT City, MIN(Birthyear) AS Birthyear
FROM people
GROUP by City) P2 USING(Birthyear, City)
GROUP BY P.City
ORDER BY P.Birthyear ASC
LIMIT 10;
ORIGINAL POST
salut, j'ai essayé d'utiliser votre requête mise à jour mais j'obtenais des résultats erronés jusqu'à ce que j'ajoute une condition supplémentaire pour rejoindre (également une colonne supplémentaire dans la sélection de jointure). transféré à votre requête, j'utilise ceci:
SELECT P.*, COUNT(*) AS ct
FROM people P
JOIN (SELECT City, MIN(Birthyear) AS Birthyear
FROM people
GROUP by City) P2 ON P2.Birthyear = P.Birthyear AND P2.City = P.City
GROUP BY P.City
ORDER BY P.Birthyear ASC
LIMIT 10;
en théorie, vous ne devriez pas avoir besoin du dernier GROUP BY P.City, mais je l'ai laissé là pour le moment, juste au cas où. le supprimera probablement plus tard.
Pas joli mais devrait aussi fonctionner avec plusieurs personnes avec le même dob:
Données de test:
select id, name, city, dob
into people
from
(select 1 id,'Egon Spengler' name, 'New York' city , 1957 dob
union all select 2, 'Mac Taylor','New York', 1955
union all select 3, 'Sarah Connor','Los Angeles', 1959
union all select 4, 'Jean-Luc Picard','La Barre', 2305
union all select 5, 'Ellen Ripley','Nostromo', 2092
union all select 6, 'James T. Kirk','Riverside', 2233
union all select 7, 'Henry Jones','Chicago', 1899
union all select 8, 'Blah','New York', 1955) a
Requete:
select
*
from
people p
left join people p1
ON
p.city = p1.city
and (p.dob > p1.dob and p.id <> p1.id)
or (p.dob = p1.dob and p.id > p1.id)
where
p1.id is null
order by
p.dob