2009-04-16 16 views
15

OK Tôi có một bảng như thế này:Query đơn giản để lấy Max Giá trị cho mỗi ID

ID  Signal Station OwnerID 
111  -120  Home  1 
111  -130  Car  1 
111  -135  Work  2 
222  -98  Home  2 
222  -95  Work  1 
222  -103  Work  2 

Đây là tất cả trong cùng ngày. Tôi chỉ cần truy vấn để trả lại tín hiệu tối đa cho mỗi ID:

ID Signal Station OwnerID 
111 -120  Home  1 
222 -95  Work  1 

tôi đã cố gắng sử dụng MAX() và tập hợp messes lên với Trạm và OwnerID là khác nhau cho mỗi bản ghi. Tôi có cần phải làm một JOIN?

+0

Bạn đang sử dụng phiên bản SQL Server nào? –

Trả lời

15

Một cái gì đó như thế này? Tự mình tham gia bảng của bạn và loại trừ các hàng có tín hiệu cao hơn được tìm thấy.

select cur.id, cur.signal, cur.station, cur.ownerid 
from yourtable cur 
where not exists (
    select * 
    from yourtable high 
    where high.id = cur.id 
    and high.signal > cur.signal 
) 

Điều này sẽ liệt kê một hàng cho mỗi tín hiệu cao nhất, vì vậy có thể có nhiều hàng cho mỗi id.

+0

Vâng, điều này sẽ trả về các bản sao nếu Tín hiệu giống nhau đối với nhiều Trạm. –

+0

Đã chỉnh sửa để bạn nhận được nhiều hàng cho mỗi tín hiệu, nhưng không có trùng lặp. Sử dụng câu trả lời của Quassnoi nếu bạn chỉ muốn một hàng ngẫu nhiên trong số những người có tín hiệu cao nhất. – Andomar

+0

Có, tôi nghĩ rằng điều này đang hoạt động. Tôi cần kiểm tra dữ liệu. Nhưng cảm ơn rất nhiều. –

1
WITH q AS 
     (
     SELECT c.*, ROW_NUMBER() OVER (PARTITION BY id ORDER BY signal DESC) rn 
     FROM mytable 
     ) 
SELECT * 
FROM  q 
WHERE rn = 1 

này sẽ trở lại một hàng ngay cả khi có bản sao của MAX(signal) cho một ID nhất định.

Có chỉ mục trên (id, signal) sẽ cải thiện đáng kể truy vấn này.

+0

Tốt hơn để sử dụng phương pháp tổng hợp và jon hơn là tạo cột. Trình tối ưu hóa có thể đánh giá toàn bộ: cột được tính toán ở đây cần được tính toán đầu tiên, vì vậy điều này nhiều khả năng cần một ống chỉ ở đâu đó – gbn

+0

Nếu bạn có chỉ mục trên cột này (bạn nên), kết nối sẽ kém hiệu quả hơn. – Quassnoi

+0

+ không cho SQL Server 200 chỉ trong trường hợp – gbn

0
select a.id, b.signal, a.station, a.owner from 
mytable a 
join 
(SELECT ID, MAX(Signal) as Signal FROM mytable GROUP BY ID) b 
on a.id = b.id AND a.Signal = b.Signal 
+0

Tôi nhận được lỗi "cú pháp lỗi trong từ khoản" lỗi –

+0

@thegreekness: bạn có cần bao gồm AS rõ ràng giữa các bí danh bảng không? mytable AS THAM GIA (CHỌN ...) AS b? Bạn không nên, nhưng ... –

+0

Tôi vừa mới nhận ra - điều kiện ON phải chỉ định một tham gia trên tín hiệu quá. –

3

Trong SQL-92 (không sử dụng các hoạt động OLAP sử dụng bởi Quassnoi), sau đó bạn có thể sử dụng cổ điển:

SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID 
    FROM (SELECT id, MAX(Signal) AS MaxSignal 
      FROM t 
      GROUP BY id) AS g 
     JOIN t ON g.id = t.id AND g.MaxSignal = t.Signal; 

(cú pháp không được kiểm soát; giả bảng của bạn là 't'.)

Truy vấn phụ trong mệnh đề FROM xác định giá trị tín hiệu tối đa cho mỗi id; phép nối kết hợp với hàng dữ liệu tương ứng từ bảng chính. NB: nếu có một số mục nhập cho một ID cụ thể mà tất cả đều có cùng cường độ tín hiệu và cường độ đó là MAX(), thì bạn sẽ nhận được một số hàng đầu ra cho ID đó.


Tested chống lại IBM Informix Dynamic Server 11.50.FC3 chạy trên Solaris 10:

+ CREATE TEMP TABLE signal_info 
(
    id  INTEGER NOT NULL, 
    signal INTEGER NOT NULL, 
    station CHAR(5) NOT NULL, 
    ownerid INTEGER NOT NULL 
); 
+ INSERT INTO signal_info VALUES(111, -120, 'Home', 1); 
+ INSERT INTO signal_info VALUES(111, -130, 'Car' , 1); 
+ INSERT INTO signal_info VALUES(111, -135, 'Work', 2); 
+ INSERT INTO signal_info VALUES(222, -98 , 'Home', 2); 
+ INSERT INTO signal_info VALUES(222, -95 , 'Work', 1); 
+ INSERT INTO signal_info VALUES(222, -103, 'Work', 2); 
+ SELECT g.ID, g.MaxSignal, t.Station, t.OwnerID 
    FROM (SELECT id, MAX(Signal) AS MaxSignal 
      FROM signal_info 
      GROUP BY id) AS g 
     JOIN signal_info AS t ON g.id = t.id AND g.MaxSignal = t.Signal; 

111  -120 Home 1 
222  -95  Work 1 

Tôi đặt tên cho bảng Signal_Info cho thử nghiệm này - nhưng có vẻ như để tạo ra câu trả lời đúng. Điều này chỉ cho thấy có ít nhất một DBMS hỗ trợ ký pháp. Tuy nhiên, tôi hơi ngạc nhiên khi MS SQL Server không - bạn đang sử dụng phiên bản nào?


Nó không bao giờ hết làm tôi ngạc nhiên khi các câu hỏi SQL thường được gửi mà không có tên bảng.

+0

Tôi nhận được lỗi "Lỗi cú pháp trong mệnh đề FROM" và nó trỏ đến JOIN –

14

Bạn đang thực hiện thao tác tối đa/tối thiểu theo nhóm. Đây là một cái bẫy phổ biến: nó cảm thấy giống như một cái gì đó mà nên được dễ dàng để làm, nhưng trong SQL nó aggravatingly không phải là.

Có một số cách tiếp cận (cả tiêu chuẩn ANSI và nhà cung cấp cụ thể) cho vấn đề này, hầu hết trong số đó là tối ưu hóa phụ trong nhiều trường hợp. Một số sẽ cung cấp cho bạn nhiều hàng khi nhiều hơn một hàng chia sẻ cùng một giá trị tối đa/tối thiểu; một số thì không. Một số hoạt động tốt trên các bảng với một số lượng nhỏ các nhóm; những người khác hiệu quả hơn cho một số lượng lớn các nhóm có các hàng nhỏ hơn cho mỗi nhóm.

Here's a discussion một số điểm chung (MySQL thiên vị nhưng thường áp dụng). Cá nhân, nếu tôi biết không có tối đa nhiều (hoặc không quan tâm đến việc nhận chúng), tôi thường có xu hướng hướng đến phương pháp không tham gia tự do, mà tôi sẽ đăng bài như chưa có ai khác:

SELECT reading.ID, reading.Signal, reading.Station, reading.OwnerID 
FROM readings AS reading 
LEFT JOIN readings AS highersignal 
    ON highersignal.ID=reading.ID AND highersignal.Signal>reading.Signal 
WHERE highersignal.ID IS NULL; 
+0

Việc sử dụng bí danh "đọc" và "highersignal" làm cho việc hiểu truy vấn trở nên dễ dàng! Cảm ơn bạn. – Sabuncu

0

Chúng ta có thể làm bằng tự tham gia

SELECT T1.ID,T1.Signal,T2.Station,T2.OwnerID 
FROM (select ID,max(Signal) as Signal from mytable group by ID) T1 
LEFT JOIN mytable T2 
ON T1.ID=T2.ID and T1.Signal=T2.Signal; 

Hoặc bạn cũng có thể sử dụng các truy vấn sau đây

SELECT t0.ID,t0.Signal,t0.Station,t0.OwnerID 
FROM mytable t0 
LEFT JOIN mytable t1 ON t0.ID=t1.ID AND t1.Signal>t0.Signal 
WHERE t1.ID IS NULL; 
2
 

with tab(id, sig, sta, oid) as 
(
select 111 as id, -120 as signal, 'Home' as station, 1 as ownerId union all 
select 111, -130, 'Car', 1 union all 
select 111, -135, 'Work', 2 union all 
select 222, -98, 'Home', 2 union all 
select 222, -95, 'Work', 1 union all 
select 222, -103, 'Work', 2 
) , 
tabG(id, maxS) as 
(
    select id, max(sig) as sig from tab group by id 
) 
select g.*, p.* from tabG g 
cross apply (select top(1) * from tab t where t.id=g.id order by t.sig desc) p 
 
+0

Thêm một số explana – HaveNoDisplayName

0
 
SELECT * FROM StatusTable 
WHERE Signal IN (
    SELECT A.maxSignal FROM 
    (
     SELECT ID, MAX(Signal) AS maxSignal 
     FROM StatusTable 
     GROUP BY ID 
    ) AS A 
); 
Các vấn đề liên quan