8

別の SO 投稿 ( SQL: How to keep rows order with DISTINCT? ) によると、distinct はソートに関してはかなり未定義の動作をします。

質問があります:

select col_1 from table order by col_2

これは次のような値を返すことができます

3
5
3
2

次に、順序を保持するこれらの個別のものを選択する必要があります。つまり、必要です

select distinct(col_1) from table order by col_2 

戻る

3
5
2

だがしかし

5
3
2

これが私が実際にやろうとしていることです。col_1 はユーザー ID で、col_2 はそのユーザーによるログイン タイムスタンプ イベントです。したがって、同じユーザー (col_1) が何度もログインできます。システムで見られたユーザーの履歴リストを作成しようとしています。「私たちの最初のユーザーはこれまでに、2 番目のユーザーはこれまでに」などと言えるようにしたいと思います。

その投稿はグループ化を使用することを提案しているようですが、グループ化は行の順序を返すことを意図していないため、グループ化は順序を保持しないように見えるため、ここでこれがどのように、またはなぜ適用されるのかわかりません。実際、別の SO 投稿では、group by が探している順序を破棄する例を示しています。「Peter」を参照してください。後者の結果を保証する方法はありますか?奇妙なことに、DISTINCT 句を実装している場合最初に必ず順序付けを行い、次に結果を取得してリストの線形スキャンを実行し、順序付けを自然に保持するため、動作がなぜそうなのかわかりません。未定義。

編集:

皆さん、ありがとうございました!IMSoP の回答を受け入れました。これは、私が試してみることができるインタラクティブな例があっただけでなく (SQL Fiddle に参加してくれてありがとう)、単に「これを行う」のではなく、いくつかのことが機能した理由を説明したからです。 . 具体的には、GROUP BY が group by 以外の他の列の値を破棄しない (むしろ、ある種の内部リストに保持する) こと、およびこれらの値を ORDER BY 句で調べることができることは不明でした。

4

4 に答える 4

12

これはすべて、SQL ステートメントの「論理的な順序付け」に関係しています。DBMS は実際にはあらゆる種類の巧妙な戦略に従ってデータを取得する可能性がありますが、予測可能なロジックに従って動作する必要があります。そのため、SQL クエリのさまざまな部分は、そのロジックの動作に関して、互いに「前」または「後」に処理されると見なすことができます。

たまたま、ORDER BY句はその論理シーケンスの最後のステップであるため、「前の」ステップの動作を変更することはできません。

を使用すると、句はもちろんのこと、句が実行GROUP BYされるまでに行がグループにまとめられているため、グループ化された列のみを見ることができます。グループ。(MySQL は、論理的にそこに存在できない列を言及できる場所に物議を醸す拡張機能を実装しており、そのグループ内の任意の行から 1 つを選択します)。SELECTORDER BYGROUP BYSELECT

を使用するDISTINCTと、論理的にはのに処理されますSELECTが、ORDER BYはその後に続きます。したがってDISTINCT、重複が破棄された場合にのみ、残りの結果が特定の順序に配置されますが、破棄された行を使用してその順序を決定することはできません。


必要な結果を取得する方法については、キーは/が (論理的に) 実行されたに有効なソートする値を見つけることです。を使用する場合、集計された値は引き続き有効であることに注意してください。集計関数は、グループ内のすべての値を調べることができます。これにはとが含まれます。これは、「最小の番号」 ( ) が「昇順で並べ替えた場合の最初の番号」と同じであり、 の場合はその逆であるためです。GROUP BYDISTINCTGROUP BYMIN()MAX()MINMAX

foo_numberそのため、それぞれに適用可能な最小値に基づいて個別の値のセットを並べ替えるには、次のbar_numberように使用できます。

SELECT foo_number
FROM some_table
GROUP BY foo_number
ORDER BY MIN(bar_number) ASC

これは、任意のデータを使用したライブ デモです。


編集:コメントでは、グループ化/重複排除が行われる前に順序付けが適用された場合、その順序がグループに適用されない理由について説明しました。その場合でも、各グループ (最初または最後の行) にどの行を保持するかについての戦略が必要です。

類推として、元の行のセットをデッキから選んだトランプのセットとして想像し、額面の値が低いものから高いものへと並べ替えます。次に、ソートされたデッキを調べて、スーツごとに別々の山に配ります。どのカードが各パイルを「表す」べきですか?

カードを表向きに配る場合、最後に表示されるカードは額面の価値が最も高いカードになります (「キープ ラスト」戦略)。それらを裏向きに配り、各パイルを裏返すと、最も低い額面が表示されます (「最初にキープする」戦略)。どちらもカードの元の順序に従っており、「スーツに基づいてカードを配る」という指示は、意図された戦略をディーラー (DBMS を表す) に自動的に伝えません。

カードの最後の山が からのグループであるGROUP BY場合、MIN()MAX()は、順番に関係なく、各山を拾い上げて最低または最高の値を探すことを表します。しかし、グループの中を見ることができるので、他のことを行うことができますまた、各パイルの合計値 ( SUM) または何枚のカードがあるか ( COUNT) などを合計GROUP BYすると、「並べられた」よりもはるかに強力DISTINCTになります。

于 2013-10-16T22:01:59.653 に答える
1

参照されている回答では、順序付けを実行しようとしているのGROUP BYではありません...それは、単に、区別したい列に関連付けられた単一の値を選択しているだけです。

@bluefeet が述べているように、順序を保証したい場合は、 を使用する必要ORDER BYがあります。

ORDER BYに含まれていない値を に指定できないのはなぜSELECT DISTINCTですか?

と の次の値を考慮してcol1くださいcol2

create table yourTable (
  col_1 int,
  col_2 int
);

insert into yourTable (col_1, col_2) values (1, 1);
insert into yourTable (col_1, col_2) values (1, 3);
insert into yourTable (col_1, col_2) values (2, 2);
insert into yourTable (col_1, col_2) values (2, 4);

このデータでは、何をSELECT DISTINCT col_1 FROM yourTable ORDER BY col_2返す必要がありますか?

そのためGROUP BY、複数の値のどれを並べ替えるかを決定するために、集約関数が必要col_2です... could be MIN()、 could be MAX()、場合によっては理にかなっているような他の関数でさえAVG()あります; それはすべて特定のシナリオに依存するため、明示的にする必要があります。

select col_1
from yourTable
group by col_1
order by min(col_2)

SQL Fiddle Here

于 2013-10-16T22:20:13.750 に答える