SQL / mysql-個別/一意を選択しますが、すべての列を返しますか?


373
SELECT DISTINCT field1, field2, field3, ......   FROM table

次のSQLステートメントを実行しようとしていますが、すべての列を返したいのですが、これは可能ですか?何かのようなもの:

SELECT DISTINCT field1, * from table

12
なぜうまくいかないのSELECT DISTINCT * FROM tableですか?
ypercubeᵀᴹ

19
テーブルにPKがある場合、すべての行は当然のことdistinctです。DISTINCT field1特定のfield1値に対して複数の値を持つ列を選択するだけで、どういうわけか他のすべての列を返す場合はどうなりますか?GROUP BYたとえば、他の列で何らかの集計を使用する必要があります。
マーティン・スミス

1
個別の行だけでなく繰り返しの行が必要な場合は、個別のキーワードを削除します。
Hyperboreus、

2
結果がどのようになると期待できるか、例を挙げていただけますか?これまでのところ、私はあなたが望むクエリを理解することができません。
再帰的

3
これは同様の質問の答えです。まず、IDを持つ個別の列を取得してから、元のテーブルと結合する必要があります。1つの列でSELECT DISTINCTを実行し、他の複数の列を返す
yadavr 2013

回答:


407

次の方法でグループを探しています。

select *
from table
group by field1

これは、時々別個のonステートメントで書くことができます:

select distinct on field1 *
from table

ただし、ほとんどのプラットフォームでは、他の列の動作が指定されていないため、上記のどちらも機能しません。(もしそれがあなたが使っているものならば、最初のものはMySQLで動作します。)

個別のフィールドをフェッチし、毎回1つの任意の行を選択することに固執することができます。

一部のプラットフォーム(PostgreSQL、Oracle、T-SQLなど)では、これはウィンドウ関数を使用して直接実行できます。

select *
from (
   select *,
          row_number() over (partition by field1 order by field2) as row_number
   from table
   ) as rows
where row_number = 1

その他(MySQL、SQLite)では、テーブル全体をそれ自体と結合させるサブクエリを作成する必要があります()ので、お勧めしません。


10
クエリは私のために解析されず、エラーが発生します:The ranking function "row_number" must have an ORDER BY clause。field1によるパーティション化の後に、order by句を追加する必要があります。したがって、正しいクエリは次のようになります select * from ( select *, row_number() over (partition by field1 order by orderbyFieldName) as row_number from table ) as rows where row_number = 1
Ankur-m

1
ありがとう!私も同じ問題を抱えていて、解決策は GROUP BY
Joaquin Iurchuk、2015年

2
また、Oracle(Oracle SQL Developer)では指定できませんselect *, row_number() over (partition by field1 order by field2) as row_number from table。選択クエリで明示的にテーブル名/エイリアスを使用する必要がありますselect **table**.*, row_number() over (partition by field1 order by field2) as row_number from table
meta4

1
@jarlh:今日かもしれない... お気づきかもしれませんが、この回答はほぼ7歳です。私がアクティブだったときに後ろから思い出すことができる限り、そうではありませんでした。必要に応じて、回答のタグを付け直したり編集したりできます。
Denis de Bernardy 2018年

2
select distinct on (field1) * from table; PostgreSQLでも動作します
Chilianu Bogdan

61

質問の言い回しから、特定のフィールドの個別の値を選択し、そのような値ごとに、他のすべての列の値が同じ行にリストされるようにする必要があることを理解しました。ほとんどのDBMSは、結果が決定されていないため、とのどちらDISTINCTも使用しないとこれを許可しませんGROUP BY

次のように考えてください。2 field1回以上発生した場合、どの値field2がリストされます(field12つの行に同じ値があり、2つの行に2つの異なる値がある場合field2)。

ただし、集約関数を使用して(明示的に表示するすべてのフィールドに)、GROUP BY代わりにを使用することもできますDISTINCT

SELECT field1, MAX(field2), COUNT(field3), SUM(field4), .... FROM table GROUP BY field1

4
このソリューションの+1。したがって、私たちはできるのでSELECT field1, MIN(field2), MIN(field3), MIN(field4), .... FROM table GROUP BY field1、field2、3、4、は整数(または他の数字)である必要はありません。charフィールドにすることもできます
stalk

私がブール列で動けなくなるまでうまく機能していました。MIN(動的)列の値は、trueであってもfalseに変更されます。ブール値に対処するために使用できる他の集計関数– signonsridharは6分前です。Sum(動的)はfalseを1に変更しました
signonsridhar

1
素晴らしい提案、私はより普遍的だと思う私の解決策に私を導きました-見てください!
Garrett Simpson

@signonsridharはブール値をintにキャストし、合計を使用します。例sum(cast(COL as int)) > 0
ドリュー

26

私があなたの問題を正しく理解していれば、それは私が今持っていた問題に似ています。DISTINCTの使いやすさをすべてのデータに適用するのではなく、指定したフィールドに制限できるようにしたい。

集計関数なしでGROUP BYを使用する場合、GROUP BYのどのフィールドがDISTINCTフィールドになります。

クエリを行う場合:

SELECT * from table GROUP BY field1;

field1の単一インスタンスに基づいてすべての結果が表示されます。

たとえば、名前、住所、市区町村の表があるとします。1人のユーザーに複数の住所が記録されていますが、その人の1つの住所だけが必要な場合は、次のようにクエリできます。

SELECT * FROM persons GROUP BY name;

その結果、その名前の1つのインスタンスのみがアドレスとともに表示され、もう1つのインスタンスは結果のテーブルから省略されます。注意:フィールドにfirstName、lastNameなどのアトミック値がある場合、両方でグループ化します。

SELECT * FROM persons GROUP BY lastName, firstName;

なぜなら、2人の姓が同じで、lastNameだけでグループ化した場合、そのうちの1人が結果から除外されるからです。それらを考慮に入れる必要があります。お役に立てれば。


受け入れられた回答で述べられているように、ほとんどのSQLの化身で動作します-MYSQLでのみ
Garrett Simpson

15
SELECT  c2.field1 ,
        field2
FROM    (SELECT DISTINCT
                field1
         FROM   dbo.TABLE AS C
        ) AS c1
        JOIN dbo.TABLE AS c2 ON c1.field1 = c2.field1

C aliasそれがなくても機能するのはなぜですか?インラインFROM dbo.TABLE AS C
Talha

2
これは私のRedGate SQLPromptの使用によるものだと思います。私がそれを構成している方法では、それは常に-不要であっても-エイリアスを追加します。「
Stormy

これは私にとっては有望に見えましたが、それでも明確なフィールドではなく、すべての行が返されました1。:(
マイケルフィーバー

13

それは本当に良い質問です。私はすでにここでいくつかの役立つ回答を読みましたが、おそらくもっと正確な説明を追加できます。

GROUP BYステートメントを使用してクエリ結果の数を減らすのは、追加の情報をクエリしない限り簡単です。次のテーブル「場所」があると仮定します。

--country-- --city--
 France      Lyon
 Poland      Krakow
 France      Paris
 France      Marseille
 Italy       Milano

今クエリ

SELECT country FROM locations
GROUP BY country

結果は:

--country--
 France
 Poland
 Italy

ただし、次のクエリ

SELECT country, city FROM locations
GROUP BY country

... MS SQLでエラーをスローします。コンピュータがフランスの3つの都市「リヨン」、「パリ」、「マルセイユ」のどれを「フランス」の右側のフィールドで読みたいのかをどのようにして知ることができるのでしょうか。

2番目のクエリを修正するには、この情報を追加する必要があります。これを行う1つの方法は、関数MAX()またはMIN()を使用して、すべての候補の中から最大値または最小値を選択することです。MAX()およびMIN()は数値に適用できるだけでなく、文字列値のアルファベット順を比較することもできます。

SELECT country, MAX(city) FROM locations
GROUP BY country

結果は:

--country-- --city--
 France      Paris
 Poland      Krakow
 Italy       Milano

または:

SELECT country, MIN(city) FROM locations
GROUP BY country

結果は:

--country-- --city--
 France      Lyon
 Poland      Krakow
 Italy       Milano

これらの関数は、アルファベット順(または数値順)の両端から値を選択することに問題がない限り、適切なソリューションです。しかし、そうでない場合はどうでしょうか?たとえば、文字「M」で始まる特定の特性を持つ値が必要であると仮定します。今、物事は複雑になります。

これまでに見つけた唯一の解決策は、クエリ全体をサブクエリに入れ、その外に手動で追加の列を作成することです。

SELECT
     countrylist.*,
     (SELECT TOP 1 city
     FROM locations
     WHERE
          country = countrylist.country
          AND city like 'M%'
     )
FROM
(SELECT country FROM locations
GROUP BY country) countrylist

結果は:

--country-- --city--
 France      Marseille
 Poland      NULL
 Italy       Milano

5

素晴らしい質問@aryaxt-5年前に質問したので、答えを見つけようとして今日つまずいたので、素晴らしい質問だったと言えます。

私はこれを含めるために受け入れられた回答を編集しようとしましたが、私の編集がそれを行わない場合に備えて:

テーブルがそれほど大きくなく、主キーが自動インクリメントの整数であると想定すると、次のようになります。

SELECT 
  table.*
FROM table
--be able to take out dupes later
LEFT JOIN (
  SELECT field, MAX(id) as id
  FROM table
  GROUP BY field
) as noDupes on noDupes.id = table.id
WHERE
  //this will result in only the last instance being seen
  noDupes.id is not NULL


3

WITH句でそれを行うことができます。

例えば:

WITH c AS (SELECT DISTINCT a, b, c FROM tableName)
SELECT * FROM tableName r, c WHERE c.rowid=r.rowid AND c.a=r.a AND c.b=r.b AND c.c=r.c

これにより、WITH句クエリで選択された行のみを選択することもできます。


2

SQL Serverの場合は、dense_rankおよび追加のウィンドウ関数を使用して、指定された列に重複する値を持つすべての行と列を取得できます。ここに例があります...

with t as (
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r1' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r2' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r3' union all
    select col1 = 'a', col2 = 'b', col3 = 'c', other = 'r4' union all
    select col1 = 'c', col2 = 'b', col3 = 'a', other = 'r5' union all
    select col1 = 'a', col2 = 'a', col3 = 'a', other = 'r6'
), tdr as (
    select 
        *, 
        total_dr_rows = count(*) over(partition by dr)
    from (
        select 
            *, 
            dr = dense_rank() over(order by col1, col2, col3),
            dr_rn = row_number() over(partition by col1, col2, col3 order by other)
        from 
            t
    ) x
)

select * from tdr where total_dr_rows > 1

これは、col1、col2、およびcol3の個別の組み合わせごとに行カウントを取ります。


複雑すぎてSQLの1つの実装に固有
Garrett Simpson

1
select min(table.id), table.column1
from table 
group by table.column1

これは私のために働いた!! これは注目に値します。fetch_array()を使用している場合は、行名を暗黙的に呼び出すのではなく、インデックスラベルを介して各行を呼び出す必要があります。これには私が持っている例を書くのに十分な文字がありません:Xごめんなさい
Brandon Printiss

0
SELECT *
FROM tblname
GROUP BY duplicate_values
ORDER BY ex.VISITED_ON DESC
LIMIT 0 , 30

ORDER BY、私はちょうどここに例を入れている、あなたも、この中にIDフィールドを追加することができます


受け入れられた回答で述べたように、SQLのほとんどの化身で機能します
Garrett Simpson

0

これはここの他の場所で見つかりましたが、これは機能する単純なソリューションです:

 WITH cte AS /* Declaring a new table named 'cte' to be a clone of your table */
 (SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY val1 DESC) AS rn
 FROM MyTable /* Selecting only unique values based on the "id" field */
 )
 SELECT * /* Here you can specify several columns to retrieve */
 FROM cte
 WHERE rn = 1

MSSQLに対応
Michael Fever

-1

クエリが次のようになる可能性がある重複をチェックするフィールドにGROUP BYを追加します

SELECT field1, field2, field3, ......   FROM table GROUP BY field1

field1は重複レコードを除外するためにチェックされます

またはあなたは

SELECT *  FROM table GROUP BY field1

field1の重複レコードはSELECTから除外されます


1
GROUP BY句は、選択したフィールドと一致する必要があります。それ以外の場合、次のようなエラーがスローされますfiled2 must appear in the GROUP BY clause or be used in an aggregate function
Viuu -a

-2

GROUP BY句にすべてのフィールドを含めるだけです。


3
これを適切な回答にするには、あなたが何を意味するかについてもう少し詳細を含める必要があります。
Robbert 2013年

-2

内部クエリで実行できます

$query = "SELECT * 
            FROM (SELECT field
                FROM table
                ORDER BY id DESC) as rows               
            GROUP BY field";

2
これは質問の答えにはなりません。OPはテーブルのすべてのデータを取得しようとしましたが、単一のフィールドの重複を含む行を削除しようとしました
Garrett Simpson

-3
SELECT * from table where field in (SELECT distinct field from table)

7
それは仕事をしません。サブクエリで個別の列を選択しましたが、where句はその値を持つすべての列を取得します。したがって、「フィールド」列が一意の列である場合を除いて、クエリは「select * from table」と書くのと同じです。その場合、その列の一意性はまったく必要ありません。
Ankur-m

-3

SELECT DISTINCT FIELD1、FIELD2、FIELD3 FROM TABLE1は、3つの列すべての値がテーブル内で一意である場合に機能します。

たとえば、名に同じ値が複数あるが、選択した列の姓とその他の情報が異なる場合、レコードは結果セットに含まれます。


2
これは質問の答えにはなりません。OPはテーブルのすべてのデータを取得しようとしましたが、単一のフィールドの重複を含む行を削除しようとしました
Garrett Simpson

-3

私は使用をお勧めします

SELECT  * from table where field1 in 
(
  select distinct field1 from table
)

このように、複数の行にわたってfield1に同じ値がある場合、すべてのレコードが返されます。


1
と違いはありませんSELECT * FROM table;。さらに遅いです。
新キム

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