MySQL:N行を選択しますが、1つの列に一意の値のみがあります
-
07-07-2019 - |
質問
このデータセットを指定:
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
最も古い3人を見つける必要がありますが、すべての都市の1つだけです。
もしそれが3つの最も古いものであれば、それは...
- ヘンリー・ジョーンズ/シカゴ
- Mac Taylor /ニューヨーク
- エゴン・スペングラー/ニューヨーク
ただし、エゴン・スペングラーとマック・テイラーの両方がニューヨークにいるので、エゴン・スペングラーは脱落し、代わりにエゴン・スペングラー(サラ・コナー/ロサンゼルス)が入ってきます。
エレガントなソリューションはありますか
更新:
現在、PConroyのバリエーションが最良/最速のソリューションです:
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;
" IN"を使用した元のクエリ(5分後に中止される)大きなデータセットでは非常に遅くなりますが、サブクエリをJOINに移動すると速度が大幅に向上します。約0.15秒かかりました。テスト環境で1 mio行。 「City、Birthyear」に関するインデックスがあります。 2つ目は「誕生日」の2つ目です。
注:これは...に関連しています...
解決
おそらく最もエレガントなソリューションではなく、より大きなテーブルでは IN
のパフォーマンスが低下する可能性があります。
ネストされたクエリは、各都市の最小 Birthyear
を取得します。この Birthyear
を持つレコードのみが外部クエリで一致します。年齢で並べ替えてから3つの結果に制限すると、その都市で最も高齢の3人の高齢者が得られます(Egon Spenglerは脱落します。)
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 |
+-----------------+-------------+------+----+
編集-出生年が同じ人は複数の値を返すため、 GROUP BY City
を外部クエリに追加しました。外側のクエリでグループ化すると、複数の人がその最小 Birthyear
を持っている場合、都市ごとに1つの結果のみが返されることが保証されます。 ct
列には、その Birthyear
他のヒント
これはおそらく最もエレガントで迅速なソリューションではありませんが、機能するはずです。実際のデータベースの達人の解決策を楽しみにしています。
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
そのようなものですか?
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)
あまりきれいではありませんが、同じdobを持つ複数の人でも動作するはずです:
テストデータ:
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
クエリ:
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
@BlaM
更新済み ONの代わりにUSINGを使用すると良いことがわかりました。結果の重複する列が削除されます。
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;
オリジナルポスト
こんにちは、更新されたクエリを使用しようとしましたが、結合するための追加の条件(結合選択に追加の列も)を追加するまで間違った結果を得ていました。あなたのクエリに転送され、私はこれを使用しています:
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;
理論上は、最後のGROUP BY P.Cityは必要ないはずですが、念のためにここに置いておきました。おそらく後で削除します。