2012-09-10 14 views
4

我的道歉問什麼必須要解決很簡單,但我似乎無法總結我的腦海圍繞這個..我甚至不能拿出一個真正適合的標題對於我的問題,請原諒你的赦免。如何讓不同的行與最大值

我有一個調查,其中每個用戶可以張貼多個答案的問題,然後其他人對這些答案進行投票。我需要得到一個結果,其中每個用戶的最高票數答案被返回。

測試用例:「什麼是你最喜歡的歌的報價」讓我們假設一個問題像

CREATE TABLE `answers` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY , 
`authorId` INT, 
`answer` TEXT NOT NULL , 
`votes` INT NOT NULL 
) ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci; 

INSERT INTO `answers` VALUES 
(1, 30, "The West is the Best", 120), 
(2, 30, "Come on, baby, light my fire", 100), 
(3, 31, "Everything's gonna be allright", 350), 
(4, 31, "Sayin' oooh, I love you", 350), 
(5, 31, "Singing sweet songs of melodies pure and true", 290), 
(6, 32, "I'm your pole and all you're wearing is your shoes", 540), 
(7, 32, "And I'm crazier when I'm next to her", 180), 
(8, 32, "You hear the music in the air", 230), 
(9, 30, "You know they are a liar", 190) 

我希望得到的結果是:

id | authorId | answer            | votes 
6 |  32 | I'm your pole and all you're wearing is your shoes | 540 
3 |  31 | Everything's gonna be allright      | 350 
9 |  30 | You know they are a liar       | 190 

基本上我需要選擇每個作者的最佳答案,然後通過投票的最佳答案得到的結果進行排序。可能發生同一作者的兩個答案具有相同數量的選票;那麼應該只選擇第一張(較低的ID)(如回答#3和#4所示)。結果中可能不會出現同一作者的兩個不同答案 - 每個作者可能只贏一次。

我已經搜查,搜查,並試圖,並試圖再次和我覺得很洗腦的那一刻..這可能是因爲這不是一個單一的SQL查詢是可行的;應該是這樣,可能值得指出的是應用程序是用PHP編寫的。我知道我可以只抓住所有的答案與ORDER BY votes desc, id asc,然後遍歷結果,記住所有的authorId S和扔出去與authorId我已經看過任何行,但我需要獲得的記錄一組號碼,這可能會變得尷尬(......如果我查出太多的行等,可能需要再次運行帶有偏移量的查詢)。但最終,如果單一查詢解決方案過於複雜或根本沒有,最終可能是最好的解決方案...

任何想法? :O)

+1

+1包括樣本數據和預期結果。 –

回答

5
SELECT id, authorId, answer, votes 
FROM ( SELECT id, authorId, answer, votes 
     FROM answers 
     ORDER BY votes DESC) AS h 
GROUP BY authorId 

這個小絕招是建立立足於GROUP BY檢索各種情況下的第一行。通常這是默認ORDER BY id ASC,但是通過這個子查詢,每個authorId中的第一行具有最高的votes

注:正如伊恩長老提到,這種解決方案不ONLY_FULL_GROUP_BY積極的工作,只有在MySQL的工作。由於缺乏確認此行爲的文檔,此解決方案在某種程度上不受支持。它對我來說效果很好,但對我來說一直效果不錯。

該方法仍然適用於最新的MySQL on sqlfiddle

+0

+1分享該技巧。吹響我的想法,這是SQL-Server培訓的。 GROUP BY子句是否總是爲分組條件中的選定列產生第一行的值,或者這是否使用ORDER BY子句是特殊情況? –

+0

這是由於'ORDER BY'造成的。否則,它會將GROUP BY作爲表的默認順序,通常按「PRIMARY」排序。基本上沒有子查詢,你會得到最低id行的數據,而不是最高的選票行。 –

+0

非常感謝我(和其他一些人)對GROUP BY語句的教學!我一直認爲選擇不出現在GROUP BY子句中的列僅在列的值對於所有分組行是相等的情況下才有用,否則結果值是不可預測的。我甚至認爲我必須讀過它一個MySQL手冊頁。所以感謝澄清,對我來說:o) –

3

您可以使用子選擇:

select min(a1.id), a1.authorid, a2.mxvotes 
from answers a1 
inner join 
(
    select authorid, max(votes) mxvotes 
    from answers 
    group by authorid 
) a2 
    on a1.authorid = a2.authorid 
    and a1.votes = a2.mxvotes 
group by a1.authorid, a2.mxvotes 
order by mxvotes desc 

看到SQL Fiddle with Demo

+0

非常感謝,應該這樣做。但是,如果我可以擴展我的原始問題:如果要求根據與最低ID不同的標準(例如日期列)選擇具有相同票數的同一作者的多行,然後,我不會得到我想要的答案的ID,而是他們發佈的日期。使用這些ID,獲取其他相關數據以獲得最佳答案很容易,但我如何才能對發佈日期做同樣的事情?顯然可能有重複,日期不一定是唯一的。非常感謝! –

+0

@DanKadera你將不得不發佈一個新的問題與其他細節和更多的樣本數據,這將是猜測基於上面的描述。查看樣本數據和最終預期結果對於解決這些問題非常有幫助。 – Taryn

1

大問題,丹。

MySQL缺乏解析功能,使這個很容易解決。已有人詢問Oracle的similar question,並使用MAX函數的OVER子句解決了這個問題。這也適用於SQL Server。

您需要使用子查詢做到這一點在MySQL。這個工作對我來說:

SELECT 
    id, 
    authorId, 
    answer, 
    votes 
FROM answers AS firsts 
WHERE id = (
    SELECT 
    MIN(id) 
    FROM answers AS favorites 
    WHERE 
    votes = (
     SELECT MAX(votes) 
     FROM answers AS author_max 
     WHERE author_max.authorId = favorites.authorID 
    ) AND 
    favorites.authorId = firsts.authorId 
) 
ORDER BY votes DESC; 

見我sqlfiddle一個可執行的例子。

+0

我很驚訝地發現MySQL在研究這個答案時不支持OVER子句或公用表表達式。我相信這些缺少的語言功能會使分析查詢更難以閱讀。 –

+0

謝謝,isme,這可能比bluefeet的解決方案更容易理解(我仍然主要與GROUP BY語句發生爭執),但我相信它有與bluefeet的答案相同的問題(請參閱我的評論)。 –

0
select * from (select * from answers order by votes desc) as temp group by authorId