我做了功课,并在网络和 StackOverflow 中查找信息,但没有找到问题的答案。我看了:
Creating two colums from rows of a table (没看懂) MySQL join same table display rows in columns way (complicated) (不同,问题看起来不一样) Creating two colums from rows of a table
我用它来构建我的查询:
How to Display rows as Columns in MySQL?
我有一个表“类(class)”,如下所示:
ID title
---------
1 Math
2 Latin
3 English
4 Science
我有第二个表“结果”,用于存储每节课通过的测试用户的类型。目前有两种类型的测试:o 和 w(将来可能会有更多)。表格如下:
lesson_id usr_id test_type course_id
----------------------------------------
1 100 o 1
1 100 w 1
1 24 o 1
1 36 w 1
在上表中,用户 100 通过了数学测试 o 和 w。 在上表中,用户 24 通过了数学测试 o。 在上表中,用户 36 通过了数学测试 w。
现在我想获得用户 100 的报告,我想要如下内容:
ID title o w
------------------------------
1 Math TRUE TRUE
2 Latin FALSE FALSE
3 English FALSE FALSE
4 Science FALSE FALSE
对于用户 36:
ID title o w
------------------------------
1 Math FALSE TRUE
2 Latin FALSE FALSE
...
对于用户 24:
ID title o w
------------------------------
1 Math TRUE FALSE
2 Latin FALSE FALSE
...
任何其他用户:
ID title o w
------------------------------
1 Math FALSE FALSE
2 Latin FALSE FALSE
...
我可以通过如下查询来完成此操作:
SELECT l.id, l.title, COALESCE(s.o,FALSE) AS o, COALESCE(t.w, FALSE) AS w FROM lessons l
LEFT JOIN (
SELECT r.lesson_id,
CASE
WHEN r.test_type='o' THEN TRUE
ELSE FALSE
END AS o
FROM results r WHERE r.itype='o' AND r.usr_id=100
) AS s ON l.id=s.lesson_id
LEFT JOIN (
SELECT rr.lesson_id,
CASE
WHEN rr.test_type='w' THEN TRUE
ELSE FALSE
END AS w
FROM results rr WHERE rr.test_type='w' AND rr.usr_id=100
) AS t ON l.id=t.lesson_id
WHERE l.course_id=1 ORDER BY l.id ASC;
虽然这段代码似乎有效(仍在忙于测试它),但我不喜欢它,因为它需要两个联接,并且每个联接都是由表中的选择组成,该表将来可能会变得相当大。此查询将经常运行
您能否建议一种更好的方法来做到这一点(更好可以意味着更智能、更直接、更快或其他设计......或任何其他建议:-))?
如果我需要坚持这一点,您能否推荐有关如何设置最佳索引以快速运行此查询的引用资料?您使用过的链接、文章?
如果创建更多 test_types 会发生什么?我的查询仅使用 w 和 o 如果明天有更多怎么办?有没有通用的方法来做这种事情?
非常欢迎任何帮助/建议,
菲利普
最佳答案
您尝试执行的操作在其他数据库中称为PIVOT
。不幸的是,MySQL 没有这样的函数,因此您必须使用聚合函数和 CASE
语句来创建一个函数。
如果您知道只有两个 test_type
值,那么您可以对其进行硬编码:
select l.id,
l.title,
max(case when test_type = 'o' then 'true' else 'false' end) as o,
max(case when test_type = 'w' then 'true' else 'false' end) as w
from lessons l
left join results r
on l.id = r.lesson_id
and r.usr_id = 100 -- the user id will change for each person
group by l.id, l.title
现在,如果您想动态执行此操作,这意味着您事先不知道要转置的 test_types
数量,那么您应该查看以下文章:
Dynamic pivot tables (transform rows to columns)
您的代码将如下所示:
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'MAX(CASE WHEN test_type = ''',
test_type,
''' THEN ''true'' ELSE ''false'' END) AS ',
test_type
)
) INTO @sql
FROM Results;
SET @sql
= CONCAT('SELECT l.id,
l.title, ', @sql, '
from lessons l
left join results r
on l.id = r.lesson_id
and r.usr_id = 100
group by l.id, l.title');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
关于MySQL:在与表 A 的联接结果中获取表 B 的行作为列。有比这更聪明/更好的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12308112/