2009-07-31 37 views
6

Tôi có một truy vấn dọc theo dòng củaLàm một truy vấn SQL hiệu quả hơn

select b.* from 
(select key, max(val) as val from (somequery) group by key) as a 
inner join 
(somequery) as b 
on a.key = b.key and a.val = b.val 
order by key 

Và tôi đã tự hỏi nếu có một cách rõ ràng (mà tôi đang thiếu) để đơn giản hóa nó (cho rằng somequery có thể thay Dài).

Bất kỳ suy nghĩ nào cũng sẽ được đánh giá cao.

+0

somequery? Bạn sẽ cần phải xây dựng trên đó nếu bạn mong đợi để có được bất kỳ sự giúp đỡ thực sự. –

+1

@rexem: Không có OP nào. Rõ ràng là anh ta muốn kéo chỉ những hàng có giá trị tối đa. – Eric

Trả lời

2

Có, nhưng nó chắc chắn không rõ ràng:

select 
    * 
from 
    (
    select 
     key, 
     val, 
     col, 
     max(val) over (partition by key) as MaxVal 
    from 
     tableA 
    ) 
where 
    val = MaxVal 

Sử dụng mệnh đề over là một cách tuyệt vời để làm điều này, và không đòi hỏi bất kỳ truy vấn con không liên quan. Tất cả điều đó là lấy tối đa val cho mỗi khóa và sau đó kết thúc tốt đẹp kết quả được đặt trong truy vấn phụ, nơi chúng tôi có thể kiểm tra val chống lại MaxVal để đảm bảo chúng tôi đang kéo hàng chính xác.

Sạch hơn và nhanh hơn nhiều so với thực hiện tối đa ba truy vấn phụ!

+0

Tôi chưa thấy MAX..OVER trước đây. Làm thế nào để làm việc này cho các phím tổng hợp? Tôi đang cố gắng trên bảng của riêng mình và tôi có thể sử dụng agg/join hoặc ROWNUMBER = 1, nhưng không phải là kỹ thuật này. – gbn

+0

'max (val) trên (phân vùng bằng key1, key2, key3)' hoạt động như một sự quyến rũ. – Eric

+0

Cảm ơn vì điều đó, Eric. –

-1

Tôi sẽ chọn truy vấn phụ của bạn thành một bảng tạm thời trước khi chọn từ chúng. Tôi nghĩ bạn sẽ thấy tăng hiệu suất đáng kể từ đó.

+1

Không phải của tôi downvote, nhưng ... nếu bạn chọn vào một bảng tạm thời, DBMS phải lưu trữ dữ liệu đó, và siêu dữ liệu của nó, và sau đó sử dụng nó một lần. Nó sẽ hiệu quả hơn và hiệu quả để cung cấp cho trình tối ưu hóa toàn bộ truy vấn - vì vậy nó có thể tránh hiện thực hóa truy vấn phụ nếu có thể. Bây giờ, nếu có một số truy vấn sẽ sử dụng cùng một truy vấn con, thì bạn có thể thấy một lợi ích từ một bảng tạm thời rõ ràng - mặc dù nó sẽ là một ý tưởng tốt để đo lường và đảm bảo. –

+1

@ Jonathan: Tôi đồng ý rằng về nguyên tắc những gì bạn nói là chính xác nhưng kinh nghiệm của tôi với máy chủ SQL cho thấy rằng đối với các bảng lớn hơn (nói bất cứ điều gì lớn hơn 2000 hàng) tuyến đường này là hiệu quả hơn nhiều. – Jon

0

Bạn muốn sử dụng ROW_NUMBER() hoặc RANK() cho việc này.

(và hãy chắc chắn rằng một truy vấn trước đó kết thúc bằng một dấu chấm phẩy)

with ranked as 
(
select *, row_number() over (partition by key order by val desc) as bestrow 
from sometableorquery 
) 
select * 
from ranked 
where bestrow = 1 
order by key; 

Nếu bạn muốn mối quan hệ (vì vậy mà một chìa khóa có hai giá trị tốt nhất trả về cả hai), sau đó sử dụng rank() thay vì row_number().

Rob

+0

Ngoài ra - nếu bạn muốn lấy 3 đầu của mỗi khóa, hãy thử "WHERE bestrow <= 3" –

+1

ROW_NUMBER sẽ chỉ trả lại một hàng cho mỗi khóa. Trường hợp mã OP sẽ liên kết trong trường hợp có nhiều hơn một hàng cho một khóa với val = max (val). Thay thế ROW_NUMBER() bằng RANK() sẽ giữ nguyên ý định ban đầu. –

+0

Cảm ơn Shannon. Tôi đã đề cập đến điều 'nếu bạn muốn quan hệ' trong đó. –

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