我的任务是编写一个查询,返回每个客户类别和年份的销售信息。结果集中所需的列为:
Sales.CustomerCategories
中CustomerCategoryName
和OrderYear
下订单的唯一客户数量CustomerCategoryName
和OrderYear
下达的订单数量Quantity
的UnitPrice
和Sales.OrderLines
计算得出CustomerCategoryName
和OrderYear
的每位客户的平均销售额结果应按升序排序,先按订单年份排序,然后按客户类别名称排序。
我尝试解决方案:
SELECT
CC.CustomerCategoryName,
YEAR(O.OrderDate) AS OrderYear,
COUNT(DISTINCT C.CustomerID) AS CustomerCount,
COUNT(DISTINCT O.OrderID) AS OrderCount,
SUM(OL.Quantity * OL.UnitPrice) AS Sales,
SUM(OL.Quantity * OL.UnitPrice) / COUNT(DISTINCT C.CustomerID) AS AverageSalesPerCustomer
FROM
Sales.CustomerCategories CC
INNER JOIN
Sales.Customers C ON C.CustomerCategoryID = CC.CustomerCategoryID
INNER JOIN
Sales.Orders O ON O.CustomerID = C.CustomerID
INNER JOIN
Sales.OrderLines OL ON OL.OrderID = O.OrderID
GROUP BY
CC.CustomerCategoryName, YEAR(O.OrderDate)
ORDER BY
YEAR(O.OrderDate), CC.CustomerCategoryName;
我的OrderCount
似乎是正确的。但是,我不相信我的CustomerCount
是正确的,我的Sales
和AverageSalesPerCustomer
似乎有点偏离。没有任何客户和订单的Categories
没有显示在我的结果中。
我的计数是否已关闭以及没有任何客户的类别被省略的原因是因为它们只有空值?我相信问题在于寻找所有类别。
我正在使用Microsoft的WideWorldImporters示例表。
任何帮助都会受到赞赏,因为我是SQL的新手,而Joins是一个非常难以理解的概念。
目前,您只获得订单详细信息中存在的数据...而且没有为不存在的订单获取任何内容。通常,这是通过外连接而不是内连接和isnull(possiblyNullValue,replacementValue)
来实现的。
此外,当您按年份(o.OrderDate)进行分组时,您的订单加入无法按年份进行区分...可能会在每个报告期间为每个客户获取所有年份的数据。
那么,让我们首先报告一段时间......并确保我们的结果基于:
select distinct year(o.OrderDate) from Sales.Orders
但实际上,你想要所有类别和所有年份......所以你可以将它们结合起来以获得真正的基础:
select
cc.CustomerCategoryId,
cc.CustomerCategoryName,
year(o.OrderDate)
from
Sales.Orders o
cross join
Sales.CustomerCategories cc
group by
cc.CustomerCategoryId,
cc.CustomerCategoryName,
year(o.OrderDate)
现在,您想将此混乱加入剩余的查询中。有两种方法可以做到这一点......一种方法是使用with
子句......但有时候只需将基础查询包装在括号中并使用它就像它是一个表一样:
select
cy.CustomerCategoryName,
cy.CalendarYear,
count(distinct c.CustomerId) CustomerCount,
isnull(sum(ol.UnitPrice * ol.Quantitiy),0.0) Sales,
isnull(sum(ol.UnitPrice * ol.Quantitiy) / count(distinct c.CustomerId),0.0) AverageSalesPerCustomer
from
(
select
cc.CustomerCategoryId,
cc.CustomerCategoryName,
year(o.OrderDate) CalendarYear --> must name calc'd cols in virtual tables
from
Sales.Orders o
cross join
Sales.CustomerCategories cc
group by
cc.CustomerCategoryId,
cc.CustomerCategoryName,
year(o.OrderDate)
) as cy --> cy is the "Category Years" virtual table
left outer join
Sales.Customers c
on cy.CustomerCategoryId = c.CustomerCategoryId
left outer join
Sales.Orders o
on
c.CustomerId = o.CustomerId --> join on customer and year
and --> to make sure we're only getting
cy.CalendarYear = Year(o.OrderDate) --> orders in the right year
left outer join
Sales.OrderLines ol
on o.OrderId = ol.OrderId
group by
cy.CalendarYear,
cy.CustomerCategoryName
order by
cy.CalendarYear,
cy.CustomerCategoryName
顺便说一下......轻松搞定你的查询以选择一些子集...例如,你可以添加一个where子句来只选择一个公司...然后去看看细节......看看如果它通过气味测试。限制它们时,评估结果要容易得多。同样,您可以出于同样的原因将客户添加到选择列表和外部分组。实验是关键。