我的任务是编写一个查询,该查询将返回每个客户类别和年份的销售信息。结果集中所需的列为:
Sales.CustomerCategories
CustomerCategoryName
和OrderYear
的唯一客户数量CustomerCategoryName
和OrderYear
Quantity
的{{1}}和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
不会显示在我的结果中。
是因为我的计数没有值,并且没有任何客户的类别被忽略是因为它们只有空值?我相信问题正在寻找所有类别。
我正在使用Microsoft的WideWorldImporters示例表。
由于我是SQL新手,所以任何帮助将不胜感激,而Joins是我很难理解的概念。
答案 0 :(得分:1)
当前,您只获取订单明细中存在的数据...而不获取不存在的订单的任何数据。通常,这是通过外部联接而不是内部联接和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子句以仅选择一家公司...然后查看详细信息。看它是否通过了气味测试。当您限制结果时,评估结果要容易得多。同样,出于相同的原因,您可以将客户添加到选择列表和外部分组中。实验是关键。