加入不行,子查询很烂,那怎么办?

Posted

技术标签:

【中文标题】加入不行,子查询很烂,那怎么办?【英文标题】:Join won't do it, and sub query sucks, then what? 【发布时间】:2009-11-22 07:42:37 【问题描述】:

首先,很抱歉这个非描述性的标题,我太着急了,所以我想不出一个更好的标题。 第二: 我的数据库的一部分如下图所示: 我在系统上有贡献者,每个人都写给许多来源,而一个来源可以有许多工作的贡献者。用户可以订阅尽可能多的贡献者和尽可能多的来源。现在,我想做的只是检索某个用户的所有文章。这些文章要么来自贡献者,要么来自用户订阅的来源。为方便起见,当用户订阅源时,我只需将所有源贡献者复制到 users_contributors 表。一个棘手的部分是,当我检索用户的文章时,我会检索他的贡献者撰写的所有文章,以及在他关注的来源中发布的所有文章,这些文章在系统上没有有效的贡献者。 (即contributorID 为空)。 我创建了以下查询:

 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
    )

上述查询的问题在于,它没有返回任何贡献者 ID 为 null 的文章。我知道这是因为贡献者表上的加入。在这种情况下我该怎么办?

    我应该考虑非规范化吗? 为此查询在每个表上建立索引的探测器字段是什么 快速运行(返回的行集是 大约 10000)?

    我需要在这个查询上支持分页,“With ”子句会是 适合我,或者我应该 考虑另一种策略?

    提前致谢。 Ps:我使用的是 SQL Server 2008

【问题讨论】:

@7alwagy:你用什么画的表格图? 【参考方案1】:
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

如果你需要分页,使用这个(从80100 获取页面):

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

【讨论】:

我需要加入 Contributors and Sources 以获得贡献者名称和来源名称。所以.. !! 我不确定工会是否适合我。以下是我的具体需求:我需要按 Articles.OrderDate 对退货记录进行排序,并支持对这些记录进行分页。同样在联合的第二部分,我必须加入源表以获取 SourceName(因为它不会为空)。 @7alwagy :工会应该工作。它在 sql server 2008 中受支持。请参阅technet.microsoft.com/en-us/library/ms180026.aspx。【参考方案2】:

你为什么不直接加入

Inner Join Contributors On Articles.ContributorId = Contributors.ContributorID

外连接?

Left Join Contributors On Articles.ContributorId = Contributors.ContributorID

这将导致它返回所有文章,无论是否存在匹配的 SourceID(包括 ContributorID 为空的情况)。

【讨论】:

哎呀,我打错了..它是在 Articles.ContributorID = Contributors.ContributorId 上加入贡献者..我编辑了,请再检查一次!

以上是关于加入不行,子查询很烂,那怎么办?的主要内容,如果未能解决你的问题,请参考以下文章

加入查询和子查询

高手来oracle 子查询去重

使用 substr 列通过子查询加入组

没有子查询但加入的重组查询?

加入而不是相关子查询

关于SQL DELETE嵌套子查询问题