我遇到了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;
答案 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_network
和shows
之间的关系。
编辑:
现在至少,查询是可以理解的。问题是用户可能会关注一些节目并观看一些节目。您的查询是在这两组之间生成笛卡尔积。更糟糕的是,如果一个节目没有粉丝或没有观察者,那么它就会辍学。
解决问题的一种方法是将查询拆分为两个。相反,我会在left outer join
子句中使用distinct
和select
:
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_shows
和user_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