4个表上的SQL查询:非常复杂?

时间:2011-08-26 07:52:30

标签: mysql sql database doctrine

我有四张桌子

alert:
    * monitor_id
    * group_id

group:
    * group_id

user:
    * user_id
    * email

user_group:
    * group_id
    * user_id

是否可以仅使用monitor_id来获取用户的邮件? 如是!只有一个查询可以吗? 请通过sql查询或学说帮助我!

3 个答案:

答案 0 :(得分:3)

正确的查询:

SELECT DISTINCT user.email FROM user 
inner join user_group on user.user_id=user_group.user_id 
inner join alert on  alert.group_id=user_group.group_id
where alert.monitor_id = provided_monitor_id

上一篇与Shahbaz的评论。

SELECT * FROM user inner join user_group on user.user_id=user_group.user_id 
inner join  group on user_group.group_id=group.group_id inner 
join alert on  alert.group_id=group.group_id
group by user.user_id

编辑(Shahbaz):帮助解释命令的工作原理:

如果你有两个表共享一个字段(如果你愿意,你可以使用一个变量),你可以join这两个表(也称为inner join),从而产生一个更大的表来组合两个数据表(如果没有共享字段,你甚至可以这样做)。让我们通过一个例子来说明这一点:

表人物:字段:pid,pname,pjob

带条目

  • (0,'爱丽丝','学生')
  • (1,'Bob','工厂工人')
  • (2,'clara','护士')

表格工作:字段:jname,jpay

带条目

  • ('老师',1000)
  • ('student',0)
  • ('工厂工人',2000年)

现在,如果您说People join Jobs,您将获得一个包含9个条目的表格,其中包含:

字段:pid,pname,pjob,jname,jpay

带条目

  • (0,'爱丽丝','学生','老师',1000)
  • (0,'爱丽丝','学生','学生',0)
  • (0,'爱丽丝','学生','工厂工人',2000)
  • (1,'Bob','工厂工人','老师',1000)
  • (1,'Bob','工厂工人','学生',0)
  • (1,'Bob','工厂工人','工厂工人',2000)
  • (2,'Clara','护士','老师',1000)
  • (2,'Clara','护士','学生',0)
  • (2,'Clara','护士','工厂工人',2000)

正如你所看到的,这不是一张好桌子!您可以使用on中的join条件来提取彼此相关的信息。例如,我们可能希望看到每个人的工资。因此,People.pjob应该等于Jobs.jname,所以如果你说People join Jobs on People.pjob=Jobs.jname你得到一张表:

字段:pid,pname,pjob,jname,jpay

带条目

  • (0,'爱丽丝','学生','学生',0)
  • (1,'Bob','工厂工人','工厂工人',2000)

请注意,Clara的工作在Jobs表中不存在,因此她没有出现在决赛桌中。

虽然inner join为您提供了匹配的两个表中的数据,但即使另一方没有匹配,您也可能希望获取表的数据。这称为outer join。在此示例中,People outer join Jobs生成一个具有

的表

字段:pid,pname,pjob,jname,jpay

带条目

  • (0,'爱丽丝','学生','学生',0)
  • (1,'Bob','工厂工人','工厂工人',2000)
  • (2,'Clara','护士',nullnull
  • nullnullnull,'老师',1000)

如果您只希望包含outer join左侧的表格,即使不匹配,也请使用left outer join(在这种情况下,“Clara”行将出现,而不是'老师'排)。同样,即使不匹配,right outer join也会从右表中提供行,而不是左表。

最后,您必须已经知道select的作用,它只返回一个包含所提供列中所选列的表(*选择所有列)。给定的表可以只是表的名称,也可以是用sql命令形成的任何其他表(使用select命令本身创建的表(在这种情况下不要犹豫使用括号),表创建{{1命令等)。如果您了解SQL的这种递归特性,则可以根据需要创建复杂的命令。想象一下,对表的每个操作产生另一个表,您可以简单地将其与其他操作一起使用,就像该表是一个简单存储的命名表一样!

答案 1 :(得分:3)

如果您想使用monitor_id获取用户的电子邮件,请执行以下操作:

SELECT DISTINCT
  u.user_id
  u.email
FROM `user` u
INNER JOIN user_group ug ON u.user_id = ug.user_id 
INNER JOIN `group` g ON ug.group_id = g.group_id 
INNER JOIN alert a ON a.group_id = g.group_id
WHERE a.monitor_id = '1548'

因为从monitor_id到user.email的路径遍历所有表,所以你需要所有这些连接 只要你有索引(!)连接中使用的所有字段,运行时应该很快。

答案 2 :(得分:0)

另一种方式(不使用DISTINCTGROUP BY):

SELECT 
    u.user_id
  , u.email
FROM `user` AS u
WHERE EXISTS
      ( SELECT *
        FROM alert AS a 
          JOIN `group` AS g
            ON g.group_id = a.group_id 
          JOIN user_group AS ug
            ON ug.group_id = g.group_id
        WHERE ug.user_id = u.user_id 
          AND a.monitor_id = @monitorId      -- the monintor_id to be checked
      ) 

注意:将表格或字段命名为关键字或保留字(如user,甚至更差group)并不是一种好习惯。