重複の可能性:
SQL:グループごとの最大レコードを検索
私はそのように4つの列を持つテーブルを持っています:
name major minor revision
p1 0 4 3
p1 1 0 0
p1 1 1 4
p2 1 1 1
p2 2 5 0
p3 3 4 4
これは基本的に、プログラムの各バージョンのレコードを含むcaテーブルです。すべてのプログラムとその最新バージョンを取得するために選択を実行して、結果が次のようになるようにします。
name major minor revision
p1 1 1 4
p2 2 5 0
p3 3 4 4
名前でグループ化して各列の最大値を取得することはできません。これは、各列の最大数で終わるだけで、バージョンが最も高い特定の行ではないためです。どうすればこれを設定できますか?
私がSQLの問題を解決しようとする方法は、物事を段階的に進めることです。
各製品の最大メジャー番号は次の式で与えられます。
SELECT Name, MAX(major) AS Major FROM CA GROUP BY Name;
したがって、各製品の最大メジャー番号に対応する最大マイナー番号は、次の式で与えられます。
SELECT CA.Name, CA.Major, MAX(CA.Minor) AS Minor
FROM CA
JOIN (SELECT Name, MAX(Major) AS Major
FROM CA
GROUP BY Name
) AS CB
ON CA.Name = CB.Name AND CA.Major = CB.Major
GROUP BY CA.Name, CA.Major;
したがって、最大リビジョン(各製品の最大メジャー番号に対応する最大マイナーバージョン番号)は、次の式で与えられます。
SELECT CA.Name, CA.Major, CA.Minor, MAX(CA.Revision) AS Revision
FROM CA
JOIN (SELECT CA.Name, CA.Major, MAX(CA.Minor) AS Minor
FROM CA
JOIN (SELECT Name, MAX(Major) AS Major
FROM CA
GROUP BY Name
) AS CB
ON CA.Name = CB.Name AND CA.Major = CB.Major
GROUP BY CA.Name, CA.Major
) AS CC
ON CA.Name = CC.Name AND CA.Major = CC.Major AND CA.Minor = CC.Minor
GROUP BY CA.Name, CA.Major, CA.Minor;
テスト済み-動作し、 Andomar の query と同じ答えを生成します。
大量のデータ(11616行のデータ)を作成し、Andomarのクエリのベンチマークタイミングを実行しました。ターゲットDBMSは、MacOS X10.7.2で実行されているIBMInformix Dynamic Server(IDS)バージョン11.70.FC2でした。 IDSは2番目のクエリの比較表記をサポートしていないため、Andomarの2つのクエリのうち最初のクエリを使用しました。私はデータをロードし、統計を更新し、私の後にAndomarを使用して、およびAndomarの後に私のものを使用してクエリを実行しました。また、IDSオプティマイザーによって報告された基本コストも記録しました。両方のクエリの結果データは同じでした(したがって、クエリは両方とも正確であるか、等しく不正確です)。
インデックスなしのテーブル:
Andomar's query Jonathan's query
Time: 22.074129 Time: 0.085803
Estimated Cost: 2468070 Estimated Cost: 22673
Estimated # of Rows Returned: 5808 Estimated # of Rows Returned: 132
Temporary Files Required For: Order By Temporary Files Required For: Group By
(名前、メジャー、マイナー、リビジョン)に一意のインデックスがあるテーブル:
Andomar's query Jonathan's query
Time: 0.768309 Time: 0.060380
Estimated Cost: 31754 Estimated Cost: 2329
Estimated # of Rows Returned: 5808 Estimated # of Rows Returned: 139
Temporary Files Required For: Group By
ご覧のとおり、インデックスはAndomarのクエリのパフォーマンスを劇的に向上させますが、それでもこのシステムでは私のクエリよりもコストがかかるようです。インデックスを使用すると、クエリの時間を25%節約できます。インデックスがある場合とない場合の、同等の量のデータに対するAndomarのクエリの2つのバージョンの同等の数値を確認したいと思います。 (私のテストデータは必要に応じて提供できます。132の製品がありました。質問にリストされている3つと129の新しい製品です。各新製品には(同じ)90のバージョンエントリがありました。)
不一致の理由は、Andomarのクエリのサブクエリが相関サブクエリであり、比較的コストのかかるプロセスであるためです(インデックスが欠落している場合は劇的にそうなります)。
not exists
サブクエリを使用して、古いレコードを除外できます。
select *
from YourTable yt
where not exists
(
select *
from YourTable older
where yt.name = older.name and
(
yt.major < older.major or
yt.major = older.major and yt.minor < older.minor or
yt.major = older.major and yt.minor = older.minor and
yt.revision < older.revision
)
)
これはMySQLで次のように書くこともできます:
select *
from YourTable yt
where not exists
(
select *
from YourTable older
where yt.name = older.name and
(yt.major, yt.minor, yt.revision)
< (older.major, older.major, older.revision)
)
SELECT cam.*
FROM
( SELECT DISTINCT name
FROM ca
) AS cadistinct
JOIN
ca AS cam
ON ( cam.name, cam.major, cam.minor, cam.revision )
= ( SELECT name, major, minor, revision
FROM ca
WHERE name = cadistinct.name
ORDER BY major DESC
, minor DESC
, revision DESC
LIMIT 1
)
これはMySQL(現在のバージョン)で機能しますが、お勧めしません:
SELECT *
FROM
( SELECT name, major, minor, revision
FROM ca
ORDER BY name
, major DESC
, minor DESC
, revision DESC
) AS tmp
GROUP BY name
Update3変数group_concat_max_lenの最小値は4であるため、使用できません。でも君ならできる:
select
name,
SUBSTRING_INDEX(group_concat(major order by major desc),',', 1) as major,
SUBSTRING_INDEX(group_concat(minor order by major desc, minor desc),',', 1)as minor,
SUBSTRING_INDEX(group_concat(revision order by major desc, minor desc, revision desc),',', 1) as revision
from your_table
group by name;
これはテスト済みです ここ いいえ、以前のバージョンでは間違った結果は得られず、連結された値の数にのみ問題がありました。
最高のバージョンは最高のリビジョンのものだと思っているのは私だけですか?
そう、
select a.name, a.major, a.minor, a.revision
from table a
where a.revision = (select max(b.revision) from table b where b.name = a.name)
これらの列に数値がある場合は、メジャー、マイナー、リビジョン値に対して一意で適切に順序付けられた、ある種の数式を思い付くことができます。例えば。数値が10未満の場合は、次のように文字列として追加して比較できます。
select name, major, minor, revision,
concat(major, minor, revision) as version
from versions
それらが100を超えない数値である場合は、次のようにすることができます。
select name, major, minor, revision,
(major * 10000 + minor * 100 + revision) as version
from versions
次のように、max
のversion
を名前でグループ化するだけでは不十分です。
select name, major, minor, revision
from (
select name, major, minor, revision,
(major * 10000 + minor * 100 + revision) as version
from versions) v1
where version = (select max (major * 10000 + minor * 100 + revision)
from versions v2
where v1.name = v2.name)
バージョン番号の一部ごとに最大3桁が許可されます。より多くの桁を使用したい場合は、メジャー乗算に2つのゼロを追加し、各桁に1つのゼロからマイナー乗算を追加します(明確であることを願っています)。
select t.*
from yourTable t
join (
select name, max(major * 1000000 + minor * 1000 + revision) as ver
from yourTable
group by name
) t1 on t1.ver = (t.major * 1000000 + t.minor * 1000 + t.revision)
結果:
name major minor revision
p1 1 1 4
p2 2 5 0
p3 3 4 4