今日このような質問を受けたので、皆さんの参考のためにまとめてみました
次のようなテーブルがあるとします:
ここでのデータには次の特徴があります:DepartmentIdには、多くのNameが存在する可能性があります。およびその逆。つまり、Name とDepartmentId には多対多の関係があります。
ここで、次のようなクエリを実装したいと思います。DepartmentID で並べ替えた後 (最初のステップ)、次に Name 列の一意の値を取得し (2 番目のステップ)、最初のステップ後の相対順序を保持します。この例では、返されるべき 3 つの値は次のとおりです: ACB
まず次のような書き方を考えます
Sample order byDepartmentId から個別の名前を選択します
意味的に言えば、これは非常に自然です。しかし、残念ながら、このステートメントはまったく実行できません。エラー メッセージは次のとおりです。
このエラーは、DISTINCT (重複値の削除) が使用されている場合、OrderBy の後に表示されるフィールドは SELECT の後にも表示される必要があることを意味します。 DepartmentID は実際には SELECT の後に表示されます。明らかに重複する値はないため、結果は間違いなく間違っています。
DepartmentId によるサンプル注文から個別の名前、DepartmentId を選択します
そこで、DISINCT と OrderBy の組み合わせがこの問題を引き起こすため、たとえば次のように回避することは可能でしょうか:
SELECT .NameFROM を区別 (DepartmentId によるサンプル順序から上位 100% の名前を選択) a
以前の記述方法を比較するために、サブクエリ テクノロジを使用しました。また、意味論的な観点から見ても、「まだ熱い」は非常に直感的で明確です。最初にDepartmentIdで並べ替えてから、重複する値を探したいと思います。しかし、返される結果は次のとおりです:
確かに重複した値は削除されていますが、返される順序は間違っています。最初にDepartmentIdで並べ替え、次に重複する値を削除し、並べ替え後の相対的な順序を保持したいと考えています。
なぜ上記の結果が表示されるのでしょうか?実際、これは DISTINCT 自体がソートを行うためであり、この動作は変更できません (これは以下の実行プランで確認できます)。したがって、実際のところ、以前に行った Order by はここでは意味を失います。 [実際、ADO.NET Entity Framework などの ORM ツールで生成された同様のクエリを観察すると、設定によって Order が自動的に破棄されます]
では、この場合、要件を達成することは不可能ですか?上?この要件はまれですが、ほとんどの場合、DISTINCT は最後の操作であり、並べ替えを実行するのが合理的です。
このように考えたのですが、DISTINCTの動作が組み込まれているため、この操作をバイパスすることは可能ですか?最終的に私が使用した解決策は、「それぞれの名前に番号を割り当てることができますか?」です。たとえば、A が 2 つある場合、最初の A には 1、2 番目の A には 2 というように番号を付けます。次に、クエリを実行するときに、最初に並べ替えてから、番号 1 の名前をフィルター処理して、重複する値が実際に削除されるようにしました。
SQL Server 2005 では、ROW_NUMBER 関数が提供され始めました。この関数と組み合わせて、次のクエリを実装しました。
select a.Name from (select top 100percentName,DepartmentId,ROW_NUMBER() over(partition by name order by planid) rowfrom サンプル順序 byDepartmentId) awhere a.row=1order by a.DepartmentId
次に、慎重に検討した結果、これは前述の要件を満たすはずです
。このクエリの効率が低下することは予測できます (下の図からいくつかの手がかりがわかります)。ただし、要件が厳しい場合は、ある程度のパフォーマンスが犠牲になっても不思議ではありません。もちろん、もっと良い書き方があるかどうかをさらに研究することもできます。いずれにしても、組み込み標準を使用した実装は通常、比較的高速です。