Trong quá trình lấy số liệu, thiết lập bảng biểu và báo cáo, một
trường hợp thường gặp là bạn phải hiển thị dữ liệu từ dạng dòng chuyển
thành cột - kiểu truy vấn như vậy gọi là Pivot Query và ngược lại nghĩa
là chuyển từ cột thành dòng - kiểu truy vấn như vậy gọi là Unpivot
Query.
Để hiểu rõ hơn về 2 khái niệm trên ta thực hành ví dụ sau.
A. Khởi tạo dữ liệu1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | create table cust_sales ( customer_id varchar2(10), month varchar2(3), product_id varchar2(6), sales number ); insert into cust_sales values('Adam','Jan','Prod A',34); insert into cust_sales values('Adam','Feb','Prod B',49); insert into cust_sales values('Adam','Mar','Prod C',134); insert into cust_sales values('Jones','Feb','Prod A',92); insert into cust_sales values('Jones','Mar','Prod A',34); insert into cust_sales values('Kanes','Jan','Prod B',24); insert into cust_sales values('Kanes','Feb','Prod C',83); insert into cust_sales values('Kanes','Mar','Prod A',39); create table cust_sales_month ( customer_id varchar2(10), product_id varchar2(6), january number, february number, march number ); insert into cust_sales_month values('Kanes','Prod A',0,0,1); insert into cust_sales_month values('Jones','Prod A',0,1,1); insert into cust_sales_month values('Kanes','Prod C',0,1,0); insert into cust_sales_month values('Kanes','Prod B',1,0,0); insert into cust_sales_month values('Adam','Prod B',0,1,0); insert into cust_sales_month values('Adam','Prod A',1,0,0); insert into cust_sales_month values('Adam','Prod C',0,0,1); commit; |
(Nhóm lệnh 1)
Chúng ta chú ý như sau:- Bảng cust_sales: dùng cho việc thực hành các vấn đề liên quan đến PIVOT
- Bảng cust_sales_month: dùng cho việc thực hành các vấn đề liên quan đến UNPIVOT
Ta chạy câu lệnh sau:
1 | SELECT * FROM cust_sales; |
(Câu lệnh 1)
Kết quả:
(Hình 1)
Với kết quả trên thì việc thống kê rất khó để theo dõi cho các yêu cầu sau:- Yêu cầu 1: Thống kê kết quả bán hàng theo sản phẩm
- Yêu cầu 2: Thống kê kết quả bán hàng theo tháng
- Yêu cầu 3: Thống kê kết quả bán hàng theo khách hàng
Để thực hiện được các yêu cầu thống kê như trên ta có thể dùng CASE
để làm (hàm này không được giới thiệu trong phạm vi bài này) hoặc dùng
hàm PIVOT để thực hiện (lưu ý: hàm PIVOT chỉ có từ phiên bản Oracle 11g
trở lên).
Cú pháp hàm như sau:
SELECT...
FROM ...
PIVOT[XML]
( pivot_clause
pivot_for_clause
pivot_in_clause )
WHERE ...
- pivot_clause: khai báo cột được tính toán bởi các hàm thống kê như SUM, COUNT, MAX, MIN, AVG, ...
- pivot_for_clause: khai báo cột sẽ được nhóm lại khi thực hiện thống kê bởi hàm được dùng trong pivot_clause
- pivot_in_clause: khai báo các giá trị thỏa mãn điều kiện để thực hiện pivot
Để hiểu rõ hơn về các mệnh đề được dùng trong PIVOT ta map các nội dung của yêu cầu 1 vào các mệnh đề PIVOT như sau:
Yêu cầu 1: Thống kê kết quả bán hàng theo sản phẩm- pivot_clause: thống kê kết quả bán hàng --> sum(sales)
- pivot_for_clause: theo sản phẩm --> product_id
- pivot_in_clause: kết quả hiển thị gồm các sản phẩm Prod A, Prod B, Prod C ở 3 cột --> ('Prod A', 'Prod B', 'Prod C')
- Yêu cầu 1: Thống kê kết quả bán hàng theo sản phẩm
1 2 3 4 5 6
SELECT * FROM cust_sales PIVOT (SUM(sales) FOR product_id IN ('Prod A' AS product_a, 'Prod B' AS product_b, 'Prod C' AS product_c));
(Câu lệnh 2) - Yêu cầu 2: Thống kê kết quả bán hàng theo tháng
1 2 3 4
SELECT * FROM cust_sales PIVOT (SUM (sales) FOR month IN ('Jan' AS january, 'Feb' AS february, 'Mar' AS march));
(Câu lệnh 3) - Yêu cầu 3: Thống kê kết quả bán hàng theo khách hàng
1 2 3 4
SELECT * FROM cust_sales PIVOT (SUM(sales) FOR customer_id IN('Adam','Jones','Kanes'));
(Câu lệnh 4)
Unpivot là trường hợp ngược lại của PIVOT nghĩa là khi ta có 1 tập kết quả đang được hiển thị dưới dạng cột ta muốn biến chuyển kết quả này hiển thị dưới dạng dòng. Xem ví dụ sau:
1 | SELECT * FROM cust_sales_month; |
(Câu lệnh 5)
(Hình 5)
Bảng dữ liệu trên cho biết các khách hàng có mua sản phẩm vào các tháng nào trong năm. Nếu như tháng nào mua thì đánh dấu là 1 ngược lại là 0. Với bảng dữ liệu trên ta muốn tùy biến hiển thị dữ liệu theo dạng dòng như sau:
CUSTOMER_ID | PRODUCT_ID | MONTH | YES |
---|---|---|---|
Adam | Prod A | JANUARY | 1 |
Adam | Prod A | FEBRUARY | 0 |
Adam | Prod A | MARCH | 0 |
Adam | Prod B | FEBRUARY | 1 |
Adam | Prod B | JANUARY | 0 |
Adam | Prod B | MARCH | 0 |
Adam | Prod C | FEBRUARY | 0 |
Adam | Prod C | JANUARY | 0 |
Adam | Prod C | MARCH | 1 |
Jones | Prod A | FEBRUARY | 1 |
Jones | Prod A | JANUARY | 0 |
Jones | Prod A | MARCH | 1 |
Kanes | Prod A | MARCH | 1 |
Kanes | Prod A | JANUARY | 0 |
Kanes | Prod A | FEBRUARY | 0 |
Kanes | Prod B | FEBRUARY | 0 |
Kanes | Prod B | JANUARY | 1 |
Kanes | Prod B | MARCH | 0 |
Kanes | Prod C | MARCH | 0 |
Kanes | Prod C | FEBRUARY | 1 |
Kanes | Prod C | JANUARY | 0 |
(Bảng kết quả 1)
Trước khi đi đến cách thực hiện, ta tìm hiểu sơ qua cú pháp của hàm UNPIVOT.1 2 3 4 | UNPIVOT ( unpivot_clause unpivot_for_clause unpivot_in_clause ) |
- unpivot_clause: khác với PIVOT, mệnh đề được khai báo ở đây không thực hiện tính toán; nó chỉ đơn thuần là tên cột dùng để hiển thị dữ liệu sau khi unpivot
- unpivot_for_clause: khai báo cột cần unpivot để lấy giá trị tương ứng với tên cột được khai báo ở unpivot_clause
- unpivot_in_clause: khai báo danh sách các giá trị khi thực hiện UNPIVOT
- unpivot_clause: mua / không mua --> tên cột chứa giá trị
- unpivot_for_clause: theo từng tháng --> giá trị cột month
- unpivot_in_clause: theo từng tháng --> ở đây cần thống kê 3 tháng: JANUARY, FEBRUARY và MARCH
1 2 3 4 5 | SELECT * FROM cust_sales_month UNPIVOT (yes FOR month IN ("JANUARY", "FEBRUARY", "MARCH")) ORDER BY customer_id, product_id; |
(Câu lệnh 6)
Ths ad. Cho hỏi thêm, trường hợp có thêm cột số lượng hàng bán và cần biết số lượng hàng bán và doanh số bán của từng mặt hàng thì làm thế nào ạ?
ReplyDelete