Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Kata kunci Oracle 'Partition By' dan 'Row_Number'

PARTITION BY memisahkan set, ini memungkinkan Anda untuk dapat bekerja(ROW_NUMBER(),COUNT(),SUM(),dll) pada set terkait secara independen.

Dalam kueri Anda, set terkait terdiri dari baris dengan cdt.country_code yang serupa, cdt.account, cdt.currency. Saat Anda mempartisi pada kolom tersebut dan Anda menerapkan ROW_NUMBER pada kolom tersebut. Kolom lain pada kombinasi/set tersebut akan menerima nomor urut dari ROW_NUMBER

Tapi kueri itu lucu, jika partisi Anda dengan beberapa data unik dan Anda meletakkan row_number di atasnya, itu hanya akan menghasilkan nomor yang sama. Ini seperti Anda melakukan ORDER BY pada partisi yang dijamin unik. Contoh, anggap GUID sebagai kombinasi unik dari cdt.country_code, cdt.account, cdt.currency

newid() menghasilkan GUID, jadi apa yang Anda harapkan dengan ekspresi ini?

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

...Benar, semua yang dipartisi (tidak ada yang dipartisi, setiap baris dipartisi di barisnya sendiri) row_numbers baris semuanya disetel ke 1

Pada dasarnya, Anda harus mempartisi pada kolom yang tidak unik. ORDER BY pada OVER membutuhkan PARTITION BY untuk memiliki kombinasi yang tidak unik, jika tidak semua row_numbers akan menjadi 1

Contoh, ini adalah data Anda:

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

Maka ini analog dengan permintaan Anda:

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

Apa yang akan menjadi output dari itu?

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

Anda lihat kombinasi HI HO? Tiga baris pertama memiliki kombinasi unik, oleh karena itu diset ke 1, baris B memiliki W yang sama, maka ROW_NUMBERS berbeda, demikian juga dengan baris HI C.

Sekarang, mengapa ORDER BY dibutuhkan disana? Jika pengembang sebelumnya hanya ingin menempatkan row_number pada data yang serupa (mis. HI B, semua data adalah B-W, B-W), ia dapat melakukan ini:

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

Tapi sayangnya, Oracle (dan Sql Server juga) tidak mengizinkan partisi tanpa ORDER BY; sedangkan di Postgresql, ORDER BY pada PARTISI adalah opsional:http://www.sqlfiddle.com/#!1/27821/1

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

ORDER BY pada partisi Anda terlihat agak berlebihan, bukan karena kesalahan pengembang sebelumnya, beberapa database tidak mengizinkan PARTITION tanpa ORDER BY , dia mungkin tidak dapat menemukan kolom kandidat yang baik untuk diurutkan. Jika kolom PARTITION BY dan kolom ORDER BY sama, hapus saja ORDER BY, tetapi karena beberapa database tidak mengizinkannya, Anda bisa melakukan ini:

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

Anda tidak dapat menemukan kolom yang bagus untuk digunakan untuk menyortir data yang serupa? Anda juga dapat mengurutkan secara acak, data yang dipartisi memiliki nilai yang sama omong-omong. Anda dapat menggunakan GUID misalnya (Anda menggunakan newid() untuk SQL Server). Sehingga memiliki output yang sama dengan yang dibuat oleh pengembang sebelumnya, sangat disayangkan beberapa database tidak mengizinkan PARTITION tanpa ORDER BY

Meskipun sungguh, itu menghindari saya dan saya tidak dapat menemukan alasan yang baik untuk menempatkan nomor pada kombinasi yang sama (B-W, B-W dalam contoh di atas). Ini memberi kesan database memiliki data yang berlebihan. Entah bagaimana mengingatkan saya pada ini:Bagaimana cara mendapatkan satu catatan unik dari daftar catatan yang sama dari tabel? Tidak ada batasan Unik di tabel

Benar-benar terlihat misterius melihat PARTITION BY dengan kombinasi kolom yang sama dengan ORDER BY, tidak dapat dengan mudah menyimpulkan maksud kode.

Tes langsung:http://www.sqlfiddle.com/#!3/27821/6

Tetapi seperti yang telah diperhatikan oleh dbaseman juga, tidak ada gunanya mempartisi dan mengurutkan pada kolom yang sama.

Anda memiliki kumpulan data seperti ini:

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

Kemudian Anda PARTISI OLEH hi,ho; dan kemudian Anda ORDER BY hi,ho. Tidak ada gunanya menomori data serupa :-) 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;

Keluaran:

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

Lihat? Mengapa perlu menempatkan nomor baris pada kombinasi yang sama? Apa yang akan Anda analisis pada triple A,X, double B,Y, double C,Z? :-)

Anda hanya perlu menggunakan PARTITION pada kolom non-unik, lalu Anda mengurutkan unik kolom non-unik -ing kolom Contoh akan membuatnya lebih jelas:

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 beroperasi pada kolom yang tidak unik, kemudian pada setiap kolom yang dipartisi, Anda memesan pada kolom uniknya (ho), ORDER BY ho

Keluaran:

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

Kumpulan data itu lebih masuk akal

Tes langsung:http://www.sqlfiddle.com/#!3/d0b44/1

Dan ini mirip dengan kueri Anda dengan kolom yang sama pada PARTITION BY dan ORDER BY:

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

Dan inilah hasilnya:

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

Lihat? tidak masuk akal?

Tes langsung:http://www.sqlfiddle.com/#!3/d0b44/3

Akhirnya ini mungkin pertanyaan yang tepat:

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


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. cara membuat tabel di oracle

  2. mengotomatiskan oracle skrip rollback

  3. Membuat database baru dan koneksi baru di Oracle SQL Developer

  4. Membuang Blok Data

  5. Pengurai untuk Oracle SQL