web-dev-qa-db-ja.com

SQL/mysql - distinct/UNIQUEを選択し、すべての列を返す

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

次のSQL文を実行しようとしていますが、すべての列を返すようにしたいのですが、これは可能ですか。何かのようなもの:

SELECT DISTINCT field1, * from table
332
aryaxt

あなたはグループを探しています:

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)では、テーブル全体をそれ自身で結合するようにするサブクエリを書く必要があるでしょう( example )、従ってお勧めできません。

371

あなたの質問の言い回しから、私はあなたが与えられたフィールドとそのようなそれぞれの値に対して別々の値を選択して同じ行の他の全ての列の値をリストしたいということを理解しています。結果が決定されていないため、ほとんどのDBMSはDISTINCTGROUP BYのどちらでもこれを許可しません。

このように考えてください:あなたのfield1が2回以上現れると、field2のどの値がリストされるか(あなたが2つの行でfield1の同じ値を持つが、それらの2つの行でfield2の2つの異なる値を持つ)。

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

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

私があなたの問題を正しく理解したならば、それは私が今持っていたものに似ています。すべてのデータに適用するのではなく、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人は結果から除外されます。あなたはそれらのことを考慮に入れる必要があります。お役に立てれば。

20
rocklandcitizen
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
12
Stormy

それは本当に良い質問です。私はすでにここでいくつかの役に立つ答えを読んだことがありますが、おそらくもっと正確な説明を加えることができます。

追加情報を照会しない限り、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つのフランスの都市 "Lyon"、 "Paris"、または "Marseille"のうちどれが "France"の右側にあるフィールドを読みたいのですか。

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
6
Ulf Sanne

素晴らしい質問@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
Garrett Simpson

あなたはそれを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
user2225399

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の個別の組み合わせごとに行数を取ります。

1
dotjoe

試します

SELECT table.* FROM table 
WHERE otherField = 'otherValue'
GROUP BY table.fieldWantedToBeDistinct
limit x
1
Pedro Ramos
SELECT *
FROM tblname
GROUP BY duplicate_values
ORDER BY ex.VISITED_ON DESC
LIMIT 0 , 30

ORDER BYでは、ここに例を挙げましたが、これにIDフィールドを追加することもできます。

0
SagarPPanchal