3

所以我正在研究 SQL Server 2008,我有这个查询应该很简单,但由于某种原因不起作用。它基本上看起来像这样:

SELECT TOP 10
    u.Id                AS "UserId",
    u.CreationDate      AS "Member since",
    AVG(q.Score)        AS "Average Question Rating",  
    COUNT(q.Id)         AS "N. of Questions posted by the agent",
    AVG(a.Score)        AS "Average Answer Rating",  
    COUNT(a.Id)         AS "N. of Answers posted by the agent"
FROM    
        Users u, 
        Answers a, 
        Questions q
WHERE q.OwnerUserId = u.Id
AND a.OwnerUserId = u.Id
GROUP BY u.Id, u.CreationDate

当我只处理 Answers 表或 Questions 表时,一切正常。但是,一旦我尝试同时执行这两项操作(如上面的查询),COUNT 就根本不起作用。我得到的是 COUNT(a.Id) 与 COUNT(q.Id) 相同。所以我试着减少我的查询,看看有什么问题,我意识到我只需要在使用另一个表时将 Questions 或 Answers 表(即使没有在任何地方使用它们)添加到 FROM 子句中,一切都被破坏了。

我确信这是我忽略的可笑的微不足道的事情,但这让我发疯,如果有人能指出我出了什么问题,我将不胜感激。先感谢您。

4

4 回答 4

5

您没有加入Answers并且没有Questions正确地进行聚合。在Answers和之间Questions,结果是一个笛卡尔积(对于每个用户,每个答案都与每个问题相结合)

纠正此问题的最简单方法是在子查询中执行聚合:

SELECT TOP 10
    u.Id                AS "UserId",
    u.CreationDate      AS "Member since",
    ISNULL((SELECT AVG(Score) FROM Answers   WHERE OwnerUserId = u.Id), 0)
                        AS "Average Question Rating",  
           (SELECT COUNT(*)   FROM Answers   WHERE OwnerUserId = u.Id)        
                        AS "N. of Questions posted by the agent",
    ISNULL((SELECT AVG(Score) FROM Questions WHERE OwnerUserId = u.Id), 0)
                        AS "Average Answer Rating",  
           (SELECT COUNT(*)   FROM Questions WHERE OwnerUserId = u.Id)
                        AS "N. of Answers posted by the agent"
FROM  Users u

或者使用连接:

SELECT TOP 10
     u.Id                AS "UserId",
     u.CreationDate      AS "Member since",
     ISNULL(q.a, 0)      AS "Average Question Rating",  
     ISNULL(q.c, 0)      AS "N. of Questions posted by the agent",
     ISNULL(a.a, 0)      AS "Average Answer Rating",  
     ISNULL(a.c, 0)      AS "N. of Answers posted by the agent"
FROM Users u
-- If you LEFT JOIN these tables, you'll get also results for users without
-- questions or answers
LEFT OUTER JOIN (SELECT OwnerUserId, AVG(Score) a, COUNT(*) c 
     FROM Questions GROUP BY OwnerUserId) q
     ON  q.OwnerUserId = u.Id
LEFT OUTER JOIN (SELECT OwnerUserId, AVG(Score) a, COUNT(*) c 
     FROM Answers GROUP BY OwnerUserId) a
     ON  a.OwnerUserId = u.Id

我不太了解 SQL Server 的查询优化器,所以我不能说哪个会更快。第一个解决方案可以利用标量子查询缓存,如果在 SQL Server 中可用的话。否则,第二个查询可能执行较少的嵌套循环。

于 2012-04-23T15:26:47.443 回答
3

如其他地方所述,您在问题和答案上的用户 ID 连接本质上会在两个表之间的用户级别产生笛卡尔连接。更好的方法是使用联合:

SELECT TOP 10
    u.Id                AS "UserId",
    u.CreationDate      AS "Member since",
    AVG(q_score)        AS "Average Question Rating",  
    COUNT(q_id)         AS "N. of Questions posted by the agent",
    AVG(a_score)        AS "Average Answer Rating",  
    COUNT(a_id)         AS "N. of Answers posted by the agent"
FROM Users u
JOIN (select OwnerUserId,
             Score        q_score,
             Id           q_id,
             NULL         a_score,
             NULL         a_id
      from Answers
      union all
      select OwnerUserId,
             NULL         q_score,
             NULL         q_id,
             Score        a_score,
             Id           a_id
      from Questions) qa
  ON qa.OwnerUserId = u.Id
GROUP BY u.Id, u.CreationDate
于 2012-04-23T16:04:34.007 回答
1

仅计算 DISTINCT Id 不可行吗?

SELECT TOP 10 
    u.Id                         AS "UserId", 
    u.CreationDate               AS "Member since", 
    AVG(q.Score)                 AS "Average Question Rating",   
    COUNT(DISTINCT q.Id)         AS "N. of Questions posted by the agent", 
    AVG(a.Score)                 AS "Average Answer Rating",   
    COUNT(DISTINCT a.Id)          AS "N. of Answers posted by the agent" 
FROM     
        Users u,  
        Answers a,  
        Questions q 
WHERE q.OwnerUserId = u.Id 
AND a.OwnerUserId = u.Id 
GROUP BY u.Id, u.CreationDate 
于 2012-04-23T16:50:26.737 回答
-1

如果是我,我会在其他表(答案和问题)上进行显式连接。如果您不进行连接,它如何链接其他表?

SELECT TOP 10
    u.Id                AS "UserId",
    u.CreationDate      AS "Member since",
    AVG(q.Score)        AS "Average Question Rating",  
    COUNT(q.Id)         AS "N. of Questions posted by the agent",
    AVG(a.Score)        AS "Average Answer Rating",  
    COUNT(a.Id)         AS "N. of Answers posted by the agent"
FROM    
        Users u, 
        Answers a, 
        Questions q
WHERE q.OwnerUserId = u.Id
AND a.OwnerUserId = u.Id
GROUP BY u.Id, u.CreationDate

would be

SELECT TOP 10
    u.Id                AS "UserId",
    u.CreationDate      AS "Member since",
    AVG(q.Score)        AS "Average Question Rating",  
    COUNT(q.Id)         AS "N. of Questions posted by the agent",
    AVG(a.Score)        AS "Average Answer Rating",  
    COUNT(a.Id)         AS "N. of Answers posted by the agent"
FROM    
        Users u
JOIN Answers a on u.ID = a.ID (assuming thats how answers and users are linked).
JOIN Questions q on a.ID = q.ID (assuming thats how questions and answers are linked)
WHERE q.OwnerUserId = u.Id
AND a.OwnerUserId = u.Id
GROUP BY u.Id, u.CreationDate
于 2012-04-23T15:25:54.887 回答