Oracle 中使用层次查询方便处理财务报表
发表于:2007-07-13来源:作者:点击数:
标签:
本文介绍了如何使用 Oracle 中的Connect by 子句,并结合一个实例,完成了对一张资产负债表的计算。 Oracle 中Connect By 子句对在关系表上表现层次关系提供了方便。使用Connect by 子句需要在表中定义两个字段,一个是父节点字段,一个是节点字段。其中节点
本文介绍了如何使用Oracle 中的Connect by 子句,并结合一个实例,完成了对一张资产负债表的计算。
Oracle 中Connect By 子句对在关系表上表现层次关系提供了方便。使用Connect by 子句需要在表中定义两个字段,一个是父节点字段,一个是节点字段。其中节点字段一般来说是主键。
例如我们作一张资产负债表
数据来源:http://www.adbc.com.cn/XXLR1.ASP?ID=5211
资 产 |
期末余额 |
负债及所有者权益 |
期末余额 |
流动资产 |
4256.45 |
流动负债 |
7453.74 |
现金 |
2.00 |
短期存款 |
305.54 |
存放中央银行款项 |
160.77 |
财政性存款 |
411.80 |
存放同业款项 |
18.34 |
向中央银行借款 |
6485.05 |
短期贷款 |
4103.41 |
同业存放款项 |
2.15 |
其他流动资产 |
71.93 |
其他流动负债 |
249.20 |
长期资产 |
3287.75 |
长期负债 |
0.07 |
中长期贷款 |
3262.89 |
发行长期债券 |
|
减:贷款呆账准备 |
73.71 |
其他长期负债 |
0.07 |
固定资产净值 |
77.58 |
|
|
其他长期资产 |
20.99 |
|
|
无形、递延及其它资产 |
0.52 |
所有者权益 |
190.91 |
|
|
其中:实收资本 |
165.15 |
资产总计 |
7644.72 |
负债及所有者权益合计 |
7644.72 |
Create table balance_sheet (BS_ID INTEGER ,BS_PID INTEGER ,BS_NAME VARCHAR2(100) ,BS_VALUE NUMBER(10) );BS_ID 项目代码 BS_PID 项目父代码 BS_Name 项目名称 BS_VALUE 数据列
插入
测试数据
insert into balance_sheet values(1,0,'流动资产',4256.45);
insert into balance_sheet values(2,1,'现金',2.00);
insert into balance_sheet values(3,1,'存放中央银行款项',160.77);
insert into balance_sheet values(4,1,'存放同业款项',18.34);
insert into balance_sheet values(5,1,'短期贷款', 4103.41);
insert into balance_sheet values(6,1,'其他流动资产',71.93);
insert into balance_sheet values(7,0,'长期资产',3287.75);
insert into balance_sheet values(8,7,'中长期贷款', 3262.89);
insert into balance_sheet values(9,7,'减:贷款呆账准备',73.71);
insert into balance_sheet values(10,7,'固定资产净值',77.58);
insert into balance_sheet values(11,7,'其他长期资产',20.99);
insert into balance_sheet values(12,0,'无形、递延及其它资产',0.52);
insert into balance_sheet values(13,0,'资产总计',7644.72);
insert into balance_sheet values(14,0,'流动负债',7453.74);
insert into balance_sheet values(15,14,'短期存款',305.54);
insert into balance_sheet values(16,14,'财政性存款',411.80);
insert into balance_sheet values(17,14,'向中央银行借款',6485.05);
insert into balance_sheet values(18,14,'同业存放款项',2.15);
insert into balance_sheet values(19,14,'其他流动负债',249.20);
insert into balance_sheet values(20,0,'长期负债',0.07);
insert into balance_sheet values(21,20,'发行长期债券',null);
insert into balance_sheet values(22,20,'其他长期负债', 0.07);
insert into balance_sheet values(23,0,'所有者权益',190.91);
insert into balance_sheet values(24,23,'其中:实收资本',165.15);
insert into balance_sheet values(25,0,'负债及所有者权益合计',7644.72);
commit;
显示全部数据:
select bs_name,bs_value from balance_sheet
connect by prior bs_id = bs_pid
start with bs_pid = 0 –可以省略
流动资产 |
4256.45 |
现金 |
2 |
存放中央银行款项 |
160.77 |
存放同业款项 |
18.34 |
短期贷款 |
4103.41 |
其他流动资产 |
71.93 |
长期资产 |
3287.75 |
中长期贷款 |
3262.89 |
减:贷款呆账准备 |
73.71 |
固定资产净值 |
77.58 |
其他长期资产 |
20.99 |
无形、递延及其它资产 |
0.52 |
资产总计 |
7644.72 |
流动负债 |
7453.74 |
短期存款 |
305.54 |
财政性存款 |
411.8 |
向中央银行借款 |
6485.05 |
同业存放款项 |
2.15 |
其他流动负债 |
249.2 |
长期负债 |
0.07 |
发行长期债券 |
|
其他长期负债 |
0.07 |
所有者权益 |
190.91 |
其中:实收资本 |
165.15 |
负债及所有者权益合计 |
7644.72 |
显示一个节点的数据
select bs_name,bs_value from balance_sheet
connect by prior bs_id = bs_pid
start with bs_pid = 1
其中connect by 定义父子连接关系
start with 定义开始节点,这个子句可以省略,表示自动将全部节点展开
流动资产 |
4256.45 |
现金 |
2 |
存放中央银行款项 |
160.77 |
存放同业款项 |
18.34 |
短期贷款 |
4103.41 |
其他流动资产 |
71.93 |
(流动资产节点数据)
显示层次结构
select (case when level = 1 then ' '||bs_name
when level = 2 then ' '||bs_name
end ) bs_name
,bs_value from balance_sheet
connect by prior bs_id = bs_pid
start with bs_pid = 0
其中引用了level字段,表示层次,它是每张表默认的字段,其他默认的字段还有rownum
流动资产 |
4256.45 |
现金 |
2 |
存放中央银行款项 |
160.77 |
存放同业款项 |
18.34 |
短期贷款 |
4103.41 |
其他流动资产 |
71.93 |
长期资产 |
3287.75 |
中长期贷款 |
3262.89 |
减:贷款呆账准备 |
73.71 |
固定资产净值 |
77.58 |
其他长期资产 |
20.99 |
无形、递延及其它资产 |
0.52 |
资产总计 |
7644.72 |
流动负债 |
7453.74 |
短期存款 |
305.54 |
财政性存款 |
411.8 |
向中央银行借款 |
6485.05 |
同业存放款项 |
2.15 |
其他流动负债 |
249.2 |
长期负债 |
0.07 |
发行长期债券 |
|
其他长期负债 |
0.07 |
所有者权益 |
190.91 |
其中:实收资本 |
165.15 |
负债及所有者权益合计 |
7644.72 |
(根据层次来实现缩进风格)
以下功能 9i 及以上版本支持
层次内排序
select (case when level = 1 then ' '||bs_name
when level = 2 then ' '||bs_name
end ) bs_name
,bs_value from balance_sheet
connect by prior bs_id = bs_pid
start with bs_id = 1 or bs_id = 7
ORDER SIBLINGS BY bs_value desc
流动资产 |
4256.45 |
短期贷款 |
4103.41 |
存放中央银行款项 |
160.77 |
其他流动资产 |
71.93 |
存放同业款项 |
18.34 |
现金 |
2 |
长期资产 |
3287.75 |
中长期贷款 |
3262.89 |
固定资产净值 |
77.58 |
减:贷款呆账准备 |
73.71 |
其他长期资产 |
20.99 |
取遍历路径
select
ltrim(sys_connect_by_path( BS_Name,'|'),'|') path,
(case when level = 1 then ' '||bs_name
when level = 2 then ' '||bs_name
end ) bs_name
,bs_value
from balance_sheet
connect by prior bs_id = bs_pid
start with bs_pid = 0
流动资产 |
流动资产 |
4256.45 |
流动资产|现金 |
现金 |
2 |
流动资产|存放中央银行款项 |
存放中央银行款项 |
160.77 |
流动资产|存放同业款项 |
存放同业款项 |
18.34 |
流动资产|短期贷款 |
短期贷款 |
4103.41 |
流动资产|其他流动资产 |
其他流动资产 |
71.93 |
层次计算
这里层次计算是指根据父子节点关系进行汇总,也就是说 父节点 = SUM(子节点)。但是在财务报表父指标,不一定是子指标的叠加,也可能是几个子指标减去另外几个子指标。例如:
长期资产 = 中长期贷款 – 贷款呆账准备 +固定资产净值 +其他长期资产。
为了实现这种情况,我们建一个字段BS_Dir来表示加减方向 1表示 加,-1表示减
这样 父节点 = SUM(子节点 * Direction)
SELECT
SUBSTR (PATH, 0, INSTR (PATH, '|', -1, 1) - 1) Par_path ,
sum(bs_value * bs_dir)
FROM (SELECT BS_ID,BS_PID, LTRIM (SYS_CONNECT_BY_PATH (bs_name, '|'), '|') PATH,
bs_value,bs_dir
FROM balance_sheet
CONNECT BY PRIOR bs_id = bs_pid
START WITH bs_pid = 0)
group by SUBSTR (PATH, 0, INSTR (PATH, '|', -1, 1) - 1)
长期负债 |
0.07 |
长期资产 |
3287.75 |
流动负债 |
7453.74 |
流动资产 |
4356.45 |
所有者权益 |
165.15 |
|
30478.88 |
竟然有意外的收获,原表中的数据流动资产是错的!!!也许是我对业务
知识了解不够。如果您知道原因,还清指点。数据的最后一行是对所有原表第一层节点的叠加,如果希望得到资产和负债的总计数据,需要对节点顺序进行重新调整,我的想法是建立一个表示汇总关系的逻辑的BS_LID 和BS_LParID 。
原文转自:http://www.ltesting.net