2012-04-27 40 views
9

bảng của tôi:Oracle SQL - Chức năng phân tích TRÊN một nhóm?

ID NUM VAL 
1 1  Hello 
1 2  Goodbye 
2 2  Hey 
2 4  What's up? 
3 5  See you 

Nếu tôi muốn trả lại số tối đa cho mỗi ID, nó thực sự thoải mái và sạch sẽ:

SELECT MAX(NUM) FROM table GROUP BY (ID) 

Nhưng nếu tôi muốn lấy giá trị liên quan đến việc tối đa của mỗi số cho mỗi ID?

Tại sao tôi không thể làm:

SELECT MAX(NUM) OVER (ORDER BY NUM) FROM table GROUP BY (ID) 

Tại sao là một lỗi? Tôi muốn chọn nhóm này theo ID, chứ không phải phân vùng riêng cho mỗi cửa sổ ...

EDIT: Lỗi này không phải là "biểu thức THEO TÊN GROUP".

+1

Chúng tôi không thể nhìn thấy thông báo lỗi của mình từ đây. – RBarryYoung

+0

Bạn có thể hiển thị đầu ra mà bạn mong đợi, mô tả không có ý nghĩa với tôi ... 'Tôi muốn lấy giá trị được liên kết với giá trị tối đa của mỗi số cho mỗi ID'. Tôi cũng không chắc chắn sự khác biệt một ORDER BY sẽ làm cho một hàm MAX() ... – MatBailie

+0

Không phải là một câu trả lời chính xác cho câu hỏi nhưng một giới thiệu tốt về oracle chức năng phân tích có thể được tìm thấy tại [orafaq] (http: // www.orafaq.com/node/55). Bài đăng giúp hiểu các khái niệm với các ví dụ đơn giản. –

Trả lời

13

Bạn có thể có thể sử dụng chức năng MAX() KEEP(DENSE_RANK LAST...):

with sample_data as (
    select 1 id, 1 num, 'Hello' val from dual union all 
    select 1 id, 2 num, 'Goodbye' val from dual union all 
    select 2 id, 2 num, 'Hey' val from dual union all 
    select 2 id, 4 num, 'What''s up?' val from dual union all 
    select 3 id, 5 num, 'See you' val from dual) 
select id, max(num), max(val) keep (dense_rank last order by num) 
from sample_data 
group by id; 
+1

+1 Wow, câu trả lời này rất hay. Không biết rằng có chức năng KEEP trên chức năng cửa sổ, hoặc có thể nó là độc quyền đối với Oracle, tuy nhiên đây là giải pháp thanh lịch. Câu trả lời này hoạt động trên hầu hết các cơ sở dữ liệu mặc dù http://stackoverflow.com/a/10359164 Oracle: http://www.sqlfiddle.com/#!4/a9a07/19 Sql Server: http://www.sqlfiddle.com/ #! 3/a9a07/1 Postgresql: http://www.sqlfiddle.com/#!1/a9a07/6 –

+0

Tôi thích cách tôi liên tục tìm câu hỏi về Oracle chỉ với một truy vấn và không giải thích về những gì ma quỷ nó đang làm và làm thế nào nó hoạt động. Rất hữu ích cho việc áp dụng các giải pháp cho các tình huống khác. – jpmc26

3

Nếu bạn đang tìm kiếm để có được những hàng có chứa các giá trị từ MAX(num) GROUP BY id, điều này có xu hướng trở thành một mô hình phổ biến ...

WITH 
    sequenced_data 
AS 
(
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY num DESC) AS sequence_id, 
    * 
    FROM 
    yourTable 
) 
SELECT 
    * 
FROM 
    sequenced_data 
WHERE 
    sequence_id = 1 


EDIT

Tôi không biết nếu Teradata sẽ cho phép điều này, nhưng logic dường như có ý nghĩa ...

SELECT 
    * 
FROM 
    yourTable 
WHERE 
    num = MAX(num) OVER (PARTITION BY id) 

Hoặc có thể ...

SELECT 
    * 
FROM 
(
    SELECT 
    *, 
    MAX(num) OVER (PARTITION BY id) AS max_num_by_id 
    FROM 
    yourTable 
) 
    AS sub_query 
WHERE 
    num = max_num_by_id 

Đây là hơi khác so với câu trả lời trước của tôi; nếu nhiều bản ghi được gắn với cùng một MAX(num), điều này sẽ trả về tất cả chúng, câu trả lời khác sẽ chỉ bao giờ trả về một.


EDIT

Trong SQL đề xuất của bạn các lỗi liên quan đến thực tế là mệnh đề OVER() chứa một lĩnh vực không nằm trong nhóm của bạn. Nó giống như cố gắng để làm điều này ...

SELECT id, num FROM yourTable GROUP BY id 

num là không hợp lệ, vì có thể có nhiều giá trị trong lĩnh vực đó cho mỗi hàng trở (với các hàng trả lại được xác định bởi GROUP BY id).

Trong cùng một cách, bạn không thể đặt num bên trong mệnh đề OVER().

SELECT 

    id, 

    MAX(num),    <-- Valid as it is an aggregate 

    MAX(num)     <-- still valid 
    OVER(PARTITION BY id), <-- Also valid, as id is in the GROUP BY 

    MAX(num)     <-- still valid 
    OVER(PARTITION BY num) <-- Not valid, as num is not in the GROUP BY 

FROM 
    yourTable 
GROUP BY 
    id 


Xem câu hỏi này khi bạn không thể chỉ định một cái gì đó trong mệnh đề OVER(), và một câu trả lời hiển thị khi (tôi nghĩ) bạn có thể: over-partition-by-question

+1

một chuyến đi nhanh đến [http://sqlfiddle.com] (http://www.sqlfiddle.com/#!4/a9a07/23) có thể xác minh rằng điều này không hoạt động: 'select id, val from yourTable num = max (num) trên (phân vùng theo id) '. Nó sẽ là tốt đẹp nếu nó làm việc mặc dù, rất ngắn gọn –

4

Khi bạn sử dụng chức năng cửa sổ, bạn không cần phải sử dụng GROUP BY nữa, điều này sẽ đủ:

select id, 
    max(num) over(partition by id) 
from x 

Trên thực tế bạn có thể nhận được kết quả mà không sử dụng chức năng windowing:

select * 
from x 
where (id,num) in 
    (
    select id, max(num) 
    from x 
    group by id 
) 

Output:

ID NUM VAL 
1 2 Goodbye 
2 4 What's up 
3 5 SEE YOU 

http://www.sqlfiddle.com/#!4/a9a07/7


Nếu bạn muốn sử dụng chức năng cửa sổ, bạn có thể làm điều này:

select id, val, 
    case when num = max(num) over(partition by id) then 
     1 
    else 
     0 
    end as to_select 
from x 
where to_select = 1 

Hoặc này:

select id, val 
from x 
where num = max(num) over(partition by id) 

Nhưng vì nó không được phép làm những người, bạn phải làm điều này:

with list as 
(
    select id, val, 
    case when num = max(num) over(partition by id) then 
     1 
    else 
     0 
    end as to_select 
    from x 
) 
select * 
from list 
where to_select = 1 

http://www.sqlfiddle.com/#!4/a9a07/19

+0

'ORDER BY num' đạt được những gì? 'MAX()' của '1,2,3' là giống như' MAX() 'của' 2,3,1' ... Đối với 'MAX()', chắc chắn chỉ có 'PARTITION BY' có ý nghĩa? – MatBailie

+1

yep đúng, chỉ PARTITION BY có ý nghĩa đối với MAX. mã đầu tiên (MAX OVER ORDER BY) trên câu trả lời của tôi chỉ được sao chép nhanh chóng từ câu hỏi của OP. ORDER BY trên chức năng cửa sổ chỉ có ý nghĩa đối với tổng số lần chạy, ví dụ: SUM –

+0

Vâng, ROW_NUMBER(), RANK(), vv, * (khi chúng trả lại các giá trị khác nhau tùy thuộc vào vị trí/thứ tự) * nhưng không phải MIN(), MAX(), SUM()? – MatBailie

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