Mariadb 如何使用SQL和多重连接或合并它们

Mariadb 如何使用SQL和多重连接或合并它们,mariadb,many-to-many,Mariadb,Many To Many,我需要从表中检索事件,包括技能要求、用户参与和技能 对于一个项目,我有: 用户表 从其他技能继承的技能表 包含用户技能的用户技能表 事件表 包含事件所需技能数量的事件技能表 包含用户参与事件的events_users表 我想检索所有事件,包括技能要求和用户参与 我的第一个想法是使用左连接: SELECT e.id, e.name, es.skill_id, s.name skill_name, es.quantity, eu.user_id, u.name user_nam

我需要从表中检索事件,包括技能要求、用户参与和技能

对于一个项目,我有:

  • 用户表
  • 从其他技能继承的技能表
  • 包含用户技能的用户技能表
  • 事件表
  • 包含事件所需技能数量的事件技能表
  • 包含用户参与事件的events_users表
我想检索所有事件,包括技能要求和用户参与

我的第一个想法是使用左连接:

SELECT  e.id, e.name, es.skill_id, s.name skill_name, es.quantity,
        eu.user_id, u.name user_name, us.skill_id user_skill_id,
        uss.name user_skill_name
    FROM  events e
    LEFT JOIN  events_skills es  ON es.event_id = e.id
    LEFT JOIN  skills s  ON s.id = es.skill_id
    LEFT JOIN  events_users eu  ON eu.event_id = e.id
    LEFT JOIN  users u  ON u.id = eu.user_id
    LEFT JOIN  users_skills us  ON us.user_id = u.id
    LEFT JOIN  skills uss  ON uss.id = us.skill_id;

id  name    skill_id    skill_name  quantity    user_id user_name   user_skill_id   user_skill_name
1   eve1    2           ski2        3           1       use1        2               ski2
1   eve1    3           ski2-2      1           1       use1        2               ski2
1   eve1    2           ski2        3           2       use2        NULL            NULL
1   eve1    3           ski2-2      1           2       use2        NULL            NULL
2   eve2    NULL        NULL        NULL        NULL    NULL        NULL            NULL
2个不同的事件,第二个没有用户和技能。首先,有两个用户,第一个有一个技能,第二个没有技能,最后是两个技能要求

它工作“很好”,但它非常难看,我认为如果一个事件或用户有太多的技能,它可能会非常慢。 而且,每个事件都有很多行,很难对它们进行排序(如果我只想显示20个事件…)

为了改进,我想我可以分别加载所有技能,并删除表技能的两个左连接

但是,我可以将所有技能和数量合并到一个列中,将用户合并到其他列中吗?您是否有更好的解决方案/改进

id  name    skills  users
1   eve1    2,3;3,1 1,2;2,NULL
2   eve2    NULL    NULL

谢谢您的帮助。

将技能和用户作为逗号分隔字符串的结果也正是我要做的。为此,请使用
GROUP\u CONCAT

select e.*, s.skills, u.users
from events e
left join
(
  select event_id, group_concat(skill_id order by skill_id separator ',') as skills
  from events_skills
  group by event_id
) s on s.event_id = e.id
left join
(
  select event_id, group_concat(user_id order by user_id separator ',') as users
  from events_users
  group by event_id
) u on u.event_id = e.id
order by e.id;

将技能和用户作为逗号分隔字符串的结果也正是我要做的。为此,请使用
GROUP\u CONCAT

select e.*, s.skills, u.users
from events e
left join
(
  select event_id, group_concat(skill_id order by skill_id separator ',') as skills
  from events_skills
  group by event_id
) s on s.event_id = e.id
left join
(
  select event_id, group_concat(user_id order by user_id separator ',') as users
  from events_users
  group by event_id
) u on u.event_id = e.id
order by e.id;

Thorsten建议的另一种方法:

select  e.*, 
        ( SELECT  group_concat(skill_id order by  skill_id separator ',')
            from  events_skills
            WHERE  event_id = e.id 
        ) AS skills, 
        ( SELECT  group_concat(user_id order by  user_id separator ',' )
            from  events_users
            WHERE  event_id = e.id 
        ) AS users
    from  events e
    order by  e.id;
每个子查询都需要一个额外的连接来获取技能和用户的“名称”,而不是“id”

我建议您使用该技能的名称作为其id


当您有多个映射表时,请确保使用一对
id
作为
主键
,并按相反顺序使用
索引
。并且没有
自动增量
。详细信息:

托尔斯滕建议的另一种方法:

select  e.*, 
        ( SELECT  group_concat(skill_id order by  skill_id separator ',')
            from  events_skills
            WHERE  event_id = e.id 
        ) AS skills, 
        ( SELECT  group_concat(user_id order by  user_id separator ',' )
            from  events_users
            WHERE  event_id = e.id 
        ) AS users
    from  events e
    order by  e.id;
每个子查询都需要一个额外的连接来获取技能和用户的“名称”,而不是“id”

我建议您使用该技能的名称作为其id


当您有多个映射表时,请确保使用一对
id
作为
主键
,并按相反顺序使用
索引
。并且没有
自动增量
。详情:

谢谢。性能如何?如果我理解的话,每行都会进行子选择。如果我有大的表,我想要所有事件表,它可能比“Thorsten Kettner”慢,但如果我只想要几行,它可能会更好?@Lortet-Oops,我忘了建议索引。见补充。至于哪个更快,两个都试试。(这可能取决于您使用的是哪个版本的MariaDB。)谢谢。性能如何?如果我理解的话,每行都会进行子选择。如果我有大的表,我想要所有事件表,它可能比“Thorsten Kettner”慢,但如果我只想要几行,它可能会更好?@Lortet-Oops,我忘了建议索引。见补充。至于哪个更快,两个都试试。(这可能取决于您使用的是哪个版本的MariaDB。)谢谢。性能如何?若我理解的话,连接选择只执行一次,但使用表中的所有数据。如果我有大的表,但我想要所有事件表,它可以比“Rock James”快,但如果我只需要几行,它可以慢一些?这在很大程度上取决于DBMS哪个版本更快。完美的DBMS将看到两个查询选择完全相同的数据,因此它将为这两个查询提供相同的执行计划。但是是的,很可能是我的查询在整个表上更快,而Rick的查询在几行上更快。试试看。除此之外,不要太担心性能。我不期望在运行查询时有很大的不同。因此,从外观上决定你更喜欢哪一个:-)没有一个比另一个更好,这只是两种不同的有效方法。@Lortet-在MySQL/MariaDB的旧版本中,
LEFT JOIN(SELECT…
会重复计算子查询。真糟糕。但在今天的版本中,托尔斯滕和里克之间可能是一场较量。谢谢。性能如何?若我理解的话,连接选择只执行一次,但使用表中的所有数据。如果我有大的表,但我想要所有事件表,它可以比“Rock James”快,但如果我只需要几行,它可以慢一些?这在很大程度上取决于DBMS哪个版本更快。完美的DBMS将看到两个查询选择完全相同的数据,因此它将为这两个查询提供相同的执行计划。但是是的,很可能是我的查询在整个表上更快,而Rick的查询在几行上更快。试试看。除此之外,不要太担心性能。我不期望在运行查询时有很大的不同。因此,从外观上决定你更喜欢哪一个:-)没有一个比另一个更好,这只是两种不同的有效方法。@Lortet-在MySQL/MariaDB的旧版本中,
LEFT JOIN(SELECT…
会重复计算子查询。真糟糕。但在今天的版本中,托尔斯滕和里克之间可能会有分歧。