web-dev-qa-db-ja.com

Oracle 'Partition By'および 'Row_Number'キーワード

他の人が書いたSQLクエリがあり、それが何をするのかを理解しようとしています。誰かがPartition ByおよびRow_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);

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

前もって感謝します!

43
HashimR

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が必要なのですか?前の開発者が、同様のデータ(例:HI B、すべてのデータが白黒、白黒)にrow_numberを配置するだけの場合、次のようにします。

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

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

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

パーティション上のORDER BYは少し冗長に見えますが、前の開発者のせいではなく、一部のデータベースはORDER BYなしでPARTITIONを許可していないため、適切な候補を見つけることができませんソートする列。 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を使用できます(SQL Serverにはnewid()を使用します)。前の開発者が作成した出力と同じであるため、一部のデータベースではORDER BYなしでPARTITIONが許可されていないのは残念です

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

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');

それから、hi、hoによるPARTITION。そして、あなたはこんにちは、ホーで注文します。同様のデータに番号を付ける意味はありません:-) http://www.sqlfiddle.com/#!3/29ab8/

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を使用するだけで、一意でない列のunique-ing列でソートできます。例はそれをより明確にします:

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/


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

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
100
Michael Buen

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

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

お役に立てば幸いです...

7
McGarnagle

Selectステートメントから重複したレコードを破棄する簡単な方法として、row_number()をよく使用します。 where句を追加するだけです。何かのようなもの...

select a,b,rn 
  from (select a, b, row_number() over (partition by a,b order by a,b) as rn           
          from table) 
 where rn=1;
6
chris

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

2
OldManOfTheSQL