代码之家  ›  专栏  ›  技术社区  ›  Ahmed

Join不会这样做,子查询很糟糕,然后呢?

  •  2
  • Ahmed  · 技术社区  · 15 年前

    首先,对这个非描述性的标题感到抱歉,我太匆忙了,所以我找不到更好的标题。
    第二:
    我有一部分数据库,如下图所示:
    alt text 我在系统中有贡献者,每一个贡献者都写许多源,一个源可以有许多工作贡献者。用户可以订阅任意多的贡献者,也可以订阅任意多的资源。现在,我要做的只是检索特定用户的所有文章。这些文章要么来自贡献者,要么来自用户订阅的源。为了方便起见,当用户订阅源时,我只需将所有源贡献者复制到用户贡献者表中。一个棘手的问题是,当我检索用户的文章时,我会检索他贡献者所写的所有文章,以及在他所关注的源中发布的所有文章,这些文章在系统中没有有效的贡献者。(即contributid为空)。
    我创建了以下查询:

     Select Articles.ArticleID, Articles.ContributorId, Contributors.Name, 
        Sources.Name, Articles.ArticleTitle
    From Articles 
                Inner Join Contributors On Articles.ContributorId = Contributors.ContributorId
                Inner Join Sources On Articles.SourceId = Sources.SourceID          
    Where Articles.ContributorId in (
        Select ContributorId from Users_Contributors
        Where UserID = 3
        )
        OR (
    
            Articles.SourceId in (
                Select SourceId from Users_Sources
                Where UserID = 3
                )
    
                and 
                Articles.ContributorId is null
        )
    

    上面的查询的问题是,它不返回任何contributrid为空的项目。我理解这是因为参与者表中的联接。在这种情况下我该怎么办?

    1. 我应该考虑非规范化吗?
    2. 对于这个查询,每个表上要索引的prober字段是什么 快速运行(返回的行集为 大约10000)?
    3. 我需要支持此查询的分页,will“with”子句将 适合我,还是我应该 考虑另一个策略?


      事先谢谢。
      PS:我正在使用SQL Server 2008

    2 回复  |  直到 9 年前
        1
  •  4
  •   Quassnoi    15 年前
    SELECT  a.*, s.Name AS SourceName, NULL AS ContributorName
    FROM    User_Sources us
    JOIN    Articles a
    ON      a.SourceID = us.SourceID
    JOIN    Source s
    ON      s.SourceID = us.SourceID
    WHERE   us.UserID = 3
            AND a.ContributorID IS NULL
    UNION
    SELECT  a.*, s.Name AS SourceName, c.Name AS ContributorName
    FROM    User_Contributor uc
    JOIN    Articles a
    ON      a.ContributorID = uc.ContributorID
    JOIN    Contirbutors c
    ON      c.ContributorID = uc.ContributorID
    JOIN    Sources s
    ON      s.SourceID = a.SourceID
    WHERE   uc.UserID = 3
    

    如果需要分页,请使用此选项(从 80 100 ):

    WITH    q AS (
            SELECT  TOP 100 
                    a.*, s.Name AS SourceName, NULL AS ContributorName
            FROM    User_Sources us
            JOIN    Articles a
            ON      a.SourceID = us.SourceID
            JOIN    Source s
            ON      s.SourceID = us.SourceID
            WHERE   us.UserID = 3
                    AND a.ContributorID IS NULL
            ORDER BY
                    OrderDate
            UNION
            SELECT  TOP 100
                    a.*, s.Name AS SourceName, c.Name AS ContributorName
            FROM    User_Contributor uc
            JOIN    Articles a
            ON      a.ContributorID = uc.ContributorID
            JOIN    Contirbutors c
            ON      c.ContributorID = uc.ContributorID
            JOIN    Sources s
            ON      s.SourceID = a.SourceID
            WHERE   uc.UserID = 3
            ORDER BY
                    OrderDate
            ),
            page AS
            (
            SELECT  TOP 100 *, ROW_NUMBER() OVER (ORDER BY OrderDate) AS rn
            FROM    q
            )
    SELECT  *
    FROM    page
    WHERE   rn >= 80
    
        2
  •  2
  •   Robert Harvey    15 年前

    你为什么不加入呢

    Inner Join Contributors On Articles.ContributorId = Contributors.ContributorID
    

    外部连接?

    Left Join Contributors On Articles.ContributorId = Contributors.ContributorID
    

    这将导致它返回所有项目,无论是否有匹配的sourceid(包括contributorid为空的情况)。