4

假设我有一张公司表:

Company
coID | coName | coCSR

coCSR字段是与帐户处理程序表相关的数字 ID:

AccountHandler
ahID | ahFirstName | ahLastName

我还有一张订单表:

Order
orID | orCompanyID | orDate | orValue

现在我需要生成的输出结构如下:

Company | Account handler | No. of orders | Total of orders

这是我尝试过的查询,它会产生错误:

SELECT coID, coName, ahFirstName+' '+ahLastName AS CSRName, COUNT(orID) AS numOrders, SUM(orValue) AS totalRevenue
FROM Company
LEFT JOIN AccountHandler ON coCSR = ahID
LEFT JOIN Order ON coID = orCompanyID
WHERE coCSR = 8
AND orDate > getdate() - 365
ORDER BY coName ASC

错误是:列名 'AccountHandler.ahLastName' 在 ORDER BY 子句中无效,因为它不包含在聚合函数中并且没有 GROUP BY 子句。

如果我使用GROUP BY coID,我会在关键字“WHERE”附近得到不正确的语法。如果由于聚合函数而将 更改为WHEREHAVING则会收到错误消息,告诉我删除聚合函数或 GROUP BY 子句中不包含的每个其他列名。

我不得不承认,除了最基本的 SQL 命令,我还不懂任何东西的逻辑和语法,我只是想应用我以前见过的东西,但它不起作用。请帮助我完成这项工作。更好的是,你能帮我理解为什么它现在不起作用吗?:)

4

3 回答 3

5

一方面,您的查询可能会丢失FROM Company,但在您撰写帖子时可能会以某种方式丢失。

您似乎在按公司汇总数据。因此,您需要按公司分组。您尝试分组失败的最可能原因可能是因为您放GROUP BY错了位置。我想你把它放在 before WHERE,但实际上它应该放在它之后(和 before ORDER BY):

SELECT
  c.coID,
  c.coName,
  a.ahFirstName + ' ' + a.ahLastName AS CSRName,
  COUNT(o.orID) AS numOrders,
  SUM(o.orValue) AS totalRevenue
FROM Company c
LEFT JOIN AccountHandler a ON c.coCSR = a.ahID
LEFT JOIN [Order] o ON c.coID = o.orCompanyID
WHERE c.coCSR = 8
AND o.orDate > getdate() - 365
GROUP BY ...
ORDER BY c.coName ASC

另一个问题是,按什么分组。SQL Server 要求在GROUP BY. 因此,您的GROUP BY子句应如下所示:

GROUP BY
  c.coID,
  c.coName,
  a.ahFirstName,
  a.ahLastName

请注意,您不能通过在SELECT子句中分配给它们的别名来引用列(例如CSRName)。但是您可以使用ahFirstName+' '+ahLastName表达式而不是相应的列,在这种特殊情况下不会有任何区别。

如果您需要向此查询添加更多非聚合列,则必须将它们添加到SELECTGROUP BY。在某些时候,这可能会变得有点乏味。我建议您尝试以下方法:

SELECT
  c.coID,
  c.coName,
  a.ahFirstName + ' ' + a.ahLastName AS CSRName,
  ISNULL(o.numOrders,    0) AS numOrders,
  ISNULL(o.totalRevenue, 0) AS totalRevenue
FROM Company c
LEFT JOIN AccountHandler a ON c.coCSR = a.ahID
LEFT JOIN (
  SELECT
    orCompanyID,
    COUNT(orID)  AS numOrders,
    SUM(orValue) AS totalRevenue
  FROM [Order]
  GROUP BY
    orCompanyID
  WHERE orDate > getdate() - 365
) o ON c.coID = o.orCompanyID
WHERE c.coCSR = 8
ORDER BY c.coName ASC

也就是说,聚合Order仅在表上完成。然后将聚合的行集连接到其他表。您现在可以将更多属性拉到输出中,也可以Company不用AccountHandler担心将它们添加到输出中,GROUP BY因为在该级别不再需要分组。

于 2012-06-22T21:04:35.787 回答
1

您可以更改如下查询吗?你应该添加MaxGroup By Clause

SELECT 
        MAX(C.coID), 
        C.coName, 
        MAX(AH.ahFirstName+' '+ AH.ahLastName ) AS CSRName, 
        COUNT(O.orID) AS numOrders, 
        SUM(O.orValue) AS totalRevenue
From Company C
LEFT JOIN AccountHandler AH ON C.coCSR = AH.ahID
LEFT JOIN Order O ON C.coID = O.orCompanyID
WHERE   C.coCSR = 8 AND 
        O.orDate > getdate() - 365
Group by C.coName
ORDER BY C.coName ASC

我的建议

您应该为选定的列名称使用别名

于 2012-06-22T19:08:32.013 回答
0
SELECT 
      --<<<non aggregate section of SELECT clause
     coID   
     , coName
     , [CSRName] = CONVERT(VARCHAR(100),ahFirstName + ' ' + ahLastName) 

      --<<<aggregate section of SELECT clause
     , [numOrders] = COUNT(orID)
     , [totalRevenue] = SUM(orValue) 
FROM   --<<<<<<sql is not too happy without FROM
    Company c
    LEFT JOIN AccountHandler a
       ON coCSR = ahID
    LEFT JOIN Order o
       ON coID = orCompanyID
WHERE coCSR = 8
   AND orDate > getdate() - 365
GROUP BY
     coID   
     , coName
     , CONVERT(VARCHAR(100),ahFirstName + ' ' + ahLastName) --<<<<looks like aggregate but is just text manipulation
ORDER BY coName ASC

你有两个聚合函数;一个COUNT和一个SUM; 这意味着您需要进行一些分组,一般的经验法则是GROUP BYselect 子句的非聚合部分

OP 中真正的大问题是,当您 JOIN 两个表时,无论哪种风格(LEFT、RIGHT、OUTER、INNER、CROSS),它都必须在 FROM 子句中,并且需要在连接的任一侧指定一个表

然后,如果加入多个表,您可能希望为每个表使用别名;我刚刚使用了单个小写字母;c/o/a。尽管查看您的列名可能不需要这些,因为所有列都是唯一命名的。

于 2012-06-22T22:19:53.620 回答