MySQL:在与表A连接的结果中将表B的行作为列。比这更聪明/更好的方法?
我做了家庭作业,在网上和StackOverflow上查找信息,但没有找到问题的答案。我看了看: (不明白) (不同,问题似乎不一样) 我用它来构建我的查询: 我有一张“课程”表,如下所示:MySQL:在与表A连接的结果中将表B的行作为列。比这更聪明/更好的方法?,mysql,row,left-join,identity-column,Mysql,Row,Left Join,Identity Column,我做了家庭作业,在网上和StackOverflow上查找信息,但没有找到问题的答案。我看了看: (不明白) (不同,问题似乎不一样) 我用它来构建我的查询: 我有一张“课程”表,如下所示: ID title --------- 1 Math 2 Latin 3 English 4 Science lesson_id usr_id test_type course_id ---------------------------------------- 1
ID title
---------
1 Math
2 Latin
3 English
4 Science
lesson_id usr_id test_type course_id
----------------------------------------
1 100 o 1
1 100 w 1
1 24 o 1
1 36 w 1
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;
我还有第二个表“results”,它存储了用户在每节课中通过的测试类型。目前有两种类型的测试:o和w(将来可能会有更多)。表格如下所示:
ID title
---------
1 Math
2 Latin
3 English
4 Science
lesson_id usr_id test_type course_id
----------------------------------------
1 100 o 1
1 100 w 1
1 24 o 1
1 36 w 1
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;
在上表中,用户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;
虽然这段代码似乎可以工作(仍在忙于测试),但我不喜欢它,因为它需要两个连接,每个连接都是从一个表中选择的,将来可能会非常大。此查询将经常运行
Philippe我认为这是一个简单的聚合查询。聚合是按课程id和标题进行的。然后,计算仅旋转o和w的结果:
select l.lesson_id, l.title,
max(case when r.test_type = 'o' then 'TRUE' else 'FALSE' end) as o,
max(case when r.test_type = 'w' then 'TRUE' else 'FALSE' end) as w
from lessons l left outer join
results r
on l.lesson_id = r.lesson_id
where r.user_id = <whatever>
group by l.lesson_id, l.title
order by 1
选择l.lesson\u id,l.title,
max(r.test_type='o'然后'TRUE'或'FALSE'结束时的情况)为o,
最大值(r.test_type='w'然后'TRUE'或'FALSE'结束时的情况)为w
从课上我离开了外接
结果r
在l.lesson_id=r.lesson_id上
其中r.user\u id=
按l.lesson_id、l.title分组
按1订购
用户在此级别进行选择是一个问题,因为它需要来自结果,由于左外部联接,结果可能为空。以下是一个解决问题的变体:
select l.lesson_id, l.title,
max(case when r.test_type = 'o' then 'TRUE' else 'FALSE' end) as o,
max(case when r.test_type = 'w' then 'TRUE' else 'FALSE' end) as w
from lessons l left outer join
results r
on l.lesson_id = r.lesson_id and
r.user_id = <whatever>
group by l.lesson_id, l.title
order by 1
选择l.lesson\u id,l.title,
max(r.test_type='o'然后'TRUE'或'FALSE'结束时的情况)为o,
最大值(r.test_type='w'然后'TRUE'或'FALSE'结束时的情况)为w
从课上我离开了外接
结果r
关于l.lesson_id=r.lesson_id和
r、 用户id=
按l.lesson_id、l.title分组
按1订购
通过将条件移动到“on”子句,我们可以保证所有课程都将保留。您尝试执行的操作在其他数据库中称为
透视。不幸的是,MySQL没有,因此您必须使用聚合函数和CASE
语句创建一个
如果您知道只有两个test\u 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\u类型的数量,那么您应该阅读以下文章:
您的代码如下所示:
ID title
---------
1 Math
2 Latin
3 English
4 Science
lesson_id usr_id test_type course_id
----------------------------------------
1 100 o 1
1 100 w 1
1 24 o 1
1 36 w 1
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;
请参见我尝试了该查询,并提出了一些其他问题:1.如果用户是100(如上例所示),则似乎只返回第一行(其中o和w为true)。理想情况下,我也希望有所有其他的课程,我会再次加入这个课程。。。但这将使更多的人加入,虽然是一个小的。2.我理解max(),很有趣。但是你能解释一下为什么是分组和点菜吗?谢谢,太好了!它起作用了。看来我可以从更多的SQL阅读中获益。“使用SQL和Excel进行数据分析”正在回家的路上。非常感谢。