Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

Từ khóa 'Partition By' và 'Row_Number' của Oracle

PARTITION BY các tập hợp riêng biệt, điều này cho phép bạn có thể làm việc (ROW_NUMBER (), COUNT (), SUM (), v.v.) trên tập hợp liên quan một cách độc lập.

Trong truy vấn của bạn, tập hợp liên quan bao gồm các hàng có cdt.country_code, cdt.account, cdt.currency tương tự. Khi bạn phân vùng trên các cột đó và bạn áp dụng ROW_NUMBER trên chúng. Các cột khác trên tổ hợp / tập hợp đó sẽ nhận được số thứ tự từ ROW_NUMBER

Nhưng truy vấn đó thật buồn cười, nếu phân vùng của bạn theo một số dữ liệu duy nhất và bạn đặt row_number trên đó, nó sẽ chỉ tạo ra cùng một số. Nó giống như bạn thực hiện ĐẶT HÀNG BẰNG trên một phân vùng được đảm bảo là duy nhất. Ví dụ, hãy nghĩ về GUID là sự kết hợp duy nhất của cdt.country_code, cdt.account, cdt.currency

newid() tạo ra GUID, vì vậy bạn sẽ mong đợi điều gì ở biểu thức này?

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

... Đúng vậy, tất cả các hàng được phân vùng (không có hàng nào được phân vùng, mọi hàng được phân vùng trong hàng riêng của chúng) row_numbers của hàng đều được đặt thành 1

Về cơ bản, bạn nên phân vùng trên các cột không phải là duy nhất. ORDER BY trên OVER cần PARTITION BY có kết hợp không phải là duy nhất, nếu không, tất cả row_numbers sẽ trở thành 1

Ví dụ, đây là dữ liệu của bạn:

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

Sau đó, điều này tương tự với truy vấn của bạn:

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

Đầu ra của điều đó sẽ là gì?

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

Bạn thấy sự kết hợp của HI HO? Ba hàng đầu tiên có sự kết hợp duy nhất, do đó chúng được đặt thành 1, các hàng B có cùng W, do đó ROW_NUMBERS khác nhau, tương tự với các hàng HI C.

Bây giờ, tại sao lại là ORDER BY cần thiết ở đó? Nếu nhà phát triển trước đó chỉ muốn đặt một row_number trên dữ liệu tương tự (ví dụ:HI B, tất cả dữ liệu là B-W, B-W), anh ta chỉ có thể làm điều này:

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

Nhưng than ôi, Oracle (và cả Sql Server nữa) không cho phép phân vùng không có ORDER BY; trong khi trong Postgresql, ORDER BY trên PARTITION là tùy chọn:http://www.sqlfiddle.com/#!1/27821/1

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

ORDER BY của bạn trên phân vùng của bạn trông hơi thừa, không phải do lỗi của nhà phát triển trước đó, một số cơ sở dữ liệu không cho phép PARTITION không có ORDER BY , anh ta có thể không tìm được cột ứng viên tốt để sắp xếp. Nếu cả hai cột PARTITION BY và cột ORDER BY giống nhau, chỉ cần xóa ORDER BY, nhưng vì một số cơ sở dữ liệu không cho phép, bạn chỉ có thể thực hiện điều này:

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

Bạn không thể tìm thấy một cột tốt để sử dụng cho việc sắp xếp dữ liệu tương tự? Bạn cũng có thể sắp xếp ngẫu nhiên, dữ liệu được phân vùng có cùng giá trị dù sao. Bạn có thể sử dụng GUID chẳng hạn (bạn sử dụng newid() cho SQL Server). Vì vậy, có cùng đầu ra do nhà phát triển trước đó tạo ra, thật không may là một số cơ sở dữ liệu không cho phép PARTITION không có ORDER BY

Mặc dù thực sự, nó khiến tôi lẩn tránh và tôi không thể tìm thấy lý do chính đáng để đặt một số vào các tổ hợp giống nhau (B-W, B-W trong ví dụ ở trên). Nó tạo ấn tượng về cơ sở dữ liệu có dữ liệu dư thừa. Bằng cách nào đó đã nhắc nhở tôi điều này:Làm thế nào để lấy một bản ghi duy nhất từ ​​cùng một danh sách các bản ghi từ bảng? Không có ràng buộc duy nhất trong bảng

Nó thực sự trông phức tạp khi thấy một PHẦN BẰNG BẰNG CHỨNG có cùng sự kết hợp của các cột với LỆNH BẰNG LỆNH, không thể dễ dàng suy ra ý định của mã.

Kiểm tra trực tiếp:http://www.sqlfiddle.com/#!3/27821/6

Nhưng như dbaseman cũng đã nhận thấy, việc phân vùng và sắp xếp thứ tự trên các cột giống nhau là vô ích.

Bạn có một tập hợp dữ liệu như sau:

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

Sau đó, bạn PARTITION BY chào, ho; và sau đó bạn ĐẶT HÀNG, chào bạn. Không có ý nghĩa đánh số dữ liệu tương tự :-) 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;

Đầu ra:

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

Xem? Tại sao cần đặt số hàng trên cùng một tổ hợp? Bạn sẽ phân tích gì về bộ ba A, X, trên kép B, Y, trên kép C, Z? :-)

Bạn chỉ cần sử dụng PARTITION trên cột không phải duy nhất, sau đó bạn sắp xếp trên (các) cột không duy nhất duy nhất -ing cột. Ví dụ sẽ làm rõ hơn:

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ạt động trên cột không duy nhất, sau đó trên mỗi cột được phân vùng, bạn đặt hàng trên cột duy nhất của nó (ho), ORDER BY ho

Đầu ra:

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

Tập dữ liệu đó có ý nghĩa hơn

Kiểm tra trực tiếp:http://www.sqlfiddle.com/#!3/d0b44/1

Và điều này tương tự với truy vấn của bạn với các cột giống nhau trên cả PARTITION BY và ORDER BY:

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

Và đây là kết quả:

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

Xem? không có ý nghĩa?

Kiểm tra trực tiếp:http://www.sqlfiddle.com/#!3/d0b44/3

Cuối cùng, đây có thể là truy vấn phù hợp:

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. Mệnh đề GIỮA so với <=AND> =

  2. Đếm số lần xuất hiện của một ký tự trong Oracle SQL

  3. Cách tạo hàm PL / SQL trong cơ sở dữ liệu Oracle

  4. ĐẶT SQLBLANKLINES:Cách Cho phép Dòng trống trong SQLcl &SQL * Plus

  5. SQLException:Vi phạm giao thức. Vấn đề về trình điều khiển JDBC của Oracle