2013-07-24 48 views
3

我在MySQL查詢時遇到了問題(我是一個新手,所以對我來說很簡單!)。我有一個帶有電視節目的網站,並希望根據兩種不同的操作(用於自定義時間表)選擇兩個日期之間播出的節目(沒有問題)。基本上,如果用戶要麼跟隨(uses_follow_shows)或觀看節目(user_watched),我想要顯示該節目,所以我想我會有(query_on_follow或query_on_watch)像下面但不起作用(我得到1200行而不是3,它從user_watched獲取每個現有行)。在不同的表上加入兩個類似的查詢 - MySQL 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 

誰能告訴我有什麼不對?

謝謝!

編輯:

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

你需要把()爲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

+0

仍然返回1200行。我認爲這是因爲在第一個OR中,它選擇了user_watched和第二個,user_follow_shows中的所有內容...不是? – Callombert

+0

我認爲@Gordon Linoff解釋說它是最好的方式:D +懶得寫全部東西,所以請閱讀:D – mirkobrankovic

+0

好吧!謝謝你的時間。 – Callombert

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 
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 S和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; 

*應該由你真正想要的列被替換 - 如果你避免users_follow_showsuser_watcheddistinct只會工作。 left outer join表示將考慮所有節目。

寫這個的另一種方式 - 擺脫了select子句中distinct的需要 - 就是編寫一個子查詢來組合觀看和隨後的節目。這將刪除重複項,如下所示:

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; 
+0

我得到這個錯誤'on子句'中未知的列'shows.id'(該列確實存在。) – Callombert

+0

我還沒有使用過連接和之前和邏輯where和and對我更有意義。但這不是第一次有人提到我應該使用它,所以我一定會嘗試去理解它。 – Callombert

+0

@metareviewr。 。 。你如何學習SQL並不學習正確的語法?你需要找到能夠更好地教授你需要知道的書籍/講師/在線材料。您的查詢缺少一個非常重要的「加入」條件。幾乎不可能發現你正在編寫連接的方式。使用正確的語法時,這是微不足道的。 –