Mysql 如何对一组有限的可能值进行反规范化/直方图化输出?

Mysql 如何对一组有限的可能值进行反规范化/直方图化输出?,mysql,Mysql,假设我有这张表,假设代表用户(“选民”)对各种对象(如地点、网站、答案等,“选民”)的评级介于一到五星之间(“分数”)。这个问题的更一般的版本是问一对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` tin

假设我有这张表,假设代表用户(“选民”)对各种对象(如地点、网站、答案等,“选民”)的评级介于一到五星之间(“分数”)。这个问题的更一般的版本是问一对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`)
);
我想为每个votee对象构建一个.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格式的数据,我想:

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

  • 它不会将一个对象的所有五个分数合并为一个分数 行/行 (即,数据的非规范化/直方图化)

  • 我只想使用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;
    
    特别是,这让我感觉特别不舒服,因为我使用带有“,”的GROUP_CONCAT将分数组合在一起;然后在别处摆弄,让mysql也用“,”连接所有其他字段,从而为.csv生成正确的格式(摆弄未显示)


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

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

    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
    

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

    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
    

    包装您的原始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;
    

    包装您的原始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;
    

    这肯定是一个更一般的答案,这使它成为我将记住的答案,尽管对于手头的特定问题,我认为Eric的答案更快,因为它避免了子选择。这肯定是一个更一般的答案,这使它成为我将记住的答案,虽然对于手头的特定问题,我认为Eric的答案更快,因为它避免了子选择。