0

****编辑**** 在此处添加 SQL Fiddle 链接 我在 SQL Fiddle 中创建了场景以显示我想要完成的任务。我发现它在 SQL Fiddle 中产生准确的结果但使用我的数据库产生以下结果非常奇怪。

然而,为了证明这里确实存在这些季节,我们选择了 tvseasons 加入 tvseries: TVSeason_加入_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,最合理的解释是您提到的季节都不见了TVSeriesHasTVSeason。请注意,右连接只会消除 中缺失的行TVSeriesHasTVSeason,因为该表中的数据不会在其他任何地方使用。顺便说一句,请注意您不需要交叉连接。假设您的表是健全的,您可以从 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. 每个赛季都只有一个系列,因此通过额外的外键 in 进行关联会更自然TVSeason。单独的关联表最好与多对多关系或可选字段一起使用。

  • 虽然此查询中有一个交叉连接,但它是 between TVSeriesand Users,这应该导致结果行比 between TVSeasonand少得多Users。从更高层次的角度来看,and 之间的交叉连接TVSeries表达了您想要的结果(即系列和季节之间的所有组合),而andUsers之间的交叉连接会生成大量额外的数据(个体和值),这些数据将是扔掉(因为你只对计数感兴趣)。TVSeasonUsers'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 回答