48

他の人が作成した SQL クエリがあり、その機能を理解しようとしています。誰かがここでPartition ByandRow_Numberキーワードが何をするのかを説明し、それを実際に使用する簡単な例と、それを使用したい理由を教えてください。

パーティションの例:

(SELECT cdt.*,
        ROW_NUMBER ()
        OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
              ORDER BY cdt.country_code, cdt.account, cdt.currency)
           seq_no
   FROM CUSTOMER_DETAILS cdt);

オンラインでいくつかの例を見てきましたが、それらは少し深すぎます。

前もって感謝します!

4

4 に答える 4

112

PARTITION BYセットを分離します。これにより、関連するセットで独立して作業 (ROW_NUMBER()、COUNT()、SUM() など) できるようになります。

クエリでは、cdt.country_code、cdt.account、cdt.currency が類似する行で構成される関連セット。これらの列をパーティション分割し、それらに ROW_NUMBER を適用する場合。これらの組み合わせ/セットの他の列には、ROW_NUMBER から連番が割り当てられます

しかし、そのクエリは面白いです。いくつかの一意のデータでパーティションを分割し、それに row_number を配置すると、同じ番号が生成されます。一意であることが保証されているパーティションで ORDER BY を実行するようなものです。例、GUID を一意の組み合わせと考えてください。cdt.country_code, cdt.account, cdt.currency

newid()GUID を生成するので、この式から何が期待できますか?

select
   hi,ho,
   row_number() over(partition by newid() order by hi,ho)
from tbl;

...そうです、すべてのパーティション化された (パーティション化されていない、すべての行が独自の行にパーティション化されている) 行の row_numbers はすべて 1 に設定されています

基本的に、一意でない列でパーティション化する必要があります。OVER の ORDER BY では、PARTITION BY に一意でない組み合わせが必要でした。そうしないと、すべての row_numbers が 1 になります。

例、これはあなたのデータです:

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','X'),
('A','Y'),
('A','Z'),
('B','W'),
('B','W'),
('C','L'),
('C','L');

次に、これはクエリに似ています。

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho)
from tbl;

その出力はどうなりますか?

HI  HO  COLUMN_2
A   X   1
A   Y   1
A   Z   1
B   W   1
B   W   2
C   L   1
C   L   2

HI HOの組み合わせが見えますか?最初の 3 行の組み合わせは一意であるため、1 に設定されます。B 行の W は同じであるため、ROW_NUMBERS が異なります。HI C 行と同様です。

では、なぜORDER BY必要なのですか?前の開発者が単に類似のデータに row_number を付けたいだけの場合 (例: HI B、すべてのデータが BW、BW)、次のようにできます。

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

しかし、悲しいかな、Oracle (および SQL Server も) は no のパーティションを許可しませんORDER BY。一方、Postgresql ではORDER BY、PARTITION はオプションです: http://www.sqlfiddle.com/#!1/27821/1

select
   hi,ho,
   row_number() over(partition by hi,ho)
from tbl;

あなたORDER BYのパーティションは少し冗長に見えますが、以前の開発者のせいではありません。一部のデータベースではPARTITIONno が許可されていないためORDER BY、並べ替えに適した候補の列を見つけることができない可能性があります。PARTITION BY 列と ORDER BY 列の両方が同じ場合は、ORDER BY を削除するだけですが、一部のデータベースでは許可されていないため、次のようにすることができます。

SELECT cdt.*,
        ROW_NUMBER ()
        OVER (PARTITION BY cdt.country_code, cdt.account, cdt.currency
              ORDER BY newid())
           seq_no
   FROM CUSTOMER_DETAILS cdt

同様のデータの並べ替えに使用する適切な列が見つかりませんか? ランダムにソートすることもできますが、分割されたデータはとにかく同じ値を持ちます。たとえば、GUID を使用できます ( newid()SQL Server に使用します)。そのため、前の開発者が作成したものと同じ出力が得られますが、一部のデータベースでは許可PARTITIONされていないのは残念ですORDER BY

実際には、それは私を逃し、同じ組み合わせに番号を付ける正当な理由を見つけることができません (上記の例では BW、BW)。冗長なデータを持つデータベースの印象を与えています。どういうわけかこれを思い出しました:テーブルのレコードの同じリストから一意のレコードを 1 つ取得する方法は? テーブルに UNIQUE 制約がありません

ORDER BY と同じ列の組み合わせを持つ PARTITION BY を見ると、コードの意図を簡単に推測することはできません。

ライブ テスト: http://www.sqlfiddle.com/#!3/27821/6


しかし、dbaseman も気付いているように、同じ列で分割して並べ替えても意味がありません。

次のような一連のデータがあります。

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','X'),
('A','X'),
('A','X'),
('B','Y'),
('B','Y'),
('C','Z'),
('C','Z');

次に、あなたは PARTITION BY hi,ho; そして、あなたは ORDER BY hi,ho です。同様のデータに番号を付ける意味はありません:-) http://www.sqlfiddle.com/#!3/29ab8/3

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

出力:

HI  HO  ROW_QUERY_A
A   X   1
A   X   2
A   X   3
B   Y   1
B   Y   2
C   Z   1
C   Z   2

見る?同じ組み合わせに行番号を付ける必要があるのはなぜですか? トリプル A、X、ダブル B、Y、ダブル C、Z で何を分析しますか? :-)


一意でない列で PARTITION を使用するだけで、一意でない列の一意の列でソートできます。例はそれをより明確にします:

create table tbl(hi varchar, ho varchar);

insert into tbl values
('A','D'),
('A','E'),
('A','F'),
('B','F'),
('B','E'),
('C','E'),
('C','D');

select
   hi,ho,
   row_number() over(partition by hi order by ho) as nr
from tbl;

PARTITION BY hi一意でない列で動作し、パーティション分割された各列で、一意の列 (ho) で注文します。ORDER BY ho

出力:

HI  HO  NR
A   D   1
A   E   2
A   F   3
B   E   1
B   F   2
C   D   1
C   E   2

そのデータセットはより理にかなっています

ライブ テスト: http://www.sqlfiddle.com/#!3/d0b44/1

これは、PARTITION BY と ORDER BY の両方で同じ列を使用するクエリに似ています。

select
   hi,ho,
   row_number() over(partition by hi,ho order by hi,ho) as nr
from tbl;

そして、これは出力です:

HI  HO  NR
A   D   1
A   E   1
A   F   1
B   E   1
B   F   1
C   D   1
C   E   1

見る?も意味ない?

ライブ テスト: http://www.sqlfiddle.com/#!3/d0b44/3


最後に、これは正しいクエリかもしれません:

SELECT cdt.*,
     ROW_NUMBER ()
     OVER (PARTITION BY cdt.country_code, cdt.account -- removed: cdt.currency
           ORDER BY 
               -- removed: cdt.country_code, cdt.account, 
               cdt.currency) -- keep
        seq_no
FROM CUSTOMER_DETAILS cdt
于 2012-05-07T06:30:36.283 に答える
7

これにより、国コード、アカウント、および通貨ごとに行番号が選択されます。したがって、国コードが「US」、アカウントが「XYZ」、通貨が「$USD」の行には、それぞれ 1 ~ n の行番号が割り当てられます。結果セット内のこれらの列の他のすべての組み合わせについても同じことが言えます。

order by句はまったく何もしないので、このクエリはちょっと面白いです。各パーティションのすべての行には同じ国コード、アカウント、および通貨が含まれているため、これらの列によるポイント順序付けはありません。したがって、この特定のクエリで割り当てられる最終的な行番号は予測できません。

それが役立つことを願っています...

于 2012-05-07T05:34:35.293 に答える
3

これが古いスレッドであることは知っていますが、PARTITION は ORDER BY ではなく GROUP BY に相当します。この関数の ORDER BY は . . . オーダーバイ。これは、シーケンス番号を追加することにより、冗長性から一意性を作成する方法にすぎません。または、関数のエイリアス列を参照するときに、WHERE 句によって他の冗長なレコードを削除することもできます。ただし、SELECT ステートメントの DISTINCT は、おそらくその点で同じことを達成します。

于 2016-01-13T18:51:43.490 に答える