sql >> データベース >  >> RDS >> PostgreSQL

PostgresDISTINCTとDISTINCTONの違いは何ですか?

    DISTINCTとDISTINCTONのセマンティクスは完全に異なります。

    最初の理論

    DISTINCTはタプル全体に適用されます。クエリの結果が計算されると、DISTINCTは重複するタプルを結果から削除します。

    たとえば、次の内容のテーブルRを想定します。

    #table r;
    a | b 
    ---+---
    1 | a
    2 | b
    3 | c
    3 | d
    2 | e
    1 | a
    

    (6行)

    Rとは異なる*を選択すると、次のようになります。

    # select distinct * from r;
     a | b 
    ---+---
     1 | a
     3 | d
     2 | e
     2 | b
     3 | c
    (5 rows)
    

    明確なものは、投影された属性のリスト全体に適用されることに注意してください。したがって、

    select distinct * from R
    

    意味的には

    と同等です
    select distinct a,b from R
    

    発行できません

    select a, distinct b From R
    

    DISTINCTはSELECTの後に続く必要があります。結果の属性ではなく、タプル全体に適用されます。

    DISTINCT ON 言語へのpostgresqlの追加です。 group byと似ていますが、同一ではありません。

    その構文は次のとおりです。

     SELECT DISTINCT ON (attributeList) <rest as any query>
    

    例:

     SELECT DISTINCT ON (a) * from R
    

    そのセマンティクスは次のように説明できます。 DISTINCT ON(a)を使用せずに、通常どおりクエリを計算しますが、結果を投影する前に、現在の結果を並べ替え、DISTINCT ONの属性リストに従ってグループ化します(group byと同様)。次に、各グループの最初のタプルを使用して投影を行い、他のタプルを無視します。

    例:

    select distinct * from r order by a;
         a | b 
        ---+---
         1 | a
         2 | e
         2 | b
         3 | c
         3 | d
        (5 rows)
    

    次に、aの異なる値ごとに、最初のタプルを取得します。これは次と同じです:

     SELECT DISTINCT on (a) * from r;
      a | b 
     ---+---
     1 | a
     2 | b
     3 | c
     (3 rows)
    

    一部のDBMS(特にsqlite)では、このクエリを実行できます:

     SELECT a,b from R group by a;
    

    そして、これはあなたに同様の結果を与えます。

    Postgresqlは、aからbへの機能依存性がある場合にのみ、このクエリを許可します。つまり、このクエリは、リレーションRのインスタンスについて、値またはaごとに一意のタプルが1つしかない場合に有効になります(したがって、最初のタプルの選択は決定論的です。タプルは1つだけです)。

    たとえば、Rの主キーがaの場合、a-> bおよび:

    SELECT a, b FROM R group by a
    

    と同じです:

      SELECT DISTINCT on (a) a, b from r;
    

    さて、問題に戻りましょう:

    最初のクエリ:

    SELECT DISTINCT count(dimension1)
    FROM data_table;
    

    ディメンション1の数(dimension1がnullではないdata_table内のタプルの数)を計算します。このクエリは、常に一意である1つのタプルを返します(したがって、DISTINCTは冗長です)。

    クエリ2:

    SELECT count(*)
    FROM (SELECT DISTINCT ON (dimension1) dimension1
    FROM data_table
    GROUP BY dimension1) AS tmp_table;
    

    これはクエリ内のクエリです。わかりやすくするために書き直します:

    WITH tmp_table AS (
       SELECT DISTINCT ON (dimension1) 
         dimension1 FROM data_table
         GROUP by dimension1) 
    SELECT count(*) from tmp_table
    

    最初のtmp_tableを計算してみましょう。上で述べたように、最初にDISTINCT ONを無視し、残りのクエリを実行しましょう。これは、dimension1によるグループ化です。したがって、クエリのこの部分は、dimension1の異なる値ごとに1つのタプルになります。

    さて、DISTINCTON。再びdimension1を使用します。ただし、dimension1はすでに一意です(group byのため)。したがって、これによりDISTINCT ONがsuperflouosになります(何もしません)。最終的なカウントは、グループ内のすべてのタプルのカウントです。

    ご覧のとおり、次のクエリには同等性があります(属性aを持つすべての関係に適用されます):

    SELECT (DISTINCT ON a) a
    FROM R
    

    および

    SELECT a FROM R group by a
    

    および

    SELECT DISTINCT a FROM R
    

    警告

    クエリでDISTINCTONの結果を使用すると、データベースの特定のインスタンスに対して非決定論的である可能性があります。つまり、クエリが同じテーブルに対して異なる結果を返す可能性があります。

    1つの興味深い側面

    DistinctONは悪いをエミュレートします はるかにクリーンな方法でのsqliteの動作。 Rには2つの属性aとbがあると仮定します:

    SELECT a, b FROM R group by a
    

    SQLの不正なステートメントです。それでも、それはsqliteで実行されます。 aの同じ値のグループ内のタプルのいずれかからbのランダムな値を取得するだけです。Postgresqlでは、このステートメントは無効です。代わりに、DISTINCT ONを使用して、次のように記述する必要があります。

    SELECT DISTINCT ON (a) a,b from R
    

    結果

    DISTINCT ONは、groupby属性に機能的に依存する値にアクセスする場合にgroupbyで役立ちます。つまり、属性のグループごとに3番目の属性の値が常に同じであることがわかっている場合は、その属性のグループでDISTINCTを使用します。それ以外の場合は、その3番目の属性を取得するためにJOINを作成する必要があります。



    1. 最大のhas_manyリレーションのみで結合し、そのリレーションに選択フィルターを含むクエリをRuby on Railsで構築するにはどうすればよいですか?

    2. nullも許可する一意の制約を作成するにはどうすればよいですか?

    3. mysqlエラーがCodeIgniterの画面に表示されないようにする方法

    4. MySQLは、ユーザーが見たテーブルをチェックすることからすでに見た行を省略します