0

****EDIT**** ここに SQL Fiddleリンクを追加する 私は SQL Fiddle でシナリオを作成し、私が達成しようとしていることを示しました。SQL Fiddle で正確な結果が得られるにもかかわらず、DB を使用して以下の結果が得られるのは非常に奇妙です。

ただし、季節が本当に存在することを証明するために、テレビシリーズに参加するテレビシーズンの一部を以下に示します。 TVSeason_Join_TVSeries

このクエリの実行:

SELECT TVSeriesHasTVSeason.tvSeriesID, TVSeason.tvSeasonID, TVSeason.title, Users.userID, 
    CASE
        WHEN UserHasWatchedTVSeason.tvSeasonID IS NULL THEN 'No'
        ELSE 'Yes'
    END as watched
FROM TVSeason
CROSS JOIN Users
LEFT JOIN UserHasWatchedTVSeason
    ON  TVSeason.tvSeasonID = UserHasWatchedTVSeason.tvSeasonID
    AND Users.userID = UserHasWatchedTVSeason.userID
RIGHT JOIN TVSeriesHasTVSeason
    ON TVSeason.tvSeasonID = TVSeriesHasTVSeason.tvSeasonID 

戻り値:

515 1769    1000 Ways to Die Season 1   3   Yes
515 1770    1000 Ways to Die Season 2   3   Yes
515 1772    1000 Ways to Die Season 4   3   Yes
515 1773    1000 Ways to Die Season 5   3   Yes
516 1774    2 Stupid Dogs Season 1      3   No
516 1775    2 Stupid Dogs Season 2      3   No
517 1777    24 Season 2                 3   Yes
517 1779    24 Season 4                 3   Yes
517 1780    24 Season 5                 3   Yes
517 1781    24 Season 6                 3   Yes
517 1782    24 Season 7                 3   Yes

シーズン ID は連続しており、1000 通りの死に方のシーズン 3 が返されていないことがはっきりとわかります。24 のシーズンも返されていません。

このクエリの何が問題なのかわかりませんか?

****編集**私は問題の有効な解決策を見つけたと思います:**

SELECT x.*,
    CASE
        WHEN UserHasWatchedTVSeason.tvSeasonID IS NULL THEN 'No'
        ELSE 'Yes'
    END as watched
FROM
(SELECT 
    TVSeries.tvSeriesID, TVSeries.title,
    TVSeriesHasTVSeason.tvSeasonID,
    Users.userID
FROM TVSeries
LEFT JOIN TVSeriesHasTVSeason
    on tvseries.tvSeriesID = TVSeriesHasTVSeason.tvSeriesID
LEFT JOIN TVSeason
    on tvseason.tvSeasonID = TVSeriesHasTVSeason.tvSeriesID
CROSS JOIN Users)x
LEFT JOIN UserHasWatchedTVSeason
    on x.tvSeasonID = UserHasWatchedTVSeason.tvSeasonID
    AND x.userID = UserHasWatchedTVSeason.userID
4

2 に答える 2

1

すべての季節が にあると仮定するとTVSeason、最も妥当な説明は、あなたが言及した季節が にないということですTVSeriesHasTVSeasonTVSeriesHasTVSeasonそのテーブルのデータは他の場所では使用されないため、右側の結合は から欠落している行を削除するだけであることに注意してください。ちなみに、クロス結合は必要ないことに注意してください。テーブルが正常であると仮定すると、UserHasWatchedTVSeason からユーザー ID を取得できます。


コメントと質問への編集に基づく更新。線の下の議論で、あなたは言いました:

シリーズ番号、テレビシーズン番号、ユーザーID番号、および視聴済み=はい、いいえ、または部分的に視聴されたシリーズを示すビューでこれを実行しようとしていると思います

以下は、適切なデータが与えられた場合に、要件に一致するクエリです。

SELECT WatchCount.tvSeriesID, WatchCount.userID,
  CASE
    WHEN WatchCount.NWatched = 0 THEN 'No'
    WHEN WatchCount.NWatched = SeasonCount.NSeasons THEN 'Yes'
    ELSE 'Partial'
    END AS Watched
FROM (
  SELECT SR.tvSeriesID, U.userID,
    COUNT(UxSN.tvSeasonID) AS NWatched
  FROM TVSeries SR
  CROSS JOIN Users U
  LEFT JOIN TVSeriesHasTVSeason SRxSN
    ON SRxSN.tvSeriesID = SR.tvSeriesID
  LEFT JOIN UserHasWatchedTVSeason UxSN
    ON UxSN.userID = U.userID
    AND UxSN.tvSeasonID = SRxSN.tvSeasonID
  GROUP BY SR.tvSeriesID, U.userID
  ) WatchCount
INNER JOIN (
  SELECT SRxSN.tvSeriesID,
    COUNT(SRxSN.tvSeasonID) AS NSeasons
  FROM TVSeriesHasTVSeason SRxSN
  GROUP BY SRxSN.tvSeriesID
  ) SeasonCount
ON SeasonCount.tvSeriesID = WatchCount.tvSeriesID

いくつかの重要な観察事項:

  • Watchedあなたのコメントは、シリーズとシーズンIDの両方をフィールドとともに返すことに言及しました。ただし、これはうまく機能しません。ユーザーとシリーズの組み合わせWatchedのプロパティです。そのため、それを返すクエリでは、季節データが既にグループ化されている必要があります (別の方法では、多くの重複データが返されます)。

  • TVSeriesHasTVSeasonあなたが提供した証拠は、数シーズンの間、テーブルに欠落または不安定な行があることを強く示唆しています。このクエリはそれを考慮していません。したがって、(回答のように)余分な左結合が必要になるTVSeasonsか、できればデータをチェックしてTVSeriesHasTVSeason.

  • TVSeriesHasTVSeason不要なようです。スキーマがあなたの管理下にある場合は、 とマージすることをお勧めしますTVSeason。各シーズンにはちょうど 1 つのシリーズがあるため、関連付けは、TVSeason. 個別の関連付けテーブルは、多対多の関係またはオプション フィールドで使用するのが最適です。

  • このクエリにはクロス結合がありますが、それは と の間TVSeriesにあるため、 と の間Usersの結果行よりもはるかに少ない結果行にTVSeasonなりUsersます。より高いレベルの観点から見ると、 と の間の相互結合は目的の結果 (つまり、シリーズと季節の間のすべての組み合わせ)TVSeriesを表現しますが、 と の間の相互結合は多くの余分なデータ (個体と値) を生成します。捨てられます(カウントのみに関心があるため)。UsersTVSeasonUsers'Yes'No

于 2013-10-31T05:19:39.413 に答える
0

これは実用的なソリューションです:

SELECT x.*,
    CASE
        WHEN UserHasWatchedTVSeason.tvSeasonID IS NULL THEN 'No'
        ELSE 'Yes'
    END as watched
FROM
    (SELECT 
        TVSeries.tvSeriesID, TVSeries.title,
        TVSeriesHasTVSeason.tvSeasonID,
        Users.userID
    FROM TVSeries
    LEFT JOIN TVSeriesHasTVSeason
        on tvseries.tvSeriesID = TVSeriesHasTVSeason.tvSeriesID
    LEFT JOIN TVSeason
        on tvseason.tvSeasonID = TVSeriesHasTVSeason.tvSeriesID
    CROSS JOIN Users)x
LEFT JOIN UserHasWatchedTVSeason
    on x.tvSeasonID = UserHasWatchedTVSeason.tvSeasonID
    AND x.userID = UserHasWatchedTVSeason.userID

私の考えでは、元の投稿では、後で JOINS で参照したときに CROSS JOIN で接続が失われていたと考えています。

私にはまだ少し不明確なため、誰かがこれが正確に機能した理由を教えてくれることを願っています.

また、「はい」、「いいえ」、「部分的に見た」を返すように回答を拡張するには:

SELECT *
FROM
    (SELECT userID, tvSeriesID, 
        CASE
            WHEN COUNT(tvSeriesID) = ABS(SUM(watched)) 
                AND SUM(watched) > 0 THEN 'Yes'
            WHEN COUNT(tvSeriesID) = ABS(SUM(watched)) 
                AND SUM(watched) < 0 THEN 'No'
            ELSE 'Partial'
        END as watched
    FROM
        (SELECT x.*,
            CASE
                WHEN UserHasWatchedTVSeason.tvSeasonID IS NULL THEN -1
                ELSE 1
            END as watched
        FROM
            (SELECT 
                TVSeries.tvSeriesID, TVSeries.title as tvSeriesTitle,
                TVSeriesHasTVSeason.tvSeasonID, 
                Users.userID
            FROM TVSeries
            LEFT JOIN TVSeriesHasTVSeason
                on tvseries.tvSeriesID = TVSeriesHasTVSeason.tvSeriesID
            LEFT JOIN TVSeason
                on tvseason.tvSeasonID = TVSeriesHasTVSeason.tvSeriesID
            CROSS JOIN Users
            )x
        LEFT JOIN UserHasWatchedTVSeason
            on x.tvSeasonID = UserHasWatchedTVSeason.tvSeasonID
            AND x.userID = UserHasWatchedTVSeason.userID
        )y
    GROUP BY userID, tvSeriesID
    )z
ORDER BY userID, tvSeriesID
于 2013-11-05T03:20:02.057 に答える