2016-08-10 49 views
12

Cho phép giả định bảng sau:Chọn giá trị tối đa cho mỗi (col1, col2)

Name    SubName  Message Time 
USA    MA    M1   1 
USA    NY    M2   2 
USA    WA    M3   3 
USA    MA    M4   4 
USA    WA    M5   5 
USA    NY    M6   6 
FIN    HEL    M7   7 
FIN    TAM    M8   8 
FIN    HEL    M9   9 

Tôi muốn có một truy vấn SQL mà sẽ trở lại như sau:

Name    SubName  Message Time 
FIN    HEL   M9   9 
FIN    TAM   M8   8 
USA    NY    M6   6 
USA    WA    M5   5 
USA    MA    M4   4 

do đó, một ORDER BY time DESC, mà được nhóm theo tên riêng biệt và được phân nhóm theo tên riêng biệt.

Điều này có khả thi không? Tôi đang tìm một giải pháp mà không phải là DBMS cụ thể - một cái gì đó mà có thể chạy trong hầu hết tất cả các DBMS.

+0

cơ sở dữ liệu gì bạn đang sử dụng? –

+0

cho phép nói rằng db không liên quan. chúng tôi muốn đến với một sql mà nên làm việc bất cứ nơi nào. –

+0

Bạn nên đề cập rằng trong câu hỏi của bạn cho câu trả lời tốt hơn – TheGameiswar

Trả lời

6

Bạn không thẻ RDBMS của bạn, vì vậy cho ANSI-SQL mà nên làm việc trên hầu hết các RDBMS của bạn có thể sử dụng ROW_NUMBER():

SELECT s.* FROM (
    SELECT t.*, 
      ROW_NUMBER() OVER(PARTITION BY t.name,t.subname ORDER BY t.time DESC) as rnk 
    FROM YourTable 
    ) s 
WHERE s.rnk = 1 
ORDER BY s.time DESC,s.name 

EDIT: Dưới đây là một câu trả lời với Core ANSI SQL, mà nên làm việc trên BẤT CỨ cơ sở dữ liệu nào bạn có thể sử dụng NOT EXISTS():

SELECT * FROM YourTable t 
WHERE NOT EXISTS(SELECT 1 FROM YourTable s 
       WHERE t.name = s.name and t.subname = s.subname 
        AND s.time > t.time) 
+1

Upvote cho thay thế SQL ANSI lõi! – jarlh

3

Bạn có thể thực hiện việc này theo hai bước. Trước hết, hãy chọn mục tốt nhất cho mỗi kết hợp name/subname. Sau đó ra lệnh cho họ. Trong hầu hết các cơ sở dữ liệu, bạn có thể sử dụng row_number() cho phần đầu tiên:

select t.* 
from (select t.*, 
      row_number() over (partition by t.name, t.subname order by time desc) as seqnum 
     from t 
    ) t 
order by time desc; 
3

có thể sử dụng ROW_NUMBER()WHERE s.rank = 1 để có được ghi đầu tiên trong mỗi nhóm thực hiện bằng phân vùng bởi:

SELECT s.Name,s.SubName,s.Message, s.Time 
FROM (
    SELECT t.*, 
      ROW_NUMBER() OVER(PARTITION BY t.Name, t.SubName ORDER BY t.Time DESC) as rank 
    FROM YourTable t) s 
WHERE s.rank = 1 
ORDER BY s.Time DESC 
+0

Mặc dù mã này có thể giúp giải quyết vấn đề, nó không giải thích _why_ và/hoặc _how_ nó trả lời câu hỏi. Việc cung cấp ngữ cảnh bổ sung này sẽ cải thiện đáng kể giá trị lâu dài của nó. Vui lòng [sửa] câu trả lời của bạn để thêm giải thích, bao gồm những giới hạn và giả định được áp dụng. –

5
SELECT * FROM 
#TEMP T1 WHERE TIME= 
(SELECT MAX(TIME) FROM #TEMP T2 
WHERE T1.NAME=T2.NAME AND T2.SUBNAME=T1.SUBNAME) 

Đầu ra:

Name SubName Message Time 
USA  WA M5  5 
USA  NY M6  6 
USA  MA M4  4 
FIN  TAM M8  8 
FIN  HEl M9  9 
+1

Chỉ có câu trả lời chính của ANSI SQL! Bỏ phiếu cho điều đó! – jarlh

4

Và nếu DBMS của bạn không hỗ trợ mở rộng T611 ANSI SQL của, hoạt động tiểu OLAP:

select t1.* 
from tablename t1 
    join (select name, subname, max(Time) maxtime 
     from tablename 
     group by name, subname) 
    on t1.name = t2.name and 
     t1.subname = t2.subname and 
     t1.time= t2.maxtime 
order by name, subname, time desc 

Các tính năng sau bên ngoài lõi SQL-2003 được sử dụng: F591, "bảng nguồn gốc"

Lưu ý rằng ANSI SQL có time như một từ dành riêng, vì vậy bạn có thể cần phân định nó là "time".

1

tôi đã không kiểm tra này nhưng tôi nghĩ rằng điều này sẽ làm việc:

select 
    t1.name as name, 
    t1.subname as subname, 
    (select max(t2.message) from table t2 where t2.name = t1.name and t2.subname = t1.subname) as message, 
    (select max(t2.time) from table t2 where t2.name = t1.name and t2.subname = t1.subname) as time 
from 
    table t1 
group by 
    t1.name, 
    t1.subname 
order by 
    t1.name 
Các vấn đề liên quan