产品销售额统计


要求统计每种产品的销售额并且在报表最后列出销售额总计。
检索每种产品的销售额可以到 T_SaleBillDetail 中按照产品进行分组,然后使用聚合函


数 SUM()来计算每种产品的销售额。因为 T_SaleBillDetail 只保存了销售量,价格和产品名
称保存在 T_Merchandise表中,因此还需要与 T_Merchandise表进行连接运算。SQL语句如
下:


select T_Merchandise.Fname,sum(T_SaleBillDetail.Fcount*T_Merchandise.FPrice)
from T_Merchandise
inner join T_SaleBillDetail
on T_SaleBillDetail.FMerchandiseId=T_Merchandise.Fid
group by T_Merchandise.fname



mysql计算每个商品的总销售额 数据库计算销售额_窗口函数



统计销售额总计同样需要与T_Merchandise表进行连接运算以取得价格,然后使用聚合
函数SUM()来计算总销售额。SQL语句如下:


select sum(T_Merchandise.FPrice*T_SaleBillDetail.Fcount)
from T_Merchandise
inner join T_SaleBillDetail
on T_SaleBillDetail.FMerchandiseId=t_Merchandise.Fid



mysql计算每个商品的总销售额 数据库计算销售额_mysql计算每个商品的总销售额_02



由于这两个查询结构是异构的, 如果要将第二个查询的结果集添加到第一个查询的结果
集后,那么就需要首先为第二个查询增加一列以保证和第一个查询的列数相同,然后将这两
个查询语句使用UNION ALL联合起来。SQL语句如下:


select T_Merchandise.Fname,sum(T_SaleBillDetail.Fcount*T_Merchandise.FPrice)
from T_Merchandise
inner join T_SaleBillDetail
on T_SaleBillDetail.FMerchandiseId=T_Merchandise.Fid
group by T_Merchandise.fname
union all
select '总计',sum(T_Merchandise.FPrice*T_SaleBillDetail.Fcount)
from T_Merchandise
inner join T_SaleBillDetail
on T_SaleBillDetail.FMerchandiseId=t_Merchandise.Fid



mysql计算每个商品的总销售额 数据库计算销售额_SQL_03



统计销售记录的份额


要求统计所有的销售明细,并且计算每一笔销售记录中销售量占同产品总销售量的百分
比。
这里要求列出每一笔销售记录中销售量, 而且还要计算销售量占同产品总销售量的百分
比,很显然这要使用窗口函数来完成。SQL语句如下:


select T_Merchandise.fname,T_SaleBillDetail.Fcount,
T_SaleBillDetail.fcount*1.0/sum(T_SaleBillDetail.Fcount) over(partition by T_Merchandise.Fname)
from T_Merchandise
inner join T_SaleBillDetail
on T_Merchandise.fid=T_SaleBillDetail.FMerchandiseId



mysql计算每个商品的总销售额 数据库计算销售额_窗口函数_04



或者:


select T_Merchandise.fname,T_SaleBillDetail.Fcount,
T_SaleBillDetail.fcount*1.0/sum(T_SaleBillDetail.Fcount) over(partition by T_SaleBillDetail.FMerchandiseId)
from T_Merchandise
inner join T_SaleBillDetail
on T_Merchandise.fid=T_SaleBillDetail.FMerchandiseId



mysql计算每个商品的总销售额 数据库计算销售额_结果集_05



为了取得每一笔销售记录中的商品名称,需要连接 T_Merchandise表;为了统计同产品
的总销量,需要使用按FMerchandiseId进行分区的 SUM()窗口函数来统计同产品总销售量
由于 FCount 是整数类型,在进行除法运算的时候为了避免精度问题,需要将 FCount 乘以
1.0这样就可以进行高精度运算了。由于这里使用来的窗口函数,所以这个 SQL语句不能在
MYSQL中运行。


为采购单分级


统计每张采购单的单号、总采购额,并且对于总采购额小于等于 500元的显示为 “小额”、
总采购额大于等于1000 元的显示为“大额”、介于 500元与 1000元之间的显示为“普通” 。
对于这种复杂的问题可以分解成几个小步骤进行处理。 首先统计所有采购单的单号以及
它们的每条交易明细的交易额,这只要将 T_PurchaseBill、T_PurchaseBillDetail 和
T_Merchandise这三张表进行连接查询就可以得到。SQL语句如下:


select T_PurchaseBill.FNumber,T_PurchaseBillDetail.FCount*T_Merchandise.FPrice
from T_PurchaseBill
inner join T_PurchaseBillDetail
on T_PurchaseBill.Fid=T_PurchaseBillDetail.FBillId
inner join T_Merchandise
on T_PurchaseBillDetail.FmerchandiseId=T_Merchandise.Fid



mysql计算每个商品的总销售额 数据库计算销售额_结果集_06



接着需要统计每张采购单的总交易额,因为我们不关系每张采购单内部的交易明细。将
上面的结果集按照采购单号进行分组,然后使用聚合函数 SUM()就可以轻松的统计每张采
购单的总交易额了。SQL语句如下:


select T_PurchaseBill.Fnumber,sum(T_PurchaseBillDetail.FCount*T_Merchandise.FPrice)
from T_PurchaseBill
inner join T_PurchaseBillDetail
on T_PurchaseBill.Fid=T_PurchaseBillDetail.FBillId
inner join T_Merchandise
on T_PurchaseBillDetail.FmerchandiseId=T_Merchandise.Fid
group by T_PurchaseBill.fnumber



mysql计算每个商品的总销售额 数据库计算销售额_窗口函数_07



这样便统计出了采购单的总交易额, 接着需要按照每张采购单的总交易额对采购单进行
分级,显然使用CASE……WHEN语句很容易的实现这个功能:


select T_PurchaseBill.Fnumber,sum(T_PurchaseBillDetail.FCount*T_Merchandise.FPrice),
case
	when sum(T_PurchaseBillDetail.FCount*T_Merchandise.FPrice)<=500 then '小额'
	when sum(T_PurchaseBillDetail.FCount*T_Merchandise.FPrice)>=1000 then '大额'
	else '普通'
end
from T_PurchaseBill
inner join T_PurchaseBillDetail
on T_PurchaseBill.Fid=T_PurchaseBillDetail.FBillId
inner join T_Merchandise
on T_PurchaseBillDetail.FmerchandiseId=T_Merchandise.Fid
group by T_PurchaseBill.fnumber



mysql计算每个商品的总销售额 数据库计算销售额_数据库_08



这样就完成了要求的功能。不过上面的 SQL 有一个问题,那就是计算每张采购单总交
易额的聚合函数“SUM(purchasebilldetail.FCount*merchandise.FPrice)”出现了很多次,这违
反了DRY 原则造成后期维护的困难,而且有可能造成性能问题,因为乘法运算是非常低效
的。可以使用子查询来解决这个问题,在子查询中计算每张采购单总交易额,这样在外部只
要引用计算结果就可以了。SQL语句如下:


select t.BillNumber,t.TotalAmount,
case
	when t.TotalAmount<=500 then '小额'
	when t.TotalAmount>=1000 then '大额'
	else '普通'
end
from 
(
	select T_PurchaseBill.Fnumber as BillNumber,sum(T_PurchaseBillDetail.FCount*T_Merchandise.FPrice) as TotalAmount
	from T_PurchaseBill
	inner join T_PurchaseBillDetail
	on T_PurchaseBill.Fid=T_PurchaseBillDetail.FBillId
	inner join T_Merchandise
	on T_PurchaseBillDetail.FmerchandiseId=T_Merchandise.Fid
	group by T_PurchaseBill.fnumber
)t



mysql计算每个商品的总销售额 数据库计算销售额_数据库_09





检索所有重叠日期销售单


要求索所有重叠日期销售单。重叠日期销售单的定义如下:如果销售单 t1 的开单日期
介于销售单t2的开单日期和确认日期之间的话,我们就说 t1与 t2日期重叠。
类似的需求在生产排程、工作计划安排等场景也可以看到。这种自身与自身进行比较的
需求一般都可以使用自连接来解决。SQL语句如下:


select t1.fnumber,t1.FMakeDate,t1.FConfirmDate,t2.Fnumber,t2.FMakeDate,t2.FConfirmDate
from T_SaleBill t1,T_SaleBill t2
where t2.FMakeDate>=t1.FMakeDate
and t2.FMakeDate<=t1.FConfirmDate
and t1.FNumber<>t2.FNumber



mysql计算每个商品的总销售额 数据库计算销售额_mysql计算每个商品的总销售额_10



为了更加清晰的理解上面的SQL语句, 我们首先查看没有 WHERE 子句的自连接部分,
观察一下它是如何能在一行中看到其他所有销售单的:


select t1.fnumber,t1.FMakeDate,t1.FConfirmDate,t2.Fnumber,t2.FMakeDate,t2.FConfirmDate
from T_SaleBill t1,T_SaleBill t2


mysql计算每个商品的总销售额 数据库计算销售额_结果集_11


结果集数据量是非常大的。这个结果集是 T_SaleBill 表自连接的结果,一共是 36 条
记录(6*6)。从上面的结果集中很容易的找到重叠日期:只要返回 t2.FMakeDate 介于
t1.FMakeDate 和 t1.FConfirmDate 之间的记录即可。这样只要再增加下面的 WHERE 子句
即可:


where t2.FMakeDate>=t1.FMakeDate
and t2.FMakeDate<=t1.FConfirmDate
and t1.FNumber<>t2.FNumber