列の一意の値ごとに最初の行のみを選択する方法


96

顧客の住所の表があるとします。

CName           |   AddressLine
-------------------------------
John Smith      | 123 Nowheresville
Jane Doe        | 456 Evergreen Terrace
John Smith      | 999 Somewhereelse
Joe Bloggs      | 1 Second Ave

テーブルでは、John Smithのような1人の顧客が複数の住所を持つことができます。'CName'に重複がある最初の行のみを返すには、このテーブルの選択クエリが必要です。このテーブルでは、3番目を除くすべての行を返す必要があります(または1番目-これらの2つのアドレスのいずれでも問題ありませんが、返されるのは1つだけです)。SELECTクエリに追加して、サーバーが以前に列の値を見たことがあるかどうかに基づいてフィルタリングできるキーワードはありますか?

回答:


125

どのアドレスが使用されてもかまわないと言った場合の非常に単純な答え。

SELECT
    CName, MIN(AddressLine)
FROM
    MyTable
GROUP BY
    CName

たとえば、「挿入された」列に従って最初の列が必要な場合、それは別のクエリです

SELECT
    M.CName, M.AddressLine,
FROM
    (
    SELECT
        CName, MIN(Inserted) AS First
    FROM
        MyTable
    GROUP BY
        CName
    ) foo
    JOIN
    MyTable M ON foo.CName = M.CName AND foo.First = M.Inserted

ただし、10列を選択するときにこのように使用することは意図されていません。また、ビット型の列は受け付けられないようです。
nuit9

1
@ nuit9:もちろん、ビットと10列では機能しません。これらの事実のどちらもあなたの質問にはありません。2番目のテクニックまたはベントゥールのテクニックを使用します。より一般的な解決方法の指針を示して、具体的に質問した内容に回答しました。
GBN、2011年

最初の部分は複数の列で機能しますが、ビット型の列では機能しません。私はこれをMS SQLサーバー2016でテストしました。
18

24

SQL 2k5 +では、次のようなことができます。

;with cte as (
  select CName, AddressLine,
  rank() over (partition by CName order by AddressLine) as [r]
  from MyTable
)
select CName, AddressLine
from cte
where [r] = 1

5
ランク、パーティション、および[r]の機能について説明してください
Roberto

10

row_number()行の行番号を取得するために使用できます。overコマンドを使用しpartition byます。句は番号付けを再開するタイミングを指定しorder by、行番号の順序を選択します。order byクエリの最後にを追加した場合でもover、番号付け時にコマンドの順序が保持されます。

select *
from mytable
where row_number() over(partition by Name order by AddressLine) = 1

6
postgresqlでは、ウィンドウ関数はWHERE句で使用できません
ekanna

3
これはMS-SQLでは許可されていません。
Mixxiphoid

1
ROW_NUMBER()WhereTeradataの条項でも機能しない
Pirate X

6

次のrow_numer() over(partition by ...)ような構文を使用できます。

select * from
(
select *
, ROW_NUMBER() OVER(PARTITION BY CName ORDER BY AddressLine) AS row
from myTable
) as a
where row = 1

これにより、という列が作成されます。rowこれは、同じ列が表示されるたびに増分するカウンターであり、CNameそれらの発生をでインデックス付けしますAddressLine。課すことによってwhere row = 1、一つは選択することができCName、そのAddressLineアルファベット順で最初に来るし。場合order byだったdesc、それは選ぶだろうCNameそのはAddressLineアルファベット順で最後になります。


1

これにより、重複する行ごとに1行が表示されます。また、ビット型の列が表示され、少なくともMS SQLサーバーで機能します。

(select cname, address 
from (
  select cname,address, rn=row_number() over (partition by cname order by cname) 
  from customeraddresses  
) x 
where rn = 1) order by cname

代わりにすべての重複を見つけたい場合は、rn = 1をrn> 1に変更してください。これが役立つことを願っています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.