SQLで一意のレコードを選択する方法


87

「SELECT * FROM table」を実行すると、次のような結果が得られました。

1 item1 data1
2 item1 data2
3 item2 data3
4 item3 data4

ご覧のとおり、column2からの重複レコードがあります(item1は重複しています)。では、どうすれば次のような結果を得ることができますか?

1 item1 data1
2 item2 data3
3 item3 data4

重複から返されるレコードは1つだけで、残りの一意のレコードも返されます。


アイテム1は技術的に複製されていません。示されているように、行1と2は固有の観測値です。行1ではなく行2を保持したい場合はどうなりますか?
サイバネティック

回答:


105

distinct単一および複数の列名を持つキーワードを使用すると、個別のレコードを取得できます。

SELECT DISTINCT column 1, column 2, ...
FROM table_name;

14
答えが実際に間違っているということでしょうか?DISTINCTは、選択されたすべての列(少なくともDB2)に適用されますが、それでも個々の列に重複する値が返されます。
コンスタンチン

26

重複を削除するだけでよい場合は、を使用してくださいDISTINCTGROUP BY各グループに集計演算子を適用するために使用する必要があります

GROUP BY v DISTINCT


11

それはあなたがそれぞれのユニークなアイテムのためにどの列を返したいかによります。あなたのデータは最小データ値を示しているようですので、この場合はSQLServerです。

SELECT item, min(data)
FROM  table
GROUP BY item

10

使用できる方法は4つあります。

  1. DISTINCT
  2. GROUP BY
  3. サブクエリ
  4. ROW_NUMBER()を使用した共通テーブル式(CTE)

TABLEテストデータを含む次のサンプルについて考えてみます。

/** Create test table */
CREATE TEMPORARY TABLE dupes(word text, num int, id int);

/** Add test data with duplicates */
INSERT INTO dupes(word, num, id)
VALUES ('aaa', 100, 1)
      ,('bbb', 200, 2)
      ,('ccc', 300, 3)
      ,('bbb', 400, 4)
      ,('bbb', 200, 5)     -- duplicate
      ,('ccc', 300, 6)     -- duplicate
      ,('ddd', 400, 7)
      ,('bbb', 400, 8)     -- duplicate
      ,('aaa', 100, 9)     -- duplicate
      ,('ccc', 300, 10);   -- duplicate

オプション1:SELECT DISTINCT

これは最も単純で簡単ですが、最も制限された方法でもあります。

SELECT DISTINCT word, num 
FROM    dupes
ORDER BY word, num;

/*
word|num|
----|---|
aaa |100|
bbb |200|
bbb |400|
ccc |300|
ddd |400|
*/

オプション2:GROUP BY

グループは次のように、あなたが集計されたデータを追加することができますmin(id)max(id)count(*)、など:

SELECT  word, num, min(id), max(id), count(*)
FROM    dupes
GROUP BY word, num
ORDER BY word, num;

/*
word|num|min|max|count|
----|---|---|---|-----|
aaa |100|  1|  9|    2|
bbb |200|  2|  5|    2|
bbb |400|  4|  8|    2|
ccc |300|  3| 10|    3|
ddd |400|  7|  7|    1|
*/

オプション3:サブクエリ

サブクエリを使用すると、最初に無視する重複行を特定してから、次のWHERE NOT IN (subquery)構成を使用して外部クエリでそれらを除外できます。

/** Find the higher id values of duplicates, distinct only added for clarity */
    SELECT  distinct d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id

/*
id|
--|
 5|
 6|
 8|
 9|
10|
*/

/** Use the previous query in a subquery to exclude the dupliates with higher id values */
SELECT  *
FROM    dupes
WHERE   id NOT IN (
    SELECT  d2.id
    FROM    dupes d1
        INNER JOIN dupes d2 ON d2.word=d1.word AND d2.num=d1.num
    WHERE d2.id > d1.id
)
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

オプション4:ROW_NUMBER()を使用した共通テーブル式

Common Table Expression(CTE)で、ROW_NUMBER()を選択し、グループ列でパーティション化して、目的の順序で並べ替えます。次に、次のレコードのみを選択しますROW_NUMBER() = 1

WITH CTE AS (
    SELECT  *
           ,row_number() OVER(PARTITION BY word, num ORDER BY id) AS row_num
    FROM    dupes
)
SELECT  word, num, id 
FROM    cte
WHERE   row_num = 1
ORDER BY word, num;

/*
word|num|id|
----|---|--|
aaa |100| 1|
bbb |200| 2|
bbb |400| 4|
ccc |300| 3|
ddd |400| 7|
*/

6

group byは、集計関数にも含まれていないという複数の列では機能しないため、内部結合を使用するだけです。

SELECT a.*
FROM yourtable a
INNER JOIN 
  (SELECT yourcolumn,
    MIN(id) as id
  FROM yourtable 
  GROUP BY yourcolumn
) AS b
  ON a.yourcolumn= b.yourcolumn
  AND a.id = b.id;

それはおそらく、でタグ付けされなければならない一つの異なる質問への答えであるグループごとの最大-N-
a_horse_with_no_name

これとDaveBakerの解決策は、SOの質問に対する正しい解決策です。このソリューションの利点は、いくつかの指定された個別の列のみを持つ行を選択でき、複数の指定された列の1つのみを選択するために1つの列MIN(id)ASidを定義する必要があることです。
ジョルダーノ


1

結果のすべての列を取得するには、次のように配置する必要があります。

SELECT distinct a, Table.* FROM Table

最初の列としてを配置、残りは定義と同じ順序ですべての列になります。つまり、列aが繰り返されます。


1
あなたはこれについて確信を持っていますか?私はこれをw3schoolsで試しましたが、最初の列が最初の列であったことを除いて、SELECT *と同じように返されました
気紛れに2015

@Freakishlyはい、それはまさに私の答えでそれが行うと言っていることです:/
htafoya 2015

これは機能しません。そのような区別の後に*を選択することはできません(1064エラーが発生します
-SQL

@Mohsinkhanよく私はあなたがテーブル名を書く必要があることを置くのを忘れました。どういうわけか私がこれを書いたときそれはうまくいきました、しかし私は今テストしました、そしてそれは*の前にテーブル名なしではありませんでした
htafoya 2017年

2
これは、select distinct * from ...
a_horse_with_no_name 2017年

-4

Select Eff_st from(select EFF_ST、ROW_NUMBER()over(PARTITION BY eff_st)XYZ-from ABC.CODE_DIM

)ここで、XYZ = 1の順序でEFF_STを使用すると、最初の5行のみがフェッチされます。

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