2008-11-04 45 views
8

Tôi có một danh sách các cửa hàng, phòng ban trong các cửa hàng và bán hàng cho từng bộ phận, như vậy (được tạo bằng cách sử dụng tối đa (bán hàng) trong truy vấn con, nhưng điều đó không quan trọng lắm ở đây.):Max of Sum trong SQL

toronto baskets 500 
vancouver baskets 350 
halifax baskets 100 
toronto noodles 275 
vancouver noodles 390 
halifax noodles 120 
halifax fish 200 

Tôi muốn hỏi bộ phận bán chạy nhất tại mỗi cửa hàng. Kết quả sẽ như sau:

toronto baskets 500 
vancouver noodles 275 
halifax fish 200 

Bất cứ khi nào tôi sử dụng GROUP BY, nó bao gồm tất cả các danh sách từ truy vấn phụ của tôi. Có một cách sạch đẹp để làm điều này mà không có một bảng tạm thời?

+0

Nền tảng cơ sở dữ liệu nào? sql server? oracle? – TheSoftwareJedi

+0

người đã nghĩ rằng mì sẽ rất phổ biến ở vancouver, eh? – TheSoftwareJedi

+0

Đó là "chọn một người chiến thắng" một lần nữa. http://stackoverflow.com/questions/246870/simple-sql-query –

Trả lời

2

này hoạt động trong Oracle, triển khai khác có thể có cú pháp khác nhau cho các chức năng phân tích (hoặc thiếu chúng hoàn toàn):

select store 
    , max(department) keep(dense_rank last order by sales) 
    , max(sales) 
    from (
     ...query that generates your results... 
     ) 
group by store 
+0

Vâng, tôi sẽ đề xuất điều đó, nhưng tôi nghĩ rằng anh ấy đang sử dụng SQL Server (như bất kỳ ai sử dụng oracle sẽ chỉ định ...) – TheSoftwareJedi

1

này sẽ làm việc trong SQL Server, tính đến năm 2005:

with data as 
(select store, department, sales 
from <your query>), 
maxsales as 
(select store, sales = max(sales) 
from data 
group by store) 
select store, (select top 1 department from data where store = t.store and sales = t.sales order by [your criteria for ties]), sales 
from maxsales m 

Tôi giả sử bạn chỉ muốn hiển thị 1 bộ phận trong trường hợp quan hệ, do đó đầu tiên 1 và [tiêu chí của bạn cho các mối quan hệ] để phân biệt giữa chúng.

0

Có thể điều này có thể hiệu quả. Đã không thử nó, mặc dù có thể có một giải pháp tốt hơn ...

select yourTable.store, dept, sales 
from yourTable 
join (
    select store, max(sales) as maxSales from yourTable group by store 
) tempTable on tempTable.store = yourTable.store 
      and tempTable.maxSales = yourTable.sales 
+0

Rất tiếc, tôi đã đăng một giải pháp tương tự vài phút. Truy vấn này sẽ không chạy đã đăng. Các) trước khi nhóm bởi đã đi, tối đa (bán hàng) trong tempTable không có tên và các cột trong sự lựa chọn cần phải xác định nguồn của họ. Không muốn hậu môn, nhưng nếu ai đó đến sau, tôi muốn nó rõ ràng. – Pete

+0

ok, tôi đã sửa nó, cảm ơn vì đã chú ý – Rockcoder

4

này hoạt động trong SQL Server (2000 trở lên cho chắc chắn)

SELECT a.Store, a.Department, a.Sales 
FROM temp a 
INNER JOIN 
(SELECT store, max(sales) as sales 
FROM temp 
GROUP BY Store) b 
ON a.Store = b.Store AND a.Sales = b.Sales; 
0

này sẽ làm việc trong SQL Server mà không cần tạm thời bảng:

SELECT Store, Department, Sales FROM 
(SELECT Store, Department, Sales, 
DENSE_RANK() OVER (PARTITION BY Store 
ORDER BY Sales DESC) AS Dense_Rank 
FROM Sales) A WHERE Dense_Rank = 1 

WHERE "bán hàng" = truy vấn ban đầu của bạn

+0

Giải pháp này là SQL 2005 trở lên mà thôi. –

0

này sẽ làm việc

Select Store, Department, Sales 
From yourTable A 
Where Sales = (Select Max(Sales) 
       From YourTable 
       Where Store = A.Store) 
2

Giải pháp 2 của tôi cho SQL 2005 dưới đây. Những cái khác tôi có thể thấy cho đến nay có thể không trả lại dữ liệu chính xác nếu hai trong số các số liệu bán hàng giống nhau. Điều đó phụ thuộc vào nhu cầu của bạn mặc dù.

Đầu tiên sử dụng hàm Row_Number(), tất cả các hàng được xếp hạng từ mức thấp nhất đến doanh số cao nhất (sau đó là một số quy tắc ràng buộc). Sau đó, thứ hạng cao nhất được chọn cho mỗi cửa hàng để có được kết quả.

Bạn có thể thử thêm mệnh đề Partion By vào hàm Row_Number (xem BOL) và/hoặc điều tra bằng cách sử dụng phép nối bên trong thay vì mệnh đề "in".

Thứ hai, mượn ý tưởng của chìa khóa trao tay, lại xếp hạng chúng, nhưng phân vùng theo cửa hàng, vì vậy chúng tôi có thể chọn xếp hạng đầu tiên. Dense_Rank có thể sẽ cung cấp cho hai hàng giống hệt nhau cùng một cấp bậc, vì vậy nếu cửa hàng và bộ phận không phải là duy nhất, nó có thể trả về hai hàng. Với Row_number số là duy nhất trong phân vùng.

Một số điều cần lưu ý là điều này có thể chậm, nhưng sẽ nhanh hơn đối với hầu hết các tập dữ liệu hơn truy vấn phụ trong một trong các giải pháp khác. Trong giải pháp đó, truy vấn sẽ phải được chạy một lần cho mỗi hàng (bao gồm cả phân loại vv), có thể dẫn đến nhiều truy vấn.

Truy vấn khác chọn doanh số tối đa trên mỗi cửa hàng và trả lại dữ liệu theo cách đó, trả lại hàng trùng lặp cho một cửa hàng nếu hai phòng ban có cùng doanh số bán hàng. Truy vấn cuối cùng cho thấy điều này.

DECLARE @tbl as TABLE (store varchar(20), department varchar(20), sales int) 

INSERT INTO @tbl VALUES ('Toronto', 'Baskets', 500) 
INSERT INTO @tbl VALUES ('Toronto', 'Noodles', 500) 
INSERT INTO @tbl VALUES ('Toronto', 'Fish', 300) 
INSERT INTO @tbl VALUES ('Halifax', 'Fish', 300) 
INSERT INTO @tbl VALUES ('Halifax', 'Baskets', 200) 

-- Expect Toronto/Noodles/500 and Halifax/Fish/300 

;WITH ranked AS -- Rank the rows by sales from 1 to x 
(
    SELECT 
     ROW_NUMBER() OVER (ORDER BY sales, store, department) as 'rank', 
     store, department, sales 
    FROM @tbl 
) 

SELECT store, department, sales 
FROM ranked 
WHERE rank in (
    SELECT max(rank) -- chose the highest ranked per store 
    FROM ranked 
    GROUP BY store 
) 

-- Another way 
SELECT store, department, sales 
FROM (
    SELECT 
     DENSE_RANK() OVER (PARTITION BY store ORDER BY sales desc, 
store desc, department desc) as 'rank', 
     store, department, sales 
    FROM @tbl 
) tbl 
WHERE rank = 1 


-- This will bring back 2 rows for Toronto 
select tbl.store, department, sales 
from @tbl tbl 
    join (
     select store, max(sales) as maxSales from @tbl group by store 
    ) tempTable on tempTable.store = tbl.store 
      and tempTable.maxSales = tbl.sales