web-dev-qa-db-ja.com

サブクエリを使用せずに最大シーケンスの行のみを選択する方法は?

各IDのシーケンスが最も高い行のみを選択しようとしています

ID  |  Seq   |  Age
-------------------
 A      1       20   
 A      2       30
 B      1       25
 B      2       32
 B      3       44
 B      4       48
 C      1       11

これは機能しているようです

SELECT ID, Age
FROM Persons a
WHERE Seq = (SELECT MAX(Seq) FROM Persons b WHERE a.ID = b.ID)

しかし、これが最善の方法であり、唯一の方法ですか?必要がなければサブクエリを使用するのは好きではありません。何かを使用できることを思い出しますが、それが何であるかを忘れています。何か案が?

10
jenswirf

SQL-Server(> = 2005)またはOracle(10g?)を想定:

WITH CTE AS
( 
   SELECT
       ROW_NUMBER() OVER (PARTITION BY ID  ORDER BY Seq DESC) AS RN
       , ID, Age
   FROM 
       Persons
)
SELECT ID, Age 
FROM CTE
WHERE RN = 1

ROW_NUMBER 結果セットのパーティション内の行の連番を返します。

編集:ここに表示されているようにOracleでも機能します: http://sqlfiddle.com/#!4/b7e79/2/

6
Tim Schmelter

一般に、ウィンドウ関数またはランク付け関数(Rank()Row_number()など)を使用する必要があります。

select *
from
(
    select *, row_number() over (partition by id order by age desc) rn
    from yourtable
) v
where rn = 1

これはSQLServer 2005+で機能します。Oracleでは、*の代わりにフィールド名を明示的に指定する必要がある場合があります。

1
podiluska

ウィンドウ関数をサポートしないRDBMSを使用する場合に備えて、次のものを使用できます。

SELECT  Persons.ID, Persons.Age, Persons.Seq
FROM    Persons
        INNER JOIN
        (   SELECT  Persons.ID, MAX(Seq) AS Seq
            FROM    Persons
            GROUP BY Persons.ID
        ) MaxP
            ON MaxP.ID = Persons.ID
            AND MaxP.Seq = Persons.Seq

それでもサブクエリが含まれますが、サブクエリなしでこれを行う方法はわかりません。また、サブクエリを避けたい理由もわかりません。

1
GarethD