在不同的表上加入两个类似的查询 - MySQL OR

时间:2013-07-24 10:28:27

标签: mysql

我遇到了MySQL查询的问题(我是新手,所以对我来说很容易!)。我有一个有电视节目的网站,想要根据两个不同的动作(自定义时间表)选择两个日期之间播出的剧集(没问题)。基本上,如果用户正在关注(uses_follow_shows)或观看节目(user_watched),我想要显示剧集,所以我认为我会(如下所示)(query_on_follow或query_on_watch),但这不起作用(我得到1200行而不是3,它从user_watched获取每个现有行。

我认为这句话会做到,但事实并非如此,我不明白为什么

SELECT * FROM show_episode_airdate, show_episode, show_network, network, shows, users_follow_shows, user_watched
                                              WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' 
                                              AND ( show_episode.episode_id = show_episode_airdate.episode_id 
                                              AND shows.id = show_network.show_id
                                              AND show_network.network_id = network.network_id 
                                              AND show_episode.imdb_id_show = shows.imdb_id 
                                              AND users_follow_shows.user_id = 2 AND shows.id = users_follow_shows.show_id  

                                              OR user_watched.user_id = 2 
                                              AND shows.id = user_watched.show_id 
                                              AND show_episode.episode_id = show_episode_airdate.episode_id 
                                              AND shows.id = show_network.show_id
                                              AND show_network.network_id = network.network_id 
                                              AND show_episode.imdb_id_show = shows.imdb_id )
                                              ORDER by network.network_id ASC

有人可以告诉我出了什么问题吗?

谢谢!

编辑:

SELECT *
 FROM show_episode_airdate join
 show_episode 
 on show_episode.episode_id = show_episode_airdate.episode_id join
 shows
 on shows.imdb_id = show_episode.imdb_id_show join
 show_network
 on show_network.show_id = shows.id join
 network
 on show_network.network_id = network.network_id join
 users_follow_shows
 on shows.id = users_follow_shows.show_id join
 user_watched
 on shows.id = user_watched.show_id 
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' and
  (users_follow_shows.user_id = 2  or
   user_watched.user_id = 2
  )
 ORDER by network.network_id ASC;

3 个答案:

答案 0 :(得分:1)

如果用正确的连接语法编写它,那么逻辑问题就会消失。结果看起来像这样:

SELECT *
FROM show_episode_airdate join
     show_episode 
     on show_episode.episode_id = show_episode_airdate.episode_id join
     show_network 
     on show_network.show_id = network.show_id join     <------- THIS IS NOT IN YOUR ORIGINAL LIST
     network
     on show_network.network_id = network.network_id join
     user_follows_shows
     on shows.id = users_follow_shows.show_id join
     user_watched
     on shows.id = user_watched.show_id 
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' and
      (users_follow_shows.user_id = 2  or
       user_watched.user_id = 2
      )
ORDER by network.network_id ASC;

有什么好处?查询更易理解,更容易理解,更容易理解,更不容易犯错误,例如遗漏连接条件。 SQL引擎可以更轻松地优化它,它应该运行得更快。使用正确的连接语法。

好像要强调我的观点,原始查询有7个表,但只有5个连接条件。这通常意味着您在表之间进行笛卡尔积。在这种情况下,我认为它忽略了show_networkshows之间的关系。

编辑:

现在至少,查询是可以理解的。问题是用户可能会关注一些节目并观看一些节目。您的查询是在这两组之间生成笛卡尔积。更糟糕的是,如果一个节目没有粉丝或没有观察者,那么它就会辍学。

解决问题的一种方法是将查询拆分为两个。相反,我会在left outer join子句中使用distinctselect

SELECT distinct *
 FROM show_episode_airdate join
 show_episode 
 on show_episode.episode_id = show_episode_airdate.episode_id join
 shows
 on shows.imdb_id = show_episode.imdb_id_show join
 show_network
 on show_network.show_id = shows.id join
 network
 on show_network.network_id = network.network_id left outer join
 users_follow_shows
 on shows.id = users_follow_shows.show_id left outer join
 user_watched
 on shows.id = user_watched.show_id 
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' and
  (users_follow_shows.user_id = 2  or
   user_watched.user_id = 2
  )
 ORDER by network.network_id ASC;

*应替换为您真正想要的列 - 而distinct仅在您避开users_follow_showsuser_watched的列时才有效。 left outer join表示将考虑所有节目。

编写这个的另一种方法 - 摆脱distinct子句中select的需要 - 是编写一个子查询来组合观看和跟随的节目。这将删除重复项,如下所示:

SELECT *
FROM show_episode_airdate join
     show_episode 
     on show_episode.episode_id = show_episode_airdate.episode_id join
     shows
     on shows.imdb_id = show_episode.imdb_id_show join
     show_network
     on show_network.show_id = shows.id join
     network
     on show_network.network_id = network.network_id join
     (select show_id, user_id
      from users_follow_shows
      union
      select show_id, user_id
      from user_watched
     ) watch_or_follow
     on shows.id = watch_or_follow.show_id
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' and
      watch_or_follow.user_id = 2
ORDER by network.network_id ASC;

答案 1 :(得分:0)

您需要将()置于OR条件中,例如,如果这是您的目标:

SELECT * FROM show_episode_airdate, show_episode, show_network, network, shows, users_follow_shows, user_watched
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' 
AND ( (show_episode.episode_id = show_episode_airdate.episode_id 
AND shows.id = show_network.show_id
AND show_network.network_id = network.network_id 
AND show_episode.imdb_id_show = shows.imdb_id 
AND users_follow_shows.user_id = 2 
AND shows.id = users_follow_shows.show_id)
OR (user_watched.user_id = 2 
AND shows.id = user_watched.show_id 
AND show_episode.episode_id = show_episode_airdate.episode_id 
AND shows.id = show_network.show_id
AND show_network.network_id = network.network_id 
AND show_episode.imdb_id_show = shows.imdb_id ) )
ORDER by network.network_id ASC

所以你会得到:IF BETWEEN日期AND首先(条件)OR秒(条件)

我建议您使用JOIN / INNER JOIN,我在所有这些AND中迷失了:D

答案 2 :(得分:0)

这是由于您在where子句中使用的OR条件。对组合条件给予适当的限制。

只需尝试以下查询。

SELECT * FROM show_episode_airdate, show_episode, show_network, network, shows, users_follow_shows, user_watched
WHERE show_episode_airdate.airdate BETWEEN '2013-07-20' AND '2013-07-27' 
 AND (( show_episode.episode_id = show_episode_airdate.episode_id 
 AND shows.id = show_network.show_id
 AND show_network.network_id = network.network_id 
 AND show_episode.imdb_id_show = shows.imdb_id 
 AND users_follow_shows.user_id = 2 AND shows.id = users_follow_shows.show_id  )
OR (user_watched.user_id = 2 
AND shows.id = user_watched.show_id 
AND show_episode.episode_id = show_episode_airdate.episode_id 
AND shows.id = show_network.show_id
AND show_network.network_id = network.network_id 
AND show_episode.imdb_id_show = shows.imdb_id ))

ORDER by network.network_id ASC