1

假设我有这张表,假设用户(“投票者”)对各种对象(例如地点、网站、答案等,“投票者”)的评分介于 1 到 5 星之间(“分数”)。这个问题的更通用版本询问如何为一对 N foos 做什么。

mysql> SHOW CREATE TABLE scores;
CREATE TABLE `scores` (
    `voter_id` BIGINT NOT NULL DEFAULT '0',
    `votee_id` BIGINT NOT NULL DEFAULT '0',
    `score` tinyint NOT NULL,
    PRIMARY KEY (`voter_id`,`votee_id`),
    KEY `votee_index` (`votee_id`)
);

我想为每个被投票者对象构建一个 .csv 文件,其中的列表示该对象已获得的一星、二星、三星、四星和五星票的数量,例如

output.csv:
votee_id, count_ones, count_twos, count_threes, count_fours, count_fives
1, 3, 7, 5, 3, 2
...

我知道我可以使用以下查询获取原始数据来支持此表:

SELECT votee_id, score, COUNT(score)
FROM scores
GROUP BY votee_id, score;

这并没有给我我想要的 csv 格式的数据:

  1. 对于给定对象未看到的分数,它不会列出 0。

  2. 它不会将对象的所有五个分数组合成一行/行(即,对数据进行非规范化/直方图)。

我想只使用 mysql 创建输出。

在闲逛了一段时间后,我有以下查询,它有效;但它的效率很低,我找不到/做任何更优雅的东西:

SELECT votee_id, GROUP_CONCAT(COALESCE(score_count, '0') ORDER BY AllUserCrossScore.score ASC)
FROM
    (SELECT votee_id, score FROM
        (SELECT 1 AS score UNION ALL
         SELECT 2 AS score UNION ALL
         SELECT 3 AS score UNION ALL
         SELECT 4 AS score UNION ALL
         SELECT 5 AS score) ScoresEnum

         JOIN

         (SELECT DISTINCT votee_id FROM scores) DistinctIds
    ) AllUserCrossScore

    LEFT JOIN

    (SELECT votee_id, score, COUNT(score) as score_count
     FROM scores
     GROUP BY votee_id, score
    ) ScoreCounts

    USING (votee_id, score)
GROUP BY votee_id;

特别是,这感觉特别 hacky,因为我使用 GROUP_CONCAT 和 ',' 将分数放在一起;然后在其他地方摆弄让mysql也用','加入所有其他字段,从而为.csv产生正确的格式(摆弄未显示)。

在这种情况下,我怎样才能做得更好?

4

2 回答 2

1

我想你正在寻找这样的东西:

SELECT
  votee_id
  SUM(CASE WHEN score = 1 THEN 1 ELSE 0 END) as count_ones
  SUM(CASE WHEN score = 2 THEN 1 ELSE 0 END) as count_twos
  SUM(CASE WHEN score = 3 THEN 1 ELSE 0 END) as count_threes
  SUM(CASE WHEN score = 4 THEN 1 ELSE 0 END) as count_fours
  SUM(CASE WHEN score = 5 THEN 1 ELSE 0 END) as count_fives
FROM scores
GROUP BY votee_id
于 2012-12-17T21:23:19.270 回答
0

包装您的原始 SQL!

SELECT
  votee_id AS votee_id,
  SUM(IF(score=1,count_score,0)) AS count_ones,
  SUM(IF(score=2,count_score,0)) AS count_twos,
  SUM(IF(score=3,count_score,0)) AS count_threes,
  SUM(IF(score=4,count_score,0)) AS count_fours,
  SUM(IF(score=5,count_score,0)) AS count_fives
FROM (
  SELECT votee_id, score, COUNT(score) as count_score
  FROM scores
  GROUP BY votee_id, score
) AS baseview
GROUP BY votee_id;
于 2012-12-17T21:24:13.777 回答