2009-10-09 45 views
5

Câu lệnh SQL thực sự phức tạp mà tôi có ở đây. Đang cố gắng tạo truy vấn này trong khoảng một giờ. Có thể bạn có thể giúp tôi.Truy vấn SQL khó hiểu

Chúng tôi có một bảng có 3 cột: tên trò chơi | người dùng | times_played

Truy vấn nên chọn ba trò chơi hàng đầu (tùy thuộc vào tổng số lần chơi) và ba người dùng hàng đầu đã chơi nhiều lần nhất trong trò chơi này => 9 hàng.

The result is like: 
CounterStrike | Smith 
CounterStrike | Jonny 
Counterstrike | Hans 
WoW   | George 
WoW   | Bob 
Wow   | Frank 
Need For Speed| James 
Need For Speed| Marion 
Need For Speed| Scarlet 

Sẽ rất tuyệt, nếu bạn có thể giúp tôi =) Cảm ơn!

+0

cơ sở dữ liệu là gì? MySQL? SQL Server? Oracle? Postgres? – Asaph

+0

Công nghệ nào? MySQL? SQL Server? Bạn có thể sử dụng thủ tục lưu sẵn không? –

+0

@foriamstu câu hỏi hay hơn: * nên * bạn sử dụng thủ tục được lưu trữ? Theo kinh nghiệm của tôi, hầu như luôn luôn: 'không'. Có vẻ tiện dụng vào thời điểm đó, trở lại để cắn bạn trong việc bảo trì. –

Trả lời

13

Cập nhật:

Như @Steve Kass chỉ ra, tôi không để ý rằng bạn chỉ muốn ba trận đầu tiên.

Dưới đây là phiên bản cập nhật:

Trong SQL Server, OraclePostgreSQL 8.4:

SELECT gamename, user 
FROM (
     SELECT r.gamename, user, 
       ROW_NUMBER() OVER (PARTITION BY game ORDER BY times_played DESC) rn, 
     FROM (
       SELECT gamename, ROW_NUMBER() OVER (ORDER BY SUM(times_played) DESC) AS game_rn 
       FROM results 
       GROUP BY 
         gamename 
       ) g 
     JOIN results r 
     ON  r.gamename = g.gamename 
     WHERE game_rn <= 3 
     ) q 
WHERE rn <= 3 
ORDER BY 
     gamename, times_played DESC 

Trong MySQL:

SELECT ro.gamename, ro.user 
FROM (
     SELECT gamename, SUM(times_played) AS rank 
     FROM results 
     ORDER BY 
       rank DESC 
     LIMIT 3 
     ) rd 
JOIN results ro 
ON  ro.gamename >= rd.gamename 
     AND ro.gamename <= rd.gamename 
     AND 
     (ro.times_played, ro.id) <= 
     (
     SELECT ri.times_played, ri.id 
     FROM results ri 
     WHERE ri.gamename = rd.gamename 
     ORDER BY 
       ri.times_played DESC, ri.id DESC 
     LIMIT 2, 1 
     ) 
ORDER BY 
     gamename, times_played DESC 

Bạn sẽ cần một PRIMARY KEY cho truy vấn này để làm việc, giả sử nó được gọi là id.

này được giải thích chi tiết hơn trong bài viết này trong blog của tôi:

Trong PostgreSQL 8.3 và dưới đây:

SELECT gamename, ((ri)[s]).user 
FROM (
     SELECT gamename, ri, generate_series(1, 3) AS s 
     FROM (
       SELECT ro.gamename, 
         ARRAY 
         (
         SELECT ri 
         FROM results ri 
         WHERE ri.gamename = ro.gamename 
         ORDER BY 
           times_played DESC 
         LIMIT 3 
         ) AS ri 
       FROM (
         SELECT gamename, SUM(times_played) AS rank 
         FROM results 
         ORDER BY 
           rank DESC 
         LIMIT 3 
         ) rd 
       ) q 
     ) q2 
ORDER BY 
     gamename, s 
+3

Nó chỉ có vẻ dễ dàng như vậy khi bạn trả lời :-) –

+0

Tôi cho rằng đó là "PARTITION BY" –

+0

Tôi muốn ném theo thứ tự bởi Game và rn để đảm bảo rằng các kết quả được hiển thị theo đúng thứ tự. –

1

Tôi không nghĩ Quassnoi nhận thấy rằng bạn đã yêu cầu những người dùng hàng đầu chỉ dành cho ba trò chơi hàng đầu (dựa trên tổng số lần chơi). Đây là một truy vấn cho điều đó (không được thử nghiệm trên dữ liệu thực, vì không có câu lệnh CREATE TABLE và INSERT nào được đưa ra). Tôi cũng bao gồm các mối quan hệ, mà Quassnoi đã không, chỉ để cho bạn thấy lựa chọn đó.

with GamesPlays(gamename,totalPlays) as (
    select 
    gamename, sum(times_played) 
    from results 
    group by gamename 
), GamesRanked(gamename,gameRank) as (
    select 
    gamename, 
    rank() over (
     order by totalPlays desc 
    ) 
    from GamesPlays 
), ResultsRanked(gamename,user,userRank) as (
    select 
    gamename, 
    user, 
    rank() over (
     partition by user 
     order by times_played desc 
    ) 
    from results; 
) 
    select 
    G.gamename, R.user 
    from ResultsRanked as R 
    join GamesRanked as G 
    on G.gamename = R.gamename 
    where gameRank <= 3 
    and userRank <= 3 
    order by 
    gameRank,userRank; 
+0

Cảm ơn bạn đã chỉ ra điều đó. Có '12' upvotes và không ai thực hiện nhưng một nhận xét simgle :) – Quassnoi

+0

Có lẽ những gì bạn đăng là rất hiếm khi mà mọi người tìm thấy nó là một sự lãng phí thời gian để xem xét chặt chẽ. :) –

0
DROP TABLE #game_stats 


CREATE TABLE #game_stats (gamename VARCHAR(50),users VARCHAR(50),times_played INT); 

INSERT INTO #game_stats VALUES ('Counter Strike','Kamesh',2); 
INSERT INTO #game_stats VALUES ('Counter Strike','Hely',4); 
INSERT INTO #game_stats VALUES ('Counter Strike','Maitri',1); 
INSERT INTO #game_stats VALUES ('Counter Strike','Laxmi',5); 
INSERT INTO #game_stats VALUES ('WOW','Kamesh',21); 
INSERT INTO #game_stats VALUES ('WOW','laxmi',60); 
INSERT INTO #game_stats VALUES ('WOW','Hely',7); 
INSERT INTO #game_stats VALUES ('NFS','Hely',5); 
INSERT INTO #game_stats VALUES ('NFS','Kamesh',1); 
INSERT INTO #game_stats VALUES ('NFS','Maitri',12); 
INSERT INTO #game_stats VALUES ('NFS','Laxmi',21); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Kamesh',45); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Maitri',52); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Laxmi',21); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Kamesh',41); 
INSERT INTO #game_stats VALUES ('HITMAN','Maitri',142); 
INSERT INTO #game_stats VALUES ('HITMAN','Laxmi',210); 
INSERT INTO #game_stats VALUES ('HITMAN','Kamesh',41); 
INSERT INTO #game_stats VALUES ('HITMAN','Maitri',102); 
INSERT INTO #game_stats VALUES ('HITMAN','Mani',142); 
INSERT INTO #game_stats VALUES ('NFS','Mani',210); 
INSERT INTO #game_stats VALUES ('CODE ZERO','Mani',41); 
INSERT INTO #game_stats VALUES ('WOW','Mani',102); 

select * from #game_stats; 

SELECT RN, 
Gamename, 
Users, 
Times_played 
FROM 
(
    SELECT ROW_NUMBER() OVER (PARTITION BY GS.gamename ORDER BY SUM(GS.times_played) DESC) AS RN, 
     GS.gamename, 
     GS.users, 
     SUM(gs.times_played) as times_played 

FROM #game_stats GS 
WHERE GS.gamename IN (
      SELECT TOP 3 gamename 
          FROM #game_stats 
          GROUP BY gamename 
                   ORDER BY sum(times_played) DESC 
        ) 
GROUP BY GS.gamename,GS.users 
) a 
WHERE RN<=3 
ORDER BY gamename,times_played DESC 
0
SELECT DISTINCT GN,US,GT,UT 
FROM 
(SELECT GN,US,GT,UT, 
     Dense_rank() over(ORDER BY GT DESC) RGT, 
     Dense_rank() over(partition BY GN ORDER BY UT DESC) RUT 
FROM 
    (SELECT gamename GN, 
      users US, 
      times_played TP, 
      sum(times_played) over (partition BY gamename) GT , 
      sum(times_played) over (partition BY gamename,users) UT 
    FROM game_stats)) 
WHERE RGT <4 
AND RUT < 4 
ORDER BY GT DESC, 
     UT DESC 
+0

kiểm tra với cái này –