【问题标题】:Multiple join with self join in MySQL and split rows in columns by a row value在 MySQL 中使用自连接进行多重连接并按行值拆分列中的行
【发布时间】:2015-05-04 11:10:58
【问题描述】:

我有三个表 "Users" 、 "Subjects" 和 "Marks" like

用户表

id  name
1   A
2   B
3   C
4   D
5   E
6   A
7   B

科目表

id  name
1   Chemistry
2   Physics
3   English
4   Maths
5   History

分数表

u_id是Users(id)的外键,s_id是Subjects(id)的外键

id  u_id    s_id    marks
 1     1       1     60
 2     1       2     70
 3     1       3     80
 4     2       2     80
 5     2       3     44
 6     3       1     50
 7     5       4     50
 8     4       5     50
 9     5       4    100
10     2       5    100

我希望结果是这样的

id  Name    Chemistry Physics English 
1   A       60        70      80
2   B       NULL      80      44
3   3       50        NULL    NULL

使用连接

到目前为止,我只能得到

name    name        marks
A       English     80
A       Physics     70
A       Chemistry   60
B       English     44
B       Physics     80
C       Chemistry   50

使用以下查询

SELECT u.name, s.name , m.marks
FROM Users as u 
RIGHT JOIN Marks as m ON m.u_id = u.id 
LEFT JOIN Subjects as s ON m.s_id = s.id  
WHERE s.name = "English" 
  OR s.name = "Physics" 
  OR s.name = "Chemistry"
ORDER BY u.name; "

【问题讨论】:

  • 我似乎无法获得所需的结果,因为在不同列中获取 Marks 的值。我使用 select u.name Name, s.name as Subject, m.marks as Marks from Users as u right join Marks as m on m.u_id = u.id left join Subjects as s on m.s_id = s.id其中 s.name = "English" OR s.name = "Physics" OR s.name = "Chemistry" order by u.name;
  • 相应地编辑您的问题。
  • @twitch,看看我做的是不是你想要的,;D

标签: mysql


【解决方案1】:

好吧,在阅读完答案后,我想发布我自己的答案:

SELECT 
  u.id
, u.name

, MAX(IF(s.id = 1, COALESCE(m.mark), 0)) as 'Chem'
, MAX(IF(s.id = 2, COALESCE(m.mark), 0)) as 'Phys'
, MAX(IF(s.id = 3, COALESCE(m.mark), 0)) as 'Eng'

FROM marks m
INNER JOIN subjects s
ON s.id = m.subjects_id
INNER JOIN users u 
ON u.id = m.users_id
GROUP BY u.id

您可以在 SqlFiddle 中检查是否满足您的所有需求:http://sqlfiddle.com/#!9/f567b/1

重要的部分是根据用户ID对所有元素进行分组,以及将结果从一个表中的行写入另一个表中的列的方式。正如@TheShalit 回答中所写,实现这一目标的方法是将值分配为列。问题是,当按用户分组时,您将有很多值,您必须从中选择重要的值(既不是 0 也不是NULL,XD)。 COALESCE 函数确保您始终返回一个整数,以防万一给出 NULL

同样重要的是要注意,您必须使用主题名称和数据库中的 ID 构建 SQL,因为 SQL 无法检索元素的名称来直接将它们写为列的名称。这就是为什么我写了“Chem”、“Phys”和“Eng”而不是正确的名字。事实上,如果您只写主题的 id 而不是名称,会更容易,以便稍后在获取行时检索元素。

考虑到非常重要的一点,您的表将在那里有正确的索引。确保您在表 marks 上有一个 UNIQUE id,其中包含用户和主题,以避免存储多个值

【讨论】:

  • 非常感谢,这几天我一直在摸不着头脑。并且解释帮助我了解了很多新功能,例如“COALESCE”和加入表格的顺序
  • 我很高兴能帮上忙,XD,我也申请了学校,也做过类似的查询。如果您喜欢它,请接受它作为答案,;D
【解决方案2】:

像这样使用选择(按学生加入和分组):

MAX(If(subjects.name="Chemistry",marks.marks,'')) Chemistry,
MAX(If(subjects.name="Physics",marks.marks,'')) Physics,
.....

【讨论】:

  • 我喜欢你的分组查询,他可以这样做,但你为什么使用 MAX?我认为只有 IF 才能做到这一点。
  • no.. 它只占用第一行,所以如果第一行是 Chemistry,Physics 将是一个空字符串
  • 我得到了答案,没有使用 max SELECT u.NAME AS NAME, If(s.​​name="Chemistry",m.marks,'') AS chemistry, If(s.​​name="Physics ",m.marks,'') AS 物理, If(s.​​name="English",m.marks,'') AS english FROM Users AS u JOIN Marks as m on u.id = m.u_id join Subjects as s on m.s_id=s.id;谢谢:)
  • 您需要使用group by u.name,正如我所说的每个学生的一行,而不是您需要max
【解决方案3】:

您需要执行以下操作:

SELECT u.NAME AS NAME,
       m_e.marks AS english,          
       m_p.marks AS physics,
       m_c.marks AS chemistry
FROM users AS u 
JOIN marks AS m_e ON m_e.u_id = u.id 
JOIN marks AS m_p ON m_p.u_id = u.id 
JOIN marks AS m_c ON m_c.u_id = u.id 
WHERE m_e.s_id = 3 AND m_c.s_id = 1 AND m_p.s_id = 2

您从一个表中获得 3 个不同的值但不同的行,因此您需要将标记表与自身连接,以便能够将 3 个不同记录中的值放入 1 个结果行中

我在 where 子句的问题中使用了您为 3 个主题定义的主要 ID 值,以确保您获得每个主题的正确结果

【讨论】:

  • 这只给了我所有主题都存在的价值,比如用户'A'而不是'B'和'C'
猜你喜欢
  • 2012-12-10
  • 1970-01-01
  • 1970-01-01
  • 2021-01-23
  • 2013-11-16
  • 2017-01-19
  • 1970-01-01
  • 2013-11-17
  • 2015-06-11
相关资源
最近更新 更多