2009-10-07 21 views
6

Tôi mới làm việc với các chức năng phân tích.Chức năng phân tích Oracle cho giá trị nhỏ nhất trong nhóm

 
DEPT EMP SALARY 
---- ----- ------ 
    10 MARY 100000 
    10 JOHN 200000 
    10 SCOTT 300000 
    20 BOB 100000 
    20 BETTY 200000 
    30 ALAN 100000 
    30 TOM 200000 
    30 JEFF 300000 

Tôi muốn bộ phận và nhân viên có mức lương tối thiểu.

Kết quả sẽ giống như thế:

 
DEPT EMP SALARY 
---- ----- ------ 
    10 MARY 100000 
    20 BOB 100000 
    30 ALAN 100000 

EDIT: Đây là SQL Tôi đã (nhưng tất nhiên, nó không hoạt động như nó muốn nhân viên trong nhóm theo quy định tại khoản cũng):

 
SELECT dept, 
    emp, 
    MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary) 
FROM mytable 
GROUP BY dept 

Trả lời

7

Tôi nghĩ rằng chức năng Rank() không phải là cách để đi với điều này, vì hai lý do.

Thứ nhất, nó có lẽ kém hiệu quả hơn phương pháp dựa trên Min().

Lý do cho điều này là truy vấn phải duy trì danh sách đã đặt hàng của tất cả tiền lương cho mỗi bộ phận vì nó quét dữ liệu và sau đó thứ hạng sẽ được chỉ định bằng cách đọc lại danh sách này. Rõ ràng là trong trường hợp không có các chỉ mục có thể được tận dụng cho điều này, bạn không thể gán một thứ hạng cho đến khi mục dữ liệu cuối cùng đã được đọc và việc duy trì danh sách là tốn kém.

Vì vậy, hiệu suất của hàm Rank() phụ thuộc vào tổng số phần tử được quét và nếu số đủ để sắp xếp đĩa thì hiệu suất sẽ sụp đổ.

Đây có lẽ hiệu quả hơn:

select dept, 
     emp, 
     salary 
from 
     (
     SELECT dept, 
       emp, 
       salary, 
       Min(salary) Over (Partition By dept) min_salary 
     FROM mytable 
     ) 
where salary = min_salary 
/

Phương pháp này chỉ yêu cầu truy vấn duy trì một giá trị duy nhất cho mỗi bộ phận của giá trị tối thiểu gặp cho đến nay. Nếu giá trị tối thiểu mới gặp phải thì giá trị hiện tại được sửa đổi, nếu không giá trị mới sẽ bị hủy. Tổng số phần tử phải được giữ trong bộ nhớ có liên quan đến số lượng phòng ban, không phải số lượng hàng được quét.

Có thể là Oracle có một đường dẫn mã để nhận ra rằng Xếp hạng không thực sự cần phải được tính toán trong trường hợp này, nhưng tôi sẽ không đặt cược vào nó.

Lý do thứ hai cho việc không thích Xếp hạng() là nó chỉ trả lời sai câu hỏi. Câu hỏi không phải là "Hồ sơ nào có mức lương là xếp hạng đầu tiên khi tiền lương cho mỗi bộ phận được tăng dần theo thứ tự", đó là "Hồ sơ nào có mức lương tối thiểu cho mỗi bộ phận". Điều đó tạo nên sự khác biệt lớn với tôi, ít nhất.

+0

Cảm ơn David. Sau khi xem xét các lợi ích của nó, tôi đã tái cấu trúc giải pháp của bạn. –

3

Bạn có thể sử dụng cú pháp RANK(). Ví dụ, truy vấn này sẽ cho bạn biết nơi một nhân viên đứng trong bộ phận của họ đối với cách lớn tiền lương của họ là:

SELECT 
    dept, 
    emp, 
    salary, 
    (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept 
FROM EMPLOYEES 

Sau đó bạn có thể truy vấn từ này, nơi salary_rank_within_dept = 1:

SELECT * FROM 
    (
    SELECT 
     dept, 
     emp, 
     salary, 
     (RANK() OVER (PARTITION BY dept ORDER BY salary)) salary_rank_within_dept 
    FROM EMPLOYEES 
) 
WHERE salary_rank_within_dept = 1 
+0

Hoàn hảo! Tôi chưa biết về RANK(). Cảm ơn. –

+0

Tôi thậm chí không biết về RANK() cho đến ngày hôm qua! :) –

+1

Tôi downvoting này vì những lý do tôi vạch ra trong câu trả lời của riêng tôi: Tôi nghĩ rằng nó có thể không hiệu quả, và tôi nghĩ rằng các truy vấn không phải là một kết hợp tốt cho câu hỏi chính xác được hỏi. Tôi không nói rằng nó sẽ không đưa ra câu trả lời đúng, chỉ là nó không thể hiện được logic của câu hỏi rất tốt. –

-1
select e2.dept, e2.emp, e2.salary 
from employee e2 
where e2.salary = (select min(e1.salary) from employee e1) 
+1

Điều đó sẽ cung cấp cho bạn một bản ghi - mức tối thiểu cho toàn bộ bảng. Bạn cần nhóm theo bộ phận trong lựa chọn của bạn. –

3

Tôi nghĩ bạn đã khá gần với truy vấn ban đầu của mình. Sau đây sẽ chạy và làm phù hợp với trường hợp thử nghiệm của bạn:

SELECT dept, 
    MIN(emp) KEEP(DENSE_RANK FIRST ORDER BY salary, ROWID) AS emp, 
    MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY salary, ROWID) AS salary 
FROM mytable 
GROUP BY dept 

Ngược lại với các RANK() các giải pháp, điều này một khoản bảo lãnh tối đa là một hàng cho mỗi bộ phận.Nhưng điều đó gợi ý một vấn đề: những gì xảy ra trong một bộ phận nơi có hai nhân viên với mức lương thấp nhất? Các giải pháp RANK() sẽ trả về cả hai nhân viên - nhiều hơn một hàng cho bộ phận. Câu trả lời này sẽ chọn một tùy ý và đảm bảo chỉ có một cho bộ phận.

+1

Vâng, đó là một điểm tốt trên nhiều bản ghi. (Các) phương thức Min() sẽ lấy tất cả các bản sao ... sẽ phức tạp hơn để lấy lại một bản ghi duy nhất cho những người đó nếu cần. –

+1

Xây dựng tuyệt vời - đặc biệt nếu phân tích được đặt ra là quan tâm nhiều hơn với giá trị * * của mức tối thiểu. Nếu * xác định các thuộc tính * của mức tối thiểu là cần thiết, việc bảo quản các bản sao có vẻ là mong muốn. – Andrew

Các vấn đề liên quan