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然后遍历结果,记住所有的authorIds 并用我已经看过的任何一行剔除authorId,但我需要获得一定数量的记录,这可能会变得尴尬( ...如果我剔除太多行等,可能需要再次使用偏移量运行查询).. 但最终,如果单查询解决方案过于复杂或根本没有,它可能是最好的解决方案......

有任何想法吗?:o)

4

4 回答 4

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

注意:正如 Iain Elder 所述,此解决方案不适用于ONLY_FULL_GROUP_BYactive,仅适用于 MySQL。由于缺乏确认此行为的文档,此解决方案在一定程度上不受支持。它对我很有效,而且对我来说一直很有效。

此方法仍然适用于 sqlfiddle 上的最新 MySQL

于 2012-09-10T21:30:19.397 回答
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

于 2012-09-10T20:28:14.840 回答
1

好问题,丹。

MySQL 缺乏分析函数来使这个问题很容易解决。一个类似的问题被问到 Oracle 并且使用 OVER 子句和 MAX 函数解决了。这也适用于 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 。

于 2012-09-10T20:52:31.657 回答
0
select * from (select * from answers order by votes desc) as temp group by authorId
于 2012-09-11T15:31:38.143 回答