有什么可以帮助到您的?

“一体化”平台报表、账簿查询的 SQL实现原理

一、报表查询
1.“一体化”平台中科目余额表
“一体化“平台中科目余额表查询主要涉及到期初余额、当期发生额、累计发生额及期末余额。查询参数主要包括:单位内码、查询期间、显示级别。
SQL语句编写思路:利用并集合运算将期初数、当期借贷发生额、累计借贷发生额合并为一个结果集,然后利用科目表科目编码的层次结构关系进行2次联结,计算出自上而下各科目期初数、发生额、累计发生额,最后根据科目性质计算出期末余额。

(
SELECT acctid,acctcode,acctname,levelno,dc
FROM t_fmaccount
WHERE acctsystypeid = &acctsystype
),
i AS
(
SELECT r.ACCOUNT,DECODE(r.dc,a.dc,r.startbal,-r.startbal) startbal,NULL c_deb,NULL c_cre,NULL t_deb,NULL t_cre
FROM t_fmyearinitbalrec r
JOIN t_fmaccount a
ON r.account = a.acctid
WHERE r.hsagency = &hsagency
AND r.acctsystype = &acctsystype --获取期初数
UNION ALL
SELECT p.account,null,SUM(DECODE(p.dc,1,amt)),SUM(DECODE(p.dc,-1,amt)),NULL,NULL
FROM t_glrecordfm p
WHERE p.hsagency = &hsagency
AND p.acctsystype = &acctsystype
AND p.term = &term
GROUP BY p.account --当期借贷发生额
UNION ALL
SELECT p.account,null,null,null,SUM(DECODE(p.dc,1,amt)),SUM(DECODE(p.dc,-1,amt))
FROM t_glrecordfm p
WHERE p.hsagency = &hsagency
AND p.acctsystype = &acctsystype
AND p.term <= &term
GROUP BY p.account --累计借贷发生额
)
SELECT acctcode,levelno,acctname,startbal,c_deb,c_cre,t_deb,t_cre,DECODE(dc,1,'借','贷') dc
, CASE dc
WHEN 1 THEN NVL(startbal,0) + NVL(t_deb,0) - NVL(t_cre,0)
ELSE NVL(startbal,0) - NVL(t_deb,0) + NVL(t_cre,0)
END AS balance
FROM(
SELECT a2.acctcode,a2.levelno,a2.acctname
, sum(i.startbal) startbal
, sum(i.c_deb) c_deb
, sum(i.c_cre) c_cre
, sum(i.t_deb) t_deb
, sum(i.t_cre) t_cre,a2.dc
FROM a a1
JOIN i
ON a1.acctid = i.account
JOIN a a2
ON regexp_like(a1.acctcode,'^('||a2.acctcode||')[[:digit:]]*$')
GROUP BY a2.acctcode,a2.levelno,a2.acctname,a2.dc
HAVING a2.levelno <= &levelno
)
ORDER BY acctcode;

执行上述代码,弹出输入对话框,需要输入一些参数:hsagency-查询单位的编码,acctsystype-核算单位类型,term-查询报表期间,levelno-显示级别,如下图所示:
查询单位编码与核算类型构成唯一主体的会计报表,hsagency引用t_pubagency表,acctsystype引用t_fmaccountsystemtype表。在本图中,“135“为行政单位核算类别。
执行结果如下:
上述代码为通用型,即根据变量输入的不同,生成不同单位、不同期间的科目余额表(类似于资产负债表),表中acctcode-科目编码,levelno-科目级别,acctname-科目名称,startbal-年初数,c_deb-当期借方发生额,c_cre-当期贷方发生额,t_deb-累计借方发生额,t_cre-累计贷方发生额,dc-余额方向,balance-期末余额。
为节省篇幅,示例代码中没有考虑凭证状态,考虑凭证状态时,应将凭证主表(t_fmvoucher)与凭证状态表(t_fmvoucherstatus)关联。
2.行政事业单位往来余额表
往来余额表显示要素主要包括:科目名称、往来名称、期初数、当期借贷发生额、累计借贷发生额、余额方向及期末余额。与科目余额表查询类似,输入参数为单位编码、会计期间。
SQL语句编写思路:利用并集合运算,从余额明细表(t_fmyearinitbalrecdetail)获取往来科目明细数据(calagency列不为0与空值),从凭证明细表(t_glrecordfm)中获取指定期间往来科目明细记录及年初至当前期间明细记录,然后分别与科目表(t_fmaccount)、往来单位信息表(t_calagency)关联并汇总。
WITH i AS
(
SELECT d.ACCOUNT
, d.calagency
, DECODE(d.dc,a.dc,d.startbal,-d.startbal) startbal
, NULL c_deb
, NULL c_cre
, NULL t_deb
, NULL t_cre
FROM t_fmyearinitbalrecdetail d
JOIN t_fmaccount a
ON d.account = a.acctid
WHERE d.hsagency = &hsagency
AND d.acctsystype = &acctsystype --获取期初数,根据科目性质,调整余额正负性
AND COALESCE(calagency,0) <> 0 --剔除0与空值
UNION ALL
SELECT ACCOUNT
, calagency
, NULL
, DECODE(dc,1,amt)
, DECODE(dc,-1,amt)
, NULL
, NULL
FROM t_glrecordfm
WHERE hsagency = &hsagency
AND acctsystype = &acctsystype
AND term = &term --当期往来明细记录
AND COALESCE(calagency,0) <> 0
UNION ALL
SELECT ACCOUNT
, calagency
, NULL
, NULL
, NULL
, DECODE(dc,1,amt) c_deb
, DECODE(dc,-1,amt) c_cre
FROM t_glrecordfm
WHERE hsagency = &hsagency
AND acctsystype = &acctsystype
AND term <= &term --年初至指定期间往来明细记录
AND COALESCE(calagency,0) <> 0
)
SELECT a.acctcode||'-'||acctname acctname
, c.code||'-'||c.name cname
, sum(i.startbal) startbal
, sum(i.c_deb) c_deb
, sum(i.c_cre) c_cre
, sum(i.t_deb) t_deb
, sum(i.t_cre) t_cre
, decode(a.dc,1,'借','贷') dc
, SUM(DECODE(a.dc,1,nvl(i.startbal,0)+NVL(i.t_deb,0)-NVL(i.t_cre,0),nvl(i.startbal,0)-NVL(i.t_deb,0)+NVL(i.t_cre,0))) balance
FROM i
JOIN t_fmaccount a
ON i.account = a.acctid
JOIN t_calagency c
ON c.itemid = i.calagency
GROUP BY a.acctcode||'-'||acctname,c.code||'-'||c.name,decode(a.dc,1,'借','贷')
ORDER BY 1,2;
执行上述SQL语句,弹出输入变量对话框,分别输入单位编码、核算类型及指定期间,结果如下:
3.总预算收支报表
总预算收入报表一般对收入科目按功能进行分类汇总,收入科目如:一般公共预算本级收入、政府性基金预算本级收入、财政专户管理资金收入、专用基金收入;与此对应,总预算支出报表也是按上述支出科目进行功能分类,如一般公共预算本级支出等。上述报表生成的方式相同,本例将总预算报表分为收入报表、支出报表,并以支出报表为例编写SQL脚本。
SQL编写思路:从凭证明细表中获取指定支出科目的按功能分类的汇总数,然后与功能分类信息表关联,设法生成自上而下按功能分类的金额。显示要素:功能分类编码、功能分类名称、金额、显示级别。
由于总预算财务核算数据量较大,应使用临时表(事务级)为宜,将当期发生额、累计发生额汇总后,插入到临时表,最后与功能信息表联结,产生支出报表。
示例代码如下:
--步骤一:创建事务级临时表
CREATE GLOBAL TEMPORARY TABLE tran_temp
(
CODE VARCHAR2(50) PRIMARY KEY,
NAME VARCHAR2(100) NOT NULL,
c_amt NUMBER(18,2),
t_amt NUMBER(18,2)
) ON COMMIT DELETE ROWS;
--插入汇总数据
INSERT INTO tran_temp
SELECT f.code,f.name,SUM(c_amt),SUM(t_amt)
FROM (
SELECT p2.expfunc,p2.dc*p2.amt c_amt,NULL t_amt
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_fmaccount a
ON a.acctid = p2.account
WHERE p1.hsagency = &hsagency
AND p1.acctsystype = &acctsystype
AND regexp_like(a.acctcode,'^('||&acctcode||')\d*$')
AND p1.vchattr <> 7
AND p1.term = &term --当期发生额
UNION ALL
SELECT p2.expfunc,null,p2.dc*p2.amt
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_fmaccount a
ON a.acctid = p2.account
WHERE p1.hsagency = &hsagency
AND p1.acctsystype = &acctsystype
AND regexp_like(a.acctcode,'^('||&acctcode||')\d*$')
AND p1.vchattr <> 7
AND p1.term <= &term --年初至当期累计发生额
) i
JOIN t_pubfunc f
ON i.expfunc = f.itemid
GROUP BY f.code,f.name;
--步骤三:执行查询
SELECT f.code,f.name,f.levelno,SUM(t.c_amt) c_amt,SUM(t.t_amt) t_amt
FROM t_pubfunc f
JOIN tran_temp t
ON regexp_like(t.code,'^('||f.code||')\d*')
GROUP BY f.code,f.name,f.levelno
ORDER BY f.code;
--提交事务
COMMIT;
在事务级临时表“tran_temp”创建后,执行步骤2,弹出输入变量对话框如下:
输入参数释义:
Hsagency-引用t_pubagency表,核算单位内码,一般为财政局;
Acctsystype-引用t_systemtype表,核算类型,为总预算;
Acctsystype-引用t_fmaccountsystemtype表,科目代码,为“一般公共预算本级收入”、“一般公共预算本级支出”等支出科目编码;
Term-会计期间。
单击“确定”,则将汇总结果插入到tran_temp临时表。
执行步骤三语句,则输出以下结果:
最后执行提交,释放临时数据。
对于总预算收入报表查询,方法类似,只需将步骤二中的“p2.dcp2.amt”修改为”-p2.dcp2.amt”即可,也可以根据输入的科目性质对正负性进行判断,这里不再赘述。
4.行政事业单位经费支出报表
行政事业单位支出报表,主要是对支出科目按经济用途进行的分类,因经费支出科目按支出资金来源分为财政拨款支出、其他资金支出,按资金来源进一步细分为基本支出、项目支出。因此需要对上述分类在报表中一并反映。
--以行政单位经费支出报表为例:
WITH i AS
(
SELECT '['||a.acctcode||']'||a.acctname acctname,e.code,SUM(p2.dc*amt) amt
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_pubexpeconormic e
ON e.itemid = p2.expeconormic
JOIN t_fmaccount a
ON a.acctid = p2.account
WHERE p2.hsagency = &hsagency
AND p2.acctsystype = &acctsystype
AND p1.vchattr <> 7 --剔除结转凭证
AND p2.term <= &term
GROUP BY '['||a.acctcode||']'||a.acctname,e.code
)
SELECT *
FROM
(
SELECT e.code,e.levelno,e.name,i.acctname
, SUM(i.amt) amt
FROM t_pubexpeconormic e
JOIN i
ON regexp_like(i.code,'^('||e.code||')\d*')
GROUP BY e.code,e.levelno,e.name,i.acctname
)
PIVOT
(SUM(amt) FOR acctname IN('[50010101]基本支出' "[50010101]基本支出"
,'[50010102]项目支出' "[50010102]项目支出"
,'[50010201]非项目资金' "[50010201]非项目资金"
,'[50010202]项目资金' "[50010202]项目资金")
)
ORDER BY CODE;
以某行政单位12月份经费支出报表为例,结果如下图所示:
本例的难点是pivot中in列表的生成方法,软件对列表的生成一般采用动态生成字符串变量方式,然后串联、拼接成SQL语句字符串,利用execute immediate来执行。对于in列表的生成方法,可以通过以下语句生成:
SELECT listagg(CHR(39)||'['||acctcode||']'||acctname||chr(39)||SPACE(1)||CHR(34)||'['||acctcode||']'||acctname||CHR(34),',')
WITHIN GROUP(ORDER BY acctcode) acctname
FROM t_fmaccount
WHERE acctsystypeid = &acctsystype
AND regexp_like(acctcode,'^(5001)\d+$')
AND isleaf = 1;
执行上述语句,输入经费支出科目编码“5001“,输入行政单位核算类型编码135(事业一般为136,根据系统设置不同改变),就能输出透视列列表。输出结果如下:
二、账簿查询
1.总分类账查询
总分类账一般是每月产生一笔汇总记录,与期初余额合并,利用窗口函数生成余额,这种查询比较简单。需要注意的是,凭证明细表中记录的是末级科目,当查询总账科目时,需要在凭证明细表中检索总账科目下的所有子级科目。
示例代码如下:
WITH i AS
(
SELECT r.acctyear,r.term,'年初数' remark
, DECODE(a.dc,1,DECODE(a.dc,r.dc,r.startbal,-startbal)) deb
, DECODE(a.dc,-1,DECODE(a.dc,r.dc,r.startbal,-startbal)) cre
, a.dc
FROM t_fmyearinitbalrec r
JOIN t_fmaccount a
ON r.account = a.acctid
WHERE r.hsagency = &hsagency
AND r.acctsystype = &acctsystype
AND a.acctcode = &acctcode
UNION ALL
SELECT p1.acctyear,p1.term,'本月合计'
, SUM(DECODE(p2.dc,1,amt)) deb
, SUM(DECODE(p2.dc,-1,amt)) cre
, a.dc
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_fmaccount a
ON a.acctid = p2.account
WHERE p2.hsagency = &hsagency
AND p2.acctsystype = &acctsystype
AND regexp_like(a.acctcode,'^('||&acctcode||')')
GROUP BY p1.acctyear,p1.term,a.dc
)
SELECT acctyear,term,remark,deb,cre,decode(dc,1,'借','贷') dc
, SUM(DECODE(dc,1,NVL(deb,0)-NVL(cre,0),NVL(cre,0)-NVL(deb,0)))
OVER(ORDER BY term) balance
FROM i
ORDER BY 2;
假设查询某单位2016年“2305-其他应付款“科目总账,输入相关变量后,结果如下:
“5001-经费支出”科目:
2.明细账查询
明细账查询与总账查询类似,当查询某个科目期初数时,应该将其子级科目明细余额合并(如果余额方向与科目性质不同,则应调整),查询凭证明细表时,其子级科目应全部显示在明细账中,如果只查询末级,则仅显示末级科目明细记录。
WITH i AS
(
SELECT NULL acctdate,NULL vchno,0 acctseq,0 acctseqsub,'年初数' remark,NULL deb,NULL cre,a.dc,SUM(DECODE(d.dc,a.dc,startbal,-startbal)) balance,0 term
FROM t_fmyearinitbalrecdetail d
JOIN t_fmaccount a
ON d.account = a.acctid
WHERE d.hsagency = &hsagency
AND d.acctsystype = &acctsystype
AND regexp_like(a.acctcode,'^('||&acctcode||')')
GROUP BY a.dc
UNION ALL
SELECT p1.acctdate,p1.vchno,p2.acctseq,p2.acctseqsub,p2.digest,DECODE(p2.dc,1,amt),DECODE(p2.dc,-1,amt) cre,a.dc
, decode(a.dc,1,DECODE(p2.dc,1,amt,0)-DECODE(p2.dc,-1,amt,0),DECODE(p2.dc,-1,amt,0)-DECODE(p2.dc,1,amt,0))
, p2.term
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_fmaccount a
ON a.acctid = p2.account
WHERE p2.hsagency = &hsagency
AND p2.acctsystype = &acctsystype
AND regexp_like(a.acctcode,'^('||&acctcode||')')
)
SELECT to_date(acctdate,'yyyymmdd') acctdate
, to_number(vchno) vchno
, remark
, deb
, cre
, decode(dc,1,'借','贷') dc
, SUM(balance) OVER(ORDER BY term,to_number(vchno) NULLS FIRST,acctseq,acctseqsub) balance
FROM i
ORDER BY term,to_number(vchno),acctseq,acctseqsub;
查询某单位“500101-经费支出/财政拨款支出“明细账,结果如下:
3.辅助账查询
辅助账一般对指定科目按某种分类进行的查询,如往来辅助明细账查询,需指定往来科目,如“1215-其他应收款”、”2305-其他应付款“等,同时还要指定往来单位。本例以其他应付款为例,说明SQL语句的编写方法。
WITH i AS
(
SELECT NULL acctdate,NULL vchno,'年初数' remark
, DECODE(a.dc,d.dc,DECODE(d.dc,1,startbal)) deb
, DECODE(a.dc,d.dc,DECODE(d.dc,-1,startbal)) cre
, a.dc
, 0 term
, 0 acctseq
, 0 acctseqsub
FROM t_fmyearinitbalrecdetail d
JOIN t_fmaccount a
ON d.account = a.acctid
JOIN t_calagency c
ON c.itemid = d.calagency
WHERE d.hsagency = &hsagency
AND d.acctsystype = &acctsystype
AND a.acctcode = '&acctcode' --科目编码
AND c.code = '&ccode' --往来单位编码
UNION ALL
SELECT p1.acctdate,to_number(vchno) vchno,digest remark
, DECODE(p2.dc,1,amt) deb
, DECODE(p2.dc,-1,amt) cre
, a.dc
, p2.term
, p2.acctseq
, p2.acctseqsub
FROM t_glvoucherfm p1
JOIN t_glrecordfm p2
ON p1.vchid = p2.vchid
JOIN t_fmaccount a
ON a.acctid = p2.account
JOIN t_calagency c
ON c.itemid = p2.calagency
WHERE p2.hsagency = &hsagency
AND p2.acctsystype = &acctsystype
AND a.acctcode = '&acctcode'
AND c.code = '&ccode'
)
SELECT to_date(acctdate,'yyyymmdd') acctdate,vchno,remark,deb,cre,DECODE(dc,1,'借','贷') dc
, sum(DECODE(dc,1,NVL(deb,0)-NVL(cre,0),NVL(cre,0)-NVL(deb,0)))
OVER(ORDER BY term NULLS FIRST,vchno NULLS FIRST,acctseq,acctseqsub) balance
FROM i
ORDER BY term NULLS FIRST,vchno NULLS FIRST,acctseq,acctseqsub;
执行上述代码,输入以下参数:
Acctcode-往来科目编码;
Ccode-往来单位编码;
Hsagency-核算单位内码;
Acctsystype-核算类型。
执行结果如下:
其他辅助账实现的方法,其原理基本相同。
账簿查询中,余额方向应以科目属性为基准,正值表示与科目原有方向相同,负值表示反方向余额。上述账簿查询时,对于期初数,均将余额表中的科目方向与科目表中的科目方向进行了匹配,当余额表中的余额方向与科目表中的科目方向一致时,取余额原值,否则取相反数,以这个标准确定科目的方向,可以避免余额方向的混乱。
余额的计算,一般采用窗口函数实现,采用唯一排序机制,获取期初至当前记录的累加值(根据科目性质计算借方减贷方或者贷方减借方的净值累加)。
此外,本文的重点是利用SQL语言查询报表、账簿,并未考虑到代码性能问题,对于有些查询,单纯使用SQL语句,可能并不是最佳实现方式。

评论区(暂无评论)

我要评论

昵称
邮箱
网址
0/200
没有评论
更多文档