MySQL 将 3 个测验表与按属性/用户计算的总数连接起来

标签 mysql select

我尝试将以下表格合并到一个查询中(最终目标是从 PHP 输出 CSV 文件):

用户

id, name, email
例如。数据

1, John, email@email.com
2, Jane, email@email.com

问题 - 问题的静态列表,每个问题都是存储为“属性”的 3 种类型之一,即单个字母 [A、B、C]

id, text, attribute
例如。数据

1, How cool are dogs?, A
2, How cool are cats?, B
3, How cool are fish?, A
4, How cool are mice?, C
5, How cool are birds?, B

users_questions - 其中答案是整数 [1-5]

id, user_id, question_id, answer
例如。数据

1, 1, 1, 2
2, 1, 2, 5
3, 1, 3, 1
4, 1, 4, 1
5, 1, 5, 4

6, 2, 1, 4
7, 2, 2, 1
8, 2, 3, 3
9, 2, 4, 2
10, 2, 5, 2

期望的结果:

我试图将所有这些数据与按属性分组的每个用户的问题合并为一个查询,因此输出格式如下:

users.id, users.name, users.email    , A_question_total, B_question_total, C_question_total
       1, John      , email@email.com,                3,                9,                1
       2, Jane      , email@email.com,                7,                3,                2

我目前拥有的:

我已经尝试过下面的查询,这些查询几乎都能满足我的需求:

我可以选择连接在一起的所有内容,但这会重复用户和问题,并且不会按用户/属性提供问题总数:

Select * FROM users
JOIN users_questions ON users.id = users_questions.user_id
JOIN questions ON questions.id = users_questions.question_id;

我还可以按用户/属性选择所有问题总数,但随后我必须单独获取用户,然后在 PHP 中将它们连接在一起。

SELECT questions.attribute, users_questions.user_id, SUM(users_questions.answer) AS `total` FROM `questions` LEFT OUTER JOIN `users_questions` ON questions.id = users_questions.`question_id` GROUP BY users_questions.user_id, questions.attribute;

我想知道是否有一种方法可以通过复杂的连接、分组、子查询等在一个查询中完成这一切。我正在努力了解如何组合上述两个查询,并转换每个用户列中本质上单独计算的总“行”。

这是示例数据的 SQL 转储:

DROP TABLE IF EXISTS `questions`;

CREATE TABLE `questions` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `text` varchar(30) DEFAULT NULL,
  `attribute` enum('A','B','C') DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `questions` (`id`, `text`, `attribute`)
VALUES
    (1,'How cool are dogs?','A'),
    (2,'How cool are cats?','B'),
    (3,'How cool are fish?','A'),
    (4,'How cool are mice?','C'),
    (5,'How cool are birds?','B');

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  `email` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `users` (`id`, `name`, `email`)
VALUES
    (1,'John','email@email.com'),
    (2,'Jane','email@email.com');

DROP TABLE IF EXISTS `users_questions`;

CREATE TABLE `users_questions` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) unsigned DEFAULT NULL,
  `question_id` int(11) unsigned DEFAULT NULL,
  `answer` tinyint(1) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `users_questions` (`id`, `user_id`, `question_id`, `answer`)
VALUES
    (1,1,1,2),
    (2,1,2,5),
    (3,1,3,1),
    (4,1,4,1),
    (5,1,5,4),
    (6,2,1,4),
    (7,2,2,1),
    (8,2,3,3),
    (9,2,4,2),
    (10,2,5,2);

感谢任何帮助!

最佳答案

我认为这个查询( SQLFiddle )会解决您的问题:

Select u.id, u.name, u.email, 
SUM(case q.attribute when 'A' then uq.answer else 0 end) as A_question_total,
SUM(case q.attribute when 'B' then uq.answer else 0 end) as B_question_total,
SUM(case q.attribute when 'C' then uq.answer else 0 end) as C_question_total
FROM users u
JOIN users_questions uq ON u.id = uq.user_id
JOIN questions q ON q.id = uq.question_id
group by u.id

输出:

id  name    email               A_question_total    B_question_total    C_question_total
1   John    email@email.com     3                   9                   1
2   Jane    email@email.com     7                   3                   2

关于MySQL 将 3 个测验表与按属性/用户计算的总数连接起来,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49970653/

相关文章:

php - mysql 选择最接近特定位置的纬度/经度

MySQL查询多个年份值

mysql - 当我的所有搜索条件都可以为空时,如何在 MySQL 中找到最新的匹配记录?

全部匹配或全不匹配的 SQL

sql - 没有 WHERE 子句的 SELECT NOT NULL 值

mysql - 用于为论坛索引选择数据的二阶相关表中的 SQL COUNT

php - MySQL 插入超出内存。我是否使用 php 脚本以 block 的形式发送数据?

mysql - 获取 'COUNT'/'GROUP BY' MySQL 查询的空结果

mysql - 同时进行 SELECT 和 UPDATE - 锁定以防止并发问题

MySQL - 使用 LEFT JOIN 会产生意想不到的结果