假设我有一张公司表:
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'附近获得不正确的语法。如果由于聚合函数我将WHERE
更改为HAVING
,我收到错误告诉我删除聚合函数或GROUP BY子句中未包含的每个其他列名。
我不得不承认,除了最基本的SQL命令之外,我还没有理解任何逻辑和语法,我只是试图应用我以前见过的东西,而且它不起作用。请帮我搞定这个。更好的是,你能帮助我理解为什么它现在不起作用吗? :)
答案 0 :(得分:5)
首先,您的查询可能缺少FROM Company
,但在撰写帖子时可能会以某种方式丢失。
您似乎正在通过公司汇总数据。因此,您需要按公司分组。您尝试分组失败的最可能原因可能是您将GROUP BY
置于错误的位置。我认为你把它放在WHERE
之前,但事实上它应该追求它(在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
表达式而不是相应的列,在这种特殊情况下它不会有任何区别。
如果您需要向此查询添加更多非聚合列,则必须将它们添加到SELECT
和GROUP 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
,因为不再需要在该级别进行分组。
答案 1 :(得分:1)
您可以更改下面的查询吗?您应该添加Max
和Group 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
您应该为选定的列名称使用别名
答案 2 :(得分: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 BY
select子句的非聚合部分
你的OP中一个非常大的问题是,当你加入两个表时,无论什么风格(LEFT,RIGHT,OUTER,INNER,CROSS)都必须在FROM子句中,并且需要在连接的任一侧指定一个表
然后,如果连接多个表,您可能希望为每个表使用别名;我刚刚使用过单个小写字母; C / O / A。虽然查看列名称可能不需要,但所有列都是唯一命名的。