加入涉及多个关联的集成查询

时间:2015-08-30 18:19:35

标签: mysql join left-join

我在dba上发布了这个,但我没有得到任何回复所以我在这里添加了它。

这是我的SQLFiddle

我在修复此查询时需要一些帮助。这个问题很简单,但我还是无法解决。让我解释它目前的工作背景,然后解释我需要整合的内容。

首先,这是我目前的表格。

用户(表演者)表

users表列出了所有用户。我们将假设此查询所有选定的用户都是类型执行者。

users
-----------
id
hash
first_name
last_name

这是users表的转储:

id  hash                              first_name  last_name  
 1  092ee63c6698851ba72183388bff1b3b  Jonathan    Kushner    
 2  2d234affe1d08c3394cd499f297d7380  Dustin      Kushner   

别名表

别名表列出了所有别名。我们将此表连接到另一个表中的表演者。

aliases
----------
id
hash
title

这是别名表的转储:

id  hash             title       
 1  436etgfgdggdd    Greatness
 2  54645655gggdgdg  Mr.Darkness
 3  ffsafsdsfdfdssf  Mr.Shadow

performers_aliases表

performers_aliases表将类型执行者的用户连接到别名表中的别名。

performers_aliases
----------
id
hash
performer_id (connects to the users.id column)
alias_id

这里是performers_aliases表的转储:

id  hash             performer_id  alias_id  
 1  dsaadsasdadsads             1           1
 2  d4544534553                 2           2
 3  adfasdadsadsa               2           3

视频表

视频表列出了所有视频。

videos
----------
id
hash
title

这是视频表的转储:

id  hash                             title       
 1  89efaed413163be4557133266ce295b4 crazy sports blooper

videos_performers

视频表演者表将视频连接到表演者类型的用户。

videos_performers
----------
id
hash
video_id
performer_id (connects to the users.id column)

继承了视频表演者的表:

id  hash                              video_id  performer_id  
 1  3a7e0f543af5152c623ad8156079bb73         1               1
 2  c0abf5f50f6382c744a9359d7dbc4c8c         1               2

行。现在让我告诉你我当前的疑问:

    SELECT        
      `users`.`first_name`,
      `users`.`last_name`,
      `aliases`.`title` AS `alias`,
      `videos`.`title` AS `video`
    FROM
      `users` 
      LEFT JOIN `performers_aliases` 
        ON `performers_aliases`.`performer_id` = `users`.`id` 
      LEFT JOIN `aliases` 
        ON `aliases`.`id` = `performers_aliases`.`alias_id` 
      LEFT JOIN `videos_performers` 
        ON `videos_performers`.`performer_id` = `users`.`id` 
      LEFT JOIN `videos` 
        ON `videos`.`id` = `videos_performers`.`video_id`  
    WHERE (
        `videos`.`hash` = '89efaed413163be4557133266ce295b4'
      ) 
    ORDER BY `users`.`last_name` ASC

此查询执行以下操作:

  • 选择视频表演者。我们需要包含别名表来获取表演者别名。 (注意:表演者可以有多个别名)

这是一个结果集:

first_name  last_name  alias        video
Jonathan    Kushner    Greatness    crazy sports blooper
Dustin      Kushner    Mr.Darkness  crazy sports blooper
Dustin      Kushner    Mr.Shadow    crazy sports blooper

正如您所看到的,此视频包含2位表演者--Jonathan Kushner和Dustin Kushner。但是,Dustin有2个别名,所以它有2个记录

我想做的是将视频表演者通过别名连接到视频,因此他没有为Dustin创建2条记录,因为他有2个别名,它只会连接到用于的别名该特定视频。

例如,此视频的输出为:

first_name  last_name  alias        video
Jonathan    Kushner    Greatness    crazy sports blooper
Dustin      Kushner    Mr.Darkness  crazy sports blooper

此结果集现在只显示2个记录,一个用于Dustin作为Mr.Darkness,一个用于Jonathan作为Greatness。你会注意到,由于Mr.Shadow没有被用作该视频的别名,因此不再存在Dustin作为Mr.Shadow的记录。

这是我目前关于如何解决这个问题的工作。我创建了一个videos_performers_aliases表,用于将视频与表演者连接到别名。 我不认为我需要performer_id列,但无论如何都喜欢它。我认为重要的是视频别名连接。

videos_performers_aliases
--------------------
id
hash
video_id
performer_id
alias_id

以下是videos_performers_aliases表的转储:

    id  hash                   video_id  performer_id  alias_id         
     1  fdsa97asd987das7das97         1             1         1  
     2  dfdfsdfsfdsdfsdfsfd           1             2         2

然后我会按如下方式修改上面的查询:

    SELECT        
      `users`.`first_name`,
      `users`.`last_name`,
      `aliases`.`title` AS `alias`,
      `videos`.`title` AS `video`
    FROM
      `users` 
      LEFT JOIN `performers_aliases` 
        ON `performers_aliases`.`performer_id` = `users`.`id` 
      LEFT JOIN `aliases` 
        ON `aliases`.`id` = `performers_aliases`.`alias_id` 
      LEFT JOIN `videos_performers` 
        ON `videos_performers`.`performer_id` = `users`.`id` 
      LEFT JOIN `videos` 
        ON `videos`.`id` = `videos_performers`.`video_id`
      LEFT JOIN `videos_performers_aliases`
        ON `videos_performers_aliases`.`video_id` = `videos`.`id`
    WHERE (
        `videos`.`hash` = '89efaed413163be4557133266ce295b4'
      ) 
    ORDER BY `users`.`last_name` ASC

如您所见,我将此添加到查询中:

LEFT JOIN `videos_performers_aliases`
        ON `videos_performers_aliases`.`video_id` = `videos`.`id`

我希望我的输出如下:

first_name  last_name  alias        video
Jonathan    Kushner    Greatness    crazy sports blooper
Dustin      Kushner    Mr.Darkness  crazy sports blooper

这暗示我们有一位表演者是达斯特先生,一位表演者是伟大的。如您所见,Mr.Shadow不在结果集中。

不幸的是,这里的结果集仍然是:

first_name  last_name  alias        video
Jonathan    Kushner    Greatness    crazy sports blooper
Dustin      Kushner    Mr.Darkness  crazy sports blooper
Dustin      Kushner    Mr.Shadow    crazy sports blooper

就我而言,这是最重要的。

任何帮助都将不胜感激。

1 个答案:

答案 0 :(得分:1)

您表达查询的方式中缺少的部分是videos_perfomers_aliases联接中的另一个条件,即将其加入videos.idaliases.id表。

LEFT JOIN `videos_performers_aliases`
  ON `videos_performers_aliases`.`video_id` = `videos`.`id`
  AND `videos_performers_aliases`.`alias_id` = `aliases`.id`

但是,使用LEFT JOIN实际上会导致返回两个别名。而使用INNER JOIN将仅返回连接的别名。

INNER JOIN `videos_performers_aliases`
  ON `videos_performers_aliases`.`video_id` = `videos`.`id`
  AND `videos_performers_aliases`.`alias_id` = `aliases`.id`

以下是修改后的版本以生成预期结果:http://sqlfiddle.com/#!9/ec26c/21

更好,连接次数更少:

但整个查询可以简化。由于videos_performers_aliases已包含视频和别名信息,因此它会为此查询(以及其他人)呈现videos_performers表格。您可以使用此链执行整个查询:

users(id) --> (performer_id)performers_aliases(alias_id) --> (id)aliases(id) --> (alias_id)videos_performers_aliases(video_id) --> (id)videos

因此可以消除其中一个连接,并使用videos_performers_aliases简化连接条件,只需要一个部分。

SELECT
  `users`.`first_name`,
  `users`.`last_name`,
  `aliases`.`title` AS alias,
  `videos`.`title` AS video
FROM
  `users` 
  LEFT JOIN `performers_aliases` 
    ON `performers_aliases`.`performer_id` = `users`.`id` 
  LEFT JOIN `aliases` 
    ON `aliases`.`id` = `performers_aliases`.`alias_id` 
  LEFT JOIN `videos_performers_aliases`
    ON videos_performers_aliases.alias_id = aliases.id
  LEFT JOIN `videos`
    ON `videos`.id = videos_performers_aliases.video_id
WHERE (
  `videos`.`hash` = '89efaed413163be4557133266ce295b4'
) 
ORDER BY `users`.`last_name` ASC

此处正在运行,产生您的预期结果:http://sqlfiddle.com/#!9/ec26c/19

关于videos_performers_aliases,你说:

  

我认为我不需要performer_id列,但无论如何都喜欢它。我认为重要的是视频别名连接。

评估是正确的。只有videosaliases之间才需要建立连接,因为您可以通过users加入performers_aliases。保留它是没有害处的,除非由于某种原因你必须重新分配别名,这意味着更新多个相关表中的performer_id。请记住一些事情 - 我怀疑你已经考虑过了。