3

我在使用 MySQL 查询时遇到问题(我是新手,所以放轻松!)。我有一个包含电视节目的网站,并且想根据两个不同的操作(对于自定义时间表)选择两个日期之间播出的剧集(没问题)。基本上,如果用户正在关注(uses_follow_shows)或观看节目(user_watched),我想显示该剧集,所以我想我会像下面那样(query_on_follow OR 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;
4

3 回答 3

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_network在这种情况下,我认为它缺少和之间的关系shows

编辑:

现在至少,这个查询是相当容易理解的。问题是用户可能会关注一些节目并且可能会观看一些节目。您的查询在这两组之间产生一个笛卡尔积。更糟糕的是,如果一个节目没有追随者或没有观众,那么它就会退出。

解决问题的一种方法是将查询一分为二。相反,我将在子句中使用left outer joins 和: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;

*应该由您实际需要的列替换 -只有当您避免来自and的distinct列时才会起作用。意味着所有节目都将被考虑。users_follow_showsuser_watchedleft 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;
于 2013-07-24T10:43:17.887 回答
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
于 2013-07-24T10:40:04.180 回答
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

于 2013-07-24T10:34:28.640 回答