1列のみのDISTINCT


155

次のクエリがあるとします。

SELECT ID, Email, ProductName, ProductModel FROM Products

重複したメールを返さないように変更するにはどうすればよいですか?

つまり、複数の行に同じ電子メールが含まれている場合、結果にはそれらの行の1つ(できれば最後の行)のみが含まれるようにします。他の列での重複は許可されるべきです。

のような句は、行全体で機能するようDISTINCTGROUP BY見えます。だから私はこれにどのように取り組むかわかりません。


2
OK、PARTITIONを使用するか、2つのselectステートメントを使用する必要がありますか?
CarneyCode、2011

また、同じメールアドレスでProductNameが異なる2つの行がある場合、何を表示する必要がありますか?(好ましくは最後のものは)明確ではありません。最後にどの順序で?
ypercubeᵀᴹ

@ypercube質問で述べたように、できれば最後のもの。しかし、それは私にとって本当に重要ではありません。そのうちの1つが欲しいだけです。
ジョナサンウッド

1
次の質問を見ることができます:question1question2またはquestion3
マリアン

なぜ使用できないのですか?SELECT DISTINCT Email、ID、ProductName、ProductModel FROM Products?
リックヘンダーソン

回答:


186

SQL Server 2005以降を使用している場合は、次のようにします。

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
              ) a
WHERE rn = 1

編集:where句を使用した例:

SELECT *
  FROM (
                SELECT  ID, 
                        Email, 
                        ProductName, 
                        ProductModel,
                        ROW_NUMBER() OVER(PARTITION BY Email ORDER BY ID DESC) rn
                    FROM Products
                   WHERE ProductModel = 2
                     AND ProductName LIKE 'CYBER%'

              ) a
WHERE rn = 1

4
私はこのPARTITION句を調査する必要があります。例をお
寄せ

@Cyber​​nate 1つの複雑化:私の内部SELECTにはWHERE条件が必要です。テーブルのすべての行に行番号が割り当てられると思います。この構文は私を少し超えています。WHERE条件を満たす特定の電子メールの1つの行を保証する更新の可能性はありますか?
ジョナサンウッド

1
内部SQLにwhere句を追加できます。ラップトップにアクセスできるようになりましたら、投稿を更新します
Chandu

1
where句を使用したサンプルで投稿を更新しました。
チャンドゥ

1
クエリにが含まれていない 場合にのみ、これが正しく機能しJOINます。すぐに私が持っているようにJOINROW_NUMBER戻り「1」よりもはるかに高い値。
Uwe Keim

10

これはSQL Server 2005+を想定しており、「最終」の定義は特定の電子メールの最大PKです。

WITH CTE AS
(
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel, 
       ROW_NUMBER() OVER (PARTITION BY Email ORDER BY ID DESC) AS RowNumber 
FROM   Products
)
SELECT ID, 
       Email, 
       ProductName, 
       ProductModel
FROM CTE 
WHERE RowNumber = 1

6

使用するときはDISTINCT、列ではなく、個別の行として考えてください。列が完全に一致しない行のみを返します。

SELECT DISTINCT ID, Email, ProductName, ProductModel
FROM Products

----------------------
1 | something@something.com | ProductName1 | ProductModel1
2 | something@something.com | ProductName1 | ProductModel1

ID列が異なるため、クエリは両方の行を返します。私は列が増加しているID列であることを想定していIDENTITYます、あなたが最後を返したいなら、私はこのようなものをお勧めします:

SELECT DISTINCT TOP 1 ID, Email, ProductName, ProductModel
FROM Products
ORDER BY ID DESC

TOP 1で、それを注文して、最初のレコードだけを返します。IDそれが最初の最後の行に結果を返します降順。これにより、最後のレコードが得られます。


2
質問で述べたように、DISTINCTは行全体で機能することがわかります。上記で提案したようにしたいのですが、メールが結果に複製されるたびに(一度だけではありません)。
ジョナサンウッド

その場合、@ Cyber​​nateの回答を使用することをお勧めします。それはあなたが必要としていることを正確に行うはずです。
jon3laze、2011

4

あなたはGROUP BY関数を使用してそれを克服できます

SELECT ID, Email, ProductName, ProductModel FROM Products GROUP BY Email


16
列 'Products.ID'は、集約関数にもGROUP BY句にも含まれていないため、選択リストでは無効です。
palota

2
これは、他の列にMAX(ID)、MAX(ProductName)、MAX(ProductModel)などを使用しないと機能しません
avl_sweden

2
postgresでは、group by句で使用される列の集約関数のみが必要です(例:)SELECT id, max(email) AS email FROM tbl GROUP by email。SQLサーバーでは、SELECT句のすべての列が集計関数に含まれている必要があります。これは戻るたびに私を噛みます。
Bruce Pierson、2018

これは機能しません。それは悪い解決策です
Dan AS

1

Accessの場合、ここに示すSQL Selectクエリを使用できます。

たとえば、次のテーブルがあるとします。

クライアント|| NOMBRES || 郵便物

888 || T800アーノルド|| t800.arnold@cyberdyne.com

123 || ジョン・コナー|| s.connor@skynet.com

125 || SARAH CONNOR ||s.connor@skynet.com

また、個別のメールのみを選択する必要があります。あなたはこれでそれを行うことができます:

SQL SELECT:

SELECT MAX(p.CLIENTE) AS ID_CLIENTE
, (SELECT TOP 1 x.NOMBRES 
    FROM Rep_Pre_Ene_MUESTRA AS x 
    WHERE x.MAIL=p.MAIL 
     AND x.CLIENTE=(SELECT MAX(l.CLIENTE) FROM Rep_Pre_Ene_MUESTRA AS l WHERE x.MAIL=l.MAIL)) AS NOMBRE, 
p.MAIL
FROM Rep_Pre_Ene_MUESTRA AS p
GROUP BY p.MAIL;

これを使用して、最大ID、その最大IDに対応する名前を選択できます。この方法で他の属性を追加できます。次に、最後に個別の列をフィルターにかけ、最後の個別の列でのみグループ化します。

これにより、対応するデータの最大IDが取得されます。minまたはその他の関数を使用して、その関数をサブクエリに複製できます。

この選択は戻ります:

クライアント|| NOMBRES || 郵便物

888 || T800アーノルド|| t800.arnold@cyberdyne.com

125 || SARAH CONNOR ||s.connor@skynet.com

選択した列にインデックスを付けることを忘れないでください。個別の列にはすべて大文字または小文字の数値データが含まれていない必要があります。そうしないと機能しません。これは、1つの登録済みメールでも機能します。ハッピーコーディング!!!


0

行全体に対する理由DISTINCTGROUP BY作業は、クエリが行全体を返すためです。

理解を助けるために:クエリが返すものを手動で書き出そうとすると、重複していない列に何を配置するかが曖昧であることがわかります。

他の列の内容が文字通り問題にならない場合は、それらを返さないでください。電子メールアドレスごとにランダムな行を返すことは、私には少し役に立たないようです。


@JohnFix行全体を返したい。結果にすでに[Email]列に同じ値の行が含まれている場合、行が返されないようにしたいだけです。
ジョナサンウッド

それで、どれを返すかをどのように決定すべきですか?電子メールごとに任意の行を返すクエリが本当に必要ですか。これは本当に、解決しようとしている問題を再考する必要があるかもしれないようなにおいがします。ほとんど私がこの質問をされるたびに(そしてそれはたくさん出てきます)、開発者がこの動作のアプリでの結果を考慮していないことがわかります。
JohnFx、2011

6
私はあなたの論理に従うのに本当に苦労しています。質問で述べたように、私は最後のもの(IDでソート)を好みます。はい、ランダムな行を選択した場合は問題ありません。そして、はい、私はそれについて考えました。
ジョナサンウッド

0

これを試して

;With Tab AS (SELECT DISTINCT Email FROM  Products)
SELECT Email,ROW_NUMBER() OVER(ORDER BY Email ASC) AS  Id FROM Tab
ORDER BY Email ASC

-2

これを試して:

SELECT ID, Email, ProductName, ProductModel FROM Products WHERE ID IN (SELECT MAX(ID) FROM Products GROUP BY Email)

2
なぜこれを試すべきなのか?これが過去8年間にここに投稿された他の回答よりも優れているのはなぜですか?問題を解決するより良い方法を共有したい場合は、それを推奨する理由を説明する必要があります。
ダーマン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.