SQL - 加入3个表但基于第一个表限制结果

时间:2012-08-14 21:51:52

标签: sql sql-server sql-server-2008

以下是我的情况的工作流程:

我有一个网站,允许注册用户注册本地奖品赞助商(即:商家)的奖品。例如,可能有一个页面将必胜客作为奖品赞助商,注册/认证用户只需点击“输入图纸”,一旦完成,就无法再次点击它。

以下是3个表格:

  1. BD_Listing(此表适用于奖品赞助商,包括基本栏目,如ListingID,Title,ContactPerson,Email,Prize)

  2. 用户(此表适用于网站上的注册用户,包括UserID,FirstName,LastName,Email等)

  3. PrizeEntry(此表是注册人数据的位置:EntryID,ListingID,User_ID,Date_Created)

  4. 现在,只要将数据存储在数据库中,这一切都可以正常工作。我的问题是SELECT。我有一个自定义模块,我正在网站的ADMIN端构建,我想执行以下操作:

    这是我的查询:

    SELECT ListingID, Title, ContactEmail, PrizeSponsor
    FROM [BD_Listing]
    WHERE PrizeSponsor = 'True'
    

    如果我在网站上的表格中显示此数据,它可以正常工作。问题是,我需要更多数据,特别是PrizeEntry表中的User_ID。此User_ID需要与Users表中的UserID连接,因为我需要从中提取其他信息。

    SELECT a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor
           b.ListingID, b.User_ID
           FROM BD_Listing a INNER JOIN PrizeEntry b ON a.ListingID = b.ListingID
           WHERE a.PrizeSponsor = 'True'
    

    现在,出现了第一个问题。如果20人注册必胜客,那么我将获得21行数据,这不是我想要的。这里最终是我的代码加入所有信息及其推理,然后你可以告诉我我做错了多么愚蠢:)

    SELECT a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor
           b.ListingID, b.User_ID
           c.UserID, c.FirstName, c.LastName, c.Email
           ,(SELECT COUNT(ListingID) AS EntryCount FROM PrizeEntry WHERE (ListingID = a.ListingID)) AS EntryCount
           ,(SELECT TOP 1 User_ID AS RandomWinner FROM PrizeEntry WHERE (ListingID = a.ListingID)ORDER BY NEWID()) as RandomWinner
    
           FROM BD_Listing a INNER JOIN PrizeEntry B on a.ListingID = b.ListingID
                             INNER JOIN Users C on b.User_ID = c.UserID
           WHERE a.PrizeSponsor = 'True'
    

    好的,所以在我的表格中显示这些数据我只想让必胜客出现一次,但是因为它与PrizeEntry表一起出现,它会多次出现。

    我想看看:

    Business: Pizza Hut // comes from the BD_Listing table
    Contact: John Doe  // comes from the BD_Listing table
    Total Registrations: 20 // count from the PrizeEntry table
    Random Winner: John Smith (UserID:10) // result from the subquery
    

    但相反,每次注册奖品时,我都会看到每个商家有多行。

    我道歉......我是新来的,这是我的第二篇文章。并通过SQL的开始学习曲线。

    非常感谢您的任何建议。

3 个答案:

答案 0 :(得分:1)

首先,如果有20个用户,则应该有20行,而不是21行。

我认为您可以简化查询,只需删除外部联接给用户,即可获得所需内容:

SELECT a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor,
       (SELECT COUNT(ListingID) AS EntryCount FROM PrizeEntry pe WHERE (pe.ListingID = a.ListingID)) AS EntryCount,
       (SELECT TOP 1 User_ID AS RandomWinner FROM PrizeEntry pe WHERE (pe.ListingID = a.ListingID) ORDER BY NEWID()) as RandomWinner
FROM BD_Listing a
WHERE a.PrizeSponsor = 'True'

您想获得赞助商的信息。相关子查询获取附加信息。要获得有关获胜者的更多信息,只需将其作为子查询并加入相应的表格,如下所示:

with t as (
         SELECT a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor,
                (SELECT COUNT(ListingID) AS EntryCount FROM PrizeEntry pe WHERE (pe.ListingID = a.ListingID)) AS EntryCount,
                (SELECT TOP 1 User_ID AS RandomWinner FROM PrizeEntry pe WHERE (pe.ListingID = a.ListingID) ORDER BY NEWID()) as RandomWinner
         FROM BD_Listing a
         WHERE a.PrizeSponsor = 'True'
        )
select t.*, u.Firstname, u.LastName, u.Email
from t join
     users u
     on t.RandomWinner = u.user_id

答案 1 :(得分:0)

最简单的方法是两个做两个查询。第一个获取赞助商信息,第二个查询获取条目。

从技术上讲,这是N + 1的情况(参见:What is SELECT N+1?),但我不会在此担心。

理论上你可以立刻得到所有东西,然后在前端你循环通过它,看看你是否已经打印了赞助商。问题在于,做N + 1实际上要好得多。

现在,如果您想要有关赞助商的摘要信息,那么您可以使用GROUP BY声明进行此操作。

像这样:

SELECT a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor, COUNT(*) AS EntryCount
   FROM BD_Listing a INNER JOIN PrizeEntry B on a.ListingID = b.ListingID
                     INNER JOIN Users C on b.User_ID = c.UserID
   WHERE a.PrizeSponsor = 'True'
   GROUP BY a.ListingID

答案 2 :(得分:0)

由于你的联接结构,你将得到所有匹配的组合:因为事情就是你无法得到任何其他东西。

您需要做的是先获取参赛者并确定您的获胜者,然后将其与列表相关联:

select a.ListingID, a.Title, a.ContactEmail, a.PrizeSponsor, d.userid, d.firstname, d.lastname, d.email
from BD_Listing a inner join (
    select top 1 listingid, userid, firstname, lastname, email from (
        select b.ListingID, c.UserID, c.FirstName, c.LastName, c.Email, newid() as ordering
        from PrizeEntry B INNER JOIN Users C on b.User_ID = c.UserID                    
    ) x order by ordering
) d on a.listingid = d.listingid