`
webcode
  • 浏览: 5943313 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

由简到难生成数据库报表(一)

 
阅读更多

在接下来,我想借助一个例子,来加深大家对数据库报表的认识,由简到难生成数据库报表!

这里创建一个简化的进销系统,系统中只有销售单和采购单,不存在红冲单据及其库存、退货等单据。由于销售单和采购单存在主从结构,所以将这两张表中的主从数据分别保存在不同的表中。下面是这个系统中表之间的关系图:


表 T_Person 为人员表,FId字段为主键,FNumber 字段为人员工号,FName 字段为人

员姓名,FManagerId字段为上级主管主键(指向T_Person表的 FId字段的外键) 。


表T_Merchandise为商品表,FId字段为主键,FNumber字段为产品编号,FName字段

为商品名,FPrice为商品价格;

表T_SaleBill为销售单主表,FNumber字段为销售单编号,

FBillMakerId字段为开单人主键(指向T_Person表的 FId字段的外键) ,FMakeDate 字段为

制单日期,FConfirmDate字段为确认日期;


表T_SaleBillDetail为销售单明细记录,FId字段

为主键,FBillId字段为主表主键(指向 T_SaleBill 表的 FId 字段的外键) ,FMerchandiseI

字段为商品主键(指向T_Merchandise表的FId字段的外键) ,FCount字段为销售数量。


表T_PurchaseBill为采购单主表,FNumber字段为采购单编号,FBillMakerId字段为开

单人主键(指向T_Person表的FId字段的外键), FMakeDate字段为制单日期, FConfirmDat

字段为确认日期;


表T_PurchaseBillDetail为采购单明细记录,FId字段为主键,FBillId字段

为主表主键(指向T_PurchaseBill表的FId字段的外键) , FMerchandiseId字段为商品主键(指

向T_Merchandise表的FId字段的外键),FCount字段为采购数量。

下面是创建表的SQL语句以及插入数据的SQL语句:

--创建T_Person表
create table T_Person
(
	FId varchar(20) not null,
	FNumber varchar(20),
	FName varchar(20),
	FManagerId varchar(20),
	primary key(FId),
	foreign key(FManagerId) references T_Person(Fid)
)
--创建T_Merchandise表
create table T_Merchandise
(
	FId varchar(20) not null,
	FNumber varchar(20),
	FName varchar(20),
	FPrice int,
	primary key(fid)
)
--创建T_SaleBill表
create table T_SaleBill
(
	FId varchar(20) not null,
	FNumber varchar(20),
	FBillMakerId varchar(20),
	FMakeDate datetime,
	FConfirmDate datetime,
	primary key(fid),
	foreign key(Fbillmakerid) references T_Person(fid)
)
--创建T_SaleBillDetail表
create table T_SaleBillDetail
(
	FId varchar(20),
	FBillId varchar(20),
	FMerchandiseId varchar(20),
	FCount int,
	primary key(fid),
	foreign key(Fbillid) references T_SaleBill(fid),
	foreign key(Fmerchandiseid) references T_Merchandise(fid)
)
--创建T_PurchaseBill表
create table T_PurchaseBill
(
	Fid varchar(20) not null,
	FNumber varchar(20),
	FBillMakerId varchar(20),
	FMakeDate datetime,
	FConfirmDate datetime,
	primary key(fid),
	foreign key(FBillMakerId) references T_Person(fid)
)
--创建T_PurchaseBillDetail表
CREATE  TABLE  T_PurchaseBillDetail
(
	FId  VARCHAR(20)  NOT  NULL  ,
	FBillId VARCHAR(20),
	FMerchandiseId  VARCHAR(20),
	FCount  INT,PRIMARY KEY  (FId),
	FOREIGN KEY  (FBillId)  REFERENCES  T_PurchaseBill(FId),
	FOREIGN  KEY  (FMerchandiseId) REFERENCES T_Merchandise(FId)
) 
--首先向T_Person、T_Merchandise两张表中插入演示数据: 
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00001','1','Robert',NULL)
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00002','2','John','00001')
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00003','3','Tom','00001')
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00004','4','Jim','00003')
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00005','5','Lily','00002')
insert into T_Person(FId,FNumber,FName,FManagerId) 
values('00006','6','Merry','00003')
insert into T_Merchandise(FId,FNumber,FName,FPrice) 
values('00001','1','Bacon',30)
insert into T_Merchandise(FId,FNumber,FName,FPrice) 
values('00002','2','Cake',2)
insert into T_Merchandise(FId,FNumber,FName,FPrice) 
values('00003','3','Apple',6

--  还要向T_SaleBill和T_PurchaseBill表中插入演示数据: 
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00001','1','00006','2007-03-15','2007-05-15')
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00002','2',null,'2006-01-25','2006-02-03')
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00003','3','00001','2006-02-12','2007-01-11')
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00004','4','00003','2008-05-25','2008-06-15')
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00005','5','00005','2008-03-17','2007-04-15')
insert into T_SaleBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00006','6','00002','2002-02-03','2007-11-11')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00001','1','00006','2007-02-15','2007-02-15')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00002','2','00004','2003-02-25','2006-03-03')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00003','3','00001','2007-02-12','2007-07-12')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00004','4','00002','2007-05-25','2007-06-15')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00005','5','00002','2007-03-17','2007-04-15')
insert into T_PurchaseBill(FId,FNumber,FBillMakerId,FMakeDate,FConfirmDate) 
values('00006','6',null,'2006-02-03','2006-11-20')

--  向T_SaleBillDetail表和T_PurchaseBillDetail表中插入演示数据: 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00001','00001','00003',20) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00002','00001','00001',30) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00003','00001','00002',22) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00004','00002','00003',12) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00005','00002','00002',11) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00006','00003','00001',60) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00007','00003','00002',2) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00008','00003','00003',5) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00009','00004','00001',16) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00010','00004','00002',8) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00011','00004','00003',9) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00012','00005','00001',6) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00013','00005','00003',26) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00014','00006','00001',66) 
insert into T_SaleBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00015','00006','00002',518) 
 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00001','00001','00002',12) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00002','00001','00001',20) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00003','00002','00001',32) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00004','00002','00003',18) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00005','00002','00002',88) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00006','00003','00003',19) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00007','00003','00002',6) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00008','00003','00001',2) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00009','00004','00001',20) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00010','00004','00003',18) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00011','00005','00002',19) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00012','00005','00001',26) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00013','00006','00003',3) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00014','00006','00001',22) 
insert into T_PurchaseBillDetail(FId,FBillId,FMerchandiseId,FCount) 
values('00015','00006','00002',168) 

显示制单人详细信息

要求显示每张销售单的编号、制单人、制单日期等信息,可以使用简单的 SELECT 语
句来完成这个任务:
SELECT FNumber, FBillMakerId, FMakeDate
FROM T_SaleBill

这里的 FBillMakerId 显示的是制单人在 T_Person 表中的主键,业务人员很难将这个编
号与人名对应起来,因此必须将其转换为制单人的姓名。FBillMakerId 字段保存的是
T_Person表的主键,而T_Person表的FName字段则为人员的名称,因此将这两个表做连接
查询即可,SQL语句如下:
SELECT salebill.FNumber,person.FName,salebill.FMakeDate
FROM T_SaleBill salebill
INNER JOIN T_Person person
ON salebill.FBillMakerId=person.FId;

这个查询结果已经能够显示开票人的姓名, 不过仔细观察会发现编号为 2的记录并没有
显示在执行结果中,这是因为这条记录的 FBillMakerId 字段为空值,所以不能与 T_Person
表中的任何记录进行匹配,而内连接不会显示没有匹配的行。一般情况下即使没有开单人也
要将这张单据显示出来,这时就要使用外部连接了,如下:

因为 T_SaleBill表中的记录必须全部显示到结果集中,而 T_SaleBill为左表,所以使用
左外部连接。执行完毕我们就能在输出结果中看到上面的执行结果:


这样没有开票人的单据也显示出来了,不过这里其对应的开票人处显示的是 NULL,这
让业务人员感到难以理解,我们使用 COALESCE()函数来解决这个问题。前面章节讲到
COALESCE()函数支持多个参数, 该函数返回参数中的第一个非空值, 这样 COALESCE(f1,f2)
就可以实现“如果 f1为空则将 f2做为返回值”这样的空值处理逻辑了。将SQL语句做如下改
造:

select saleBill.fid,coalesce(T_person.fname,'没有开单人'),FMakeDate from t_SaleBill SaleBill
left outer join T_person
on T_Person.FId=saleBill.FBillMakerId

显示销售单的信息

要求列出所有销售单的详细信息,每行显示销售单的每一条销售记录,同时每行头部要
显示此行所属的销售单的信息,比如单号、开单人、开单日期等。T_SaleBillDetail表保存的
是销售单的每一条销售记录,T_SaleBill表保存的是销售单的头信息,T_SaleBillDetail表的
FMerchandiseId字段保存的是销售的商品主键,而 T_SaleBill表的 FBillMakerId字段保存的
是开单人的主键,只要对这四张表做连接查询即可。由于 T_SaleBill表的 FBillMakerId字段
有可能为空,所以在 T_SaleBill 表和 T_Person 表进行连接的时候要使用左外连接,而为了
提高查询效率其他连接都使用内连接。SQL语句如下:
select T_SaleBill.FNumber,coalesce(T_Person.FName,'没有开单人') 开单人,T_SaleBill.FMakeDate,T_Merchandise.Fname,T_Merchandise.FPrice
from T_Salebill
left outer join T_Person
on T_Person.FId=T_SaleBill.FBillMakerId
inner join T_SaleBillDetail
on T_SaleBillDetail.FBillId=T_SaleBill.Fid
inner join T_Merchandise
on T_Merchandise.Fid=T_SaleBillDetail.FMerchandiseId
order by T_SaleBill.FMakeDate desc


计算收益

要求计算每种商品的总收益, 受收益的定义为所有的销售单中该商品的销售总额减去所
有的采购单中该商品的购买总额。
T_SaleBillDetail 表中保存的所有的销售单详细记录,因此下面的 SQL 语句可以检索
所有产品的销售记录,包括产品名和销售额:
select T_Merchandise.FName,T_Merchandise.FPrice*T_SaleBillDetail.Fcount 销售额
from T_Merchandise
inner join T_SaleBillDetail
on T_Merchandise.Fid=T_SaleBillDetail.FMerchandiseId


同理下面的SQL语句则可以检索所有产品的购买记录,包括产品名和采购额:
select T_Merchandise.FName,T_PurchaseBillDetail.Fcount*T_Merchandise.FPrice 采购额
from T_Merchandise
inner join T_PurchaseBillDetail
on T_Merchandise.Fid=T_PurchaseBillDetail.FmerchandiseId


将上述两个 SQL 语句进行 UNION 运算就可以将两个检索的结果集合并了,不过这样
就无法区分销售单和采购单了。为了区分销售单和采购单,同时方便后续运算,我们将检索
产品的购买记录的金额全部取负值,这样就可以表示采购行为的金额为负值:

这样就可以将销售记录和采购记录同时显示了:
select T_Merchandise.FName,T_Merchandise.FPrice*T_SaleBillDetail.Fcount Amount
	from T_Merchandise
	inner join T_SaleBillDetail
	on T_Merchandise.Fid=T_SaleBillDetail.FMerchandiseId
	union all
	select T_Merchandise.FName,T_PurchaseBillDetail.Fcount*T_Merchandise.FPrice*(-1) Amount
	from T_Merchandise
	inner join T_PurchaseBillDetail
	on T_Merchandise.Fid=T_PurchaseBillDetail.FmerchandiseId


这个结果集中列出了每一条详细交易记录,包括商品名和交易金额,销售行为的交易额
为正值,而购买行为的交易额为负值。有个这个执行结果,只要将这个 SQL 语句做为子查
询,然后按照商品名进行分组,然后计算交易金额的总和。SQL语句如下:
select detail.fname,sum(amount) from
(
	select T_Merchandise.FName,T_Merchandise.FPrice*T_SaleBillDetail.Fcount Amount
	from T_Merchandise
	inner join T_SaleBillDetail
	on T_Merchandise.Fid=T_SaleBillDetail.FMerchandiseId
	union all
	select T_Merchandise.FName,T_PurchaseBillDetail.Fcount*T_Merchandise.FPrice*(-1) Amount
	from T_Merchandise
	inner join T_PurchaseBillDetail
	on T_Merchandise.Fid=T_PurchaseBillDetail.FmerchandiseId
) as detail
group by fname




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics