SQL代码之多组织数据汇总成树形表格展示

需求多组织(一个数据库实例里面,存在一个总公司数据库,多个分公司数据库)环境中,以总公司的会计科目为主(分公司可能不存在总公司存在的科目),以树形结构的方式展示各个科目下每个公司的该科目对应的余额数据。每类科目有一个余额汇总小计,最后再做一个全部余额合计,本例中使用一个总公司,一个分公司做的演示

效果如下所示

 准备工作:

1、在数据库中创建两个数据库,一个 MyWorkTest (表示总公司) 一个 MyWorkTestBackUp(表示分公司)

2、分别在两个数据库中执行表结构sql语句(没用注释的部分两个表都需要执行,注释的部分,只需要执行对应数据库的sql部分)

3、准备treetable插件

4、本例用的是MVC 需要将MVC的模板 _ViewStart 中的Layout设置为null

代码实现:

1、表结构SQL

--公司信息
Create Table MyWorkTest_CompanyInfo(
    id int IDENTITY(1,1) NOT NULL,
    fullname nvarchar(10) NOT NULL,
    isHeader bit not null,
    dbname nvarchar(100) not null
)
GO
delete from MyWorkTest_CompanyInfo
insert into MyWorkTest_CompanyInfo(fullname,isHeader,dbname)
select '总公司',1,'MyWorkTest' UNION ALL
select '成都分公司',0,'MyWorkTestBackUp'
GO

--科目信息
Create Table MyWorkTest_Atype(
    typeid nvarchar(50) not null,
    parid nvarchar(50) not null,
    leveal smallint not null,
    sonnum int not null,
    fullname nvarchar(66) not null,
    usercode nvarchar(50) not null,
    balance numeric(18,2) default(0)
)
GO

delete from MyWorkTest_Atype
/*
--MyWorkTest 数据库数据
--资产类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00000','root','0','5','全部科目','00',0 UNION ALL
select '00001','00000','1','3','资产类','10',0 UNION ALL  --17640
select '0000100001','00001','2','0','库存现金','1001',10000 UNION ALL
select '0000100002','00001','2','2','银行存款','1002',0 UNION ALL --7520
select '000010000200001','0000100002','3','0','建设银行','100201',1020 UNION ALL
select '000010000200002','0000100002','3','2','工商银行','100202',0 UNION ALL --6500
select '00001000020000200001','000010000200002','4','0','成都工商银行','10020201',4000 UNION ALL
select '00001000020000200002','000010000200002','4','0','绵阳工商银行','10020202',2500 UNION ALL
select '0000100003','00001','2','2','其他货币资金','1003',0 UNION ALL  --120
select '000010000300001','0000100003','3','0','外埠存款','100301',20 UNION ALL
select '000010000300002','0000100003','3','0','信用卡','100302',100 

--负债类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00002','00000','1','4','负债类','20',0 UNION ALL  --1073
select '0000200001','00002','2','0','短期借款','2001',10 UNION ALL
select '0000200002','00002','2','2','应付账款','2002',0 UNION ALL --33
select '000020000200001','0000200002','3','0','应付货款','200201',11 UNION ALL
select '000020000200002','0000200002','3','0','应付加工费','200202',22 UNION ALL
select '0000200003','00002','2','1','应交税费','2003',0 UNION ALL --30
select '000020000300001','0000200003','3','2','应交增值税','200301',0 UNION ALL --30
select '00002000030000100001','000020000300001','4','0','进项税额','20030101',10 UNION ALL
select '00002000030000100002','000020000300001','4','0','己交税金','20030102',20 UNION ALL
select '0000200004','00002','2','','应付职工薪酬','2004',1000

--共同类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00003','00000','1','1','共同类','30',0 UNION ALL  --30
select '0000300001','00003','2','0','货币兑换','3001',10 UNION ALL
select '0000300002','00003','2','0','总公司有子公司没有的项目','3002',20 


--所有者权益
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00004','00000','1','2','所有者权益','40',0 UNION ALL  --350
select '0000400001','00004','2','0','实收资本','4001',150 UNION ALL
select '0000400002','00004','2','0','盈余公积','4002',200 


--成本类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00005','00000','1','1','成本类','50',0  UNION ALL  --30
select '0000500001','00005','2','2','生产成本','5001',0 UNION ALL  --30
select '000050000100001','0000500001','3','0','基本生产成本','500101',10 UNION ALL
select '000050000100002','0000500001','3','0','辅助生产成本','500102',20
*/

/*
--MyWorkTestBackUp 数据库数据
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00000','root','0','5','全部科目','00',0 UNION ALL
select '00001','00000','1','3','资产类','10',176.2 UNION ALL
select '0000100001','00001','2','0','库存现金','1001',100 UNION ALL
select '0000100002','00001','2','2','银行存款','1002',75 UNION ALL
select '000010000200001','0000100002','3','0','建设银行','100201',10 UNION ALL
select '000010000200002','0000100002','3','2','工商银行','100202',65 UNION ALL
select '00001000020000200001','000010000200002','4','0','成都工商银行','10020201',40 UNION ALL
select '00001000020000200002','000010000200002','4','0','绵阳工商银行','10020202',25 UNION ALL
select '0000100003','00001','2','2','其他货币资金','1003',1.20 UNION ALL
select '000010000300001','0000100003','3','0','外埠存款','100301',0.20 UNION ALL
select '000010000300002','0000100003','3','0','信用卡','100302',1 
--负债类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00002','00000','1','4','负债类','20',1.73 UNION ALL
select '0000200001','00002','2','0','短期借款','2001',0.1 UNION ALL
select '0000200002','00002','2','2','应付账款','2002',0.33 UNION ALL
select '000020000200001','0000200002','3','0','应付货款','200201',0.11 UNION ALL
select '000020000200002','0000200002','3','0','应付加工费','200202',0.22 UNION ALL
select '0000200003','00002','2','1','应交税费','2003',0.3 UNION ALL
select '000020000300001','0000200003','3','2','应交增值税','200301',0.3 UNION ALL
select '00002000030000100001','000020000300001','4','0','进项税额','20030101',0.1 UNION ALL
select '00002000030000100002','000020000300001','4','0','己交税金','20030102',0.2 UNION ALL
select '0000200004','00002','2','','应付职工薪酬','2004',1
--共同类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00003','00000','1','1','共同类','30',0.1 UNION ALL
select '0000300001','00003','2','0','货币兑换','3001',0.1 
--所有者权益
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00004','00000','1','2','所有者权益','40',0.35 UNION ALL
select '0000400001','00004','2','0','实收资本','4001',0.15 UNION ALL
select '0000400002','00004','2','0','盈余公积','4002',0.2 
--成本类
insert into MyWorkTest_Atype(typeid,parid,leveal,sonnum,fullname,usercode,balance)
select '00005','00000','1','1','成本类','50',0.3 UNION ALL
select '0000500001','00005','2','2','生产成本','5001',0.3 UNION ALL
select '000050000100001','0000500001','3','0','基本生产成本','500101',0.1 UNION ALL
select '000050000100002','0000500001','3','0','辅助生产成本','500102',0.2
*/
View Code

2、存储过程

IF EXISTS ( SELECT  *
            FROM    dbo.sysobjects
            WHERE   id = OBJECT_ID(N'[dbo].[P_Inf_GetAtypeAssistantBalance]')
                    AND OBJECTPROPERTY(id, N'IsProcedure') = 1 )
  DROP PROCEDURE [dbo].[P_Inf_GetAtypeAssistantBalance]
GO

/*
    需求:多组织环境,以总公司的科目为参考(存在总公司有的科目在子公司没有的情况),统计每个公司的每个科目的余额情况
    以树形的方式显示科目,在末级显示各个公司该科目的余额情况,
    每个末级科目显示各个公司该科目余额的汇总数据,
    不同科目类一个科目余额小计,最后汇总一个全部余额合计
*/
CREATE PROCEDURE P_Inf_GetAtypeAssistantBalance
AS
BEGIN
    SET NOCOUNT ON
    --变量申明
    DECLARE @ComName nvarchar(200),@DbName nvarchar(200), @IsHead bit, @Sql nvarchar(max)
    DECLARE @MaxLevel INT,@CIndex int
    DECLARE @CIndexStr nvarchar(200)

    -- 获取末级科目
    SELECT typeid,leveal
    INTO #AtypeCw 
    FROM MyWorkTest_Atype 
    WHERE sonnum = 0 

    --末级数据表
    CREATE TABLE #FinalData(
        CompanyID nvarchar(50),
        TypeID nvarchar(200),
        ParId nvarchar(200),
        BalanceTotal numeric(18,4),
        leveal int DEFAULT 0,
        CIndex nvarchar(200)
    )
    -- 获取末级数据封装
    set @CIndex =1
    Declare my_cursor Cursor For Select dbname, fullname,isHeader  From MyWorkTest_CompanyInfo Where dbname <> ''  Order By isHeader Desc
    Open my_cursor
    Fetch Next From my_cursor Into @DbName, @ComName,@IsHead
    While @@Fetch_Status = 0
    BEGIN
        SET @CIndexStr = right(cast(right('0000'+rtrim(@CIndex),4) as varchar(4)),4)
        SET @SQL ='select '''+@ComName+''', a.typeid,a.parid,a.balance,a.leveal,'''+@CIndexStr+''' AS cindex  from ['+@DbName+']..MyWorkTest_Atype  a
        INNER join #AtypeCw b on a.typeid = b.typeid'
        INSERT INTO #FinalData(CompanyID,TypeID,ParId,BalanceTotal,leveal,CIndex)
        exec (@Sql) 

        INSERT INTO #FinalData(CompanyID,TypeID,ParId,BalanceTotal,leveal,CIndex)    
        SELECT @ComName AS CompanyID,A.typeid,left(A.typeid,LEN(A.typeid)- 5) AS ParId,0 as BalanceTotal,0 AS leveal,@CIndexStr AS CIndex
        FROM #AtypeCw A LEFT JOIN #FinalData B ON A.typeid = B.TypeID AND b.CompanyID = @ComName
        WHERE B.TypeID IS NULL 
        GROUP BY A.typeid
        SET @CIndex = @CIndex+1
    Fetch Next From my_cursor Into @DbName, @ComName,@IsHead
    End
    Close my_cursor
    Deallocate my_cursor
 
    --在末级增加公司数据
    select LEFT(typeid,5) as ATypeIndex, tag, usercode, fullname,typeid,parId,balancetotal ,leveal,
    ROW_NUMBER() OVER(PARTITION By LEFT(typeid,5) Order By typeid,parId,tag ) as AtypeInnerIndex
    into #LastLevealData
    from (
        select 10 tag,a.usercode, a.fullname, f.TypeID,f.ParId, sum(BalanceTotal)AS BalanceTotal,a.leveal from #FinalData  f
        left join MyWorkTest_Atype  a on f.TypeID = a.typeid
        GROUP BY f.TypeID,a.fullname,f.ParId,a.leveal,a.usercode
        UNION ALL
        select 20 tag,'' AS usercode,CompanyID,TypeID+CIndex,TypeID, SUM(BalanceTotal) AS BalanceTotal,fc.leveal from #FinalData fc
        group by CompanyID,TypeID,ParId,fc.leveal,fc.CIndex
    ) t order by TypeID,tag
   
 
   --增加父级数据            
    SELECT @MaxLevel = max(leveal) FROM #LastLevealData            
    WHILE @MaxLevel > 1
      BEGIN
        INSERT INTO #LastLevealData(ATypeIndex,tag, usercode,fullname,typeid,parId,balancetotal,leveal,AtypeInnerIndex)
        SELECT LEFT(b.typeId,5) AS ATypeIndex ,10,b.usercode,b.FullName,b.typeId,b.parid,BalanceTotal,b.leveal,'' AS AtypeInnerIndex
        FROM 
        (
          SELECT DISTINCT LEFT(typeid, LEN(typeid)-5) as typeid,
            SUM(BalanceTotal) AS BalanceTotal
          FROM #LastLevealData  
          WHERE tag = 10 AND leveal = @MaxLevel
          GROUP BY LEFT(typeid, LEN(typeid)-5)            
        ) a
        INNER JOIN MyWorkTest_Atype b ON a.typeid = b.typeid 
        SET @MaxLevel = @MaxLevel - 1
     END 

    update #LastLevealData set parid = '00000' where leveal = 2 and tag = 10  
    update #LastLevealData set leveal = 9 where leveal = 1 and tag = 10
        
    -- 获取数据源
    select ATypeIndex,tag,usercode, fullname,typeid,parId,balancetotal,leveal,
    ROW_NUMBER() OVER(PARTITION By LEFT(typeid,5) Order By ATypeIndex ,typeid,tag) as AtypeInnerIndex
    into #DataSource
    from #LastLevealData 
    
    --小类合计放在每一类的最后面处理开始
    select ATypeIndex,tag,usercode, fullname,typeid,parId,balancetotal,leveal,
    ROW_NUMBER() OVER(Order By ATypeIndex,leveal,AtypeInnerIndex) as AtypeInnerIndex
    into #DataSourceRst
    from #DataSource
    
    delete from #DataSource 
    insert into #DataSource
    select * from #DataSourceRst
    --小类合计放在每一类的最后面处理结束
    
    --所有合计
    insert into #DataSource(ATypeIndex,tag,usercode, fullname,typeid,parId,balancetotal,leveal,AtypeInnerIndex) 
    select '99999' AS ATypeIndex,40 AS tag, '合计' AS usercode, '合计' AS fullname,'99999' AS typeid, '00000' AS  parId,sum(balancetotal), 0 as leveal,
    0 AS  AtypeInnerIndex 
    from #DataSource where leveal = 9 
    update #DataSource set usercode = fullname+'小计' where leveal = 9
    
    select * from #DataSource order by ATypeIndex
    
  --删除临时表
    DROP TABLE #AtypeCw
    DROP TABLE #FinalData
    DROP TABLE #LastLevealData
    DROP TABLE #DataSource
    DROP TABLE #DataSourceRst
    
END
GO
View Code

3、页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tree-table</title>
    <link rel="stylesheet" href="/Content/TreeTable/assets/layui/css/layui.css">
    <link rel="stylesheet" href="/Content/TreeTable/assets/common.css" />
</head>
<body>
    <link rel="stylesheet" href="/Content/TreeTable/assets/layui/css/layui.css">
    <link rel="stylesheet" href="/Content/TreeTable/assets/common.css" />
    <p></p>
    <div class="layui-container">
        <div class="layui-btn-group">
            <button class="layui-btn" id="btn-expand">全部展开</button>
            <button class="layui-btn" id="btn-fold">全部折叠</button>
        </div>
        <table id="auth-table" class="layui-table" lay-filter="auth-table"></table>
    </div>
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="/Content/TreeTable/assets/layui/layui.js"></script>
    <script>
    $.ajax({
        url: '/MyTest/GetDataSource',
        type: 'post',
        dataType: 'json',
        success: function (res) {
            layui.config({
                base: '/Content/TreeTable/module/'
            }).extend({
                treetable: 'treetable-lay/treetable'
            }).use(['table', 'treetable'], function () {
                var $ = layui.jquery;
                var table = layui.table;
                var treetable = layui.treetable;
                // 渲染表格
                layer.load(2);
                treetable.render({
                    data: res.data,
                    treeColIndex: 1,
                    treeSpid: '00000',
                    treeIdName: 'TypeId',
                    treePidName: 'ParId',
                    elem: '#auth-table',
                    page: false,
                    cols: [[
                        { type: 'numbers' },
                        { field: 'UserCode', minWidth: 200, title: '科目编码' },
                        { field: 'FullName', minWidth: 200, title: '科目名称' },
                        { field: 'BalanceTotal', title: '余额' },
                        { field: 'AtypeInnerIndex',  80, align: 'center', title: '排序号' },
                        { field: 'TypeId',  80, align: 'center', title: 'ID' },
                        { field: 'ParId',  80, align: 'center', title: '父级ID' },
                    ]],
                    done: function () {
                        layer.closeAll('loading');
                    }
                });

                $('#btn-expand').click(function () {
                    treetable.expandAll('#auth-table');
                });

                $('#btn-fold').click(function () {
                    treetable.foldAll('#auth-table');
                });
            });
        }
    })
    </script>
</body>
</html>
View Code

4、控制器代码

using MyWebSiteDemo.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace MyWebSiteDemo.Controllers
{
    public class MyTestController : Controller
    {
        public ActionResult Index()
        {
           return View();
        }

        public string GetDataSource() {
            ItemDbContext itemContext = new ItemDbContext();
            List<Item> list = itemContext.Database.SqlQuery<Item>("exec P_Inf_GetAtypeAssistantBalance").ToList();
            JsonData jsonData = new JsonData();
            jsonData.data = list;
            jsonData.code = "0";
            jsonData.msg = "OK";
            jsonData.count = "67";
            StringBuilder sb = new StringBuilder();
            JavaScriptSerializer json = new JavaScriptSerializer();
            json.Serialize(jsonData, sb);
            return sb.ToString();
        }
    }

    public class JsonData {
        public List<Item> data { get; set; }
        public string code { get; set; }
        public string msg { get; set; }
        public string count { get; set; }
    }

}
View Code

5、实体代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyWebSiteDemo.Models
{
    public class Item
    {
        /// <summary>
        /// 大类编号
        /// </summary>
        public string AtypeIndex { get; set; }
        //标识
        public int Tag { get; set; }
        /// <summary>
        /// 编码
        /// </summary>
        public string UserCode { get; set; }
        /// <summary>
        /// 全名
        /// </summary>
        public string FullName { get; set; }
        /// <summary>
        /// 编号
        /// </summary>
        public string TypeId { get; set; }
        /// <summary>
        /// 父级编号
        /// </summary>
        public string ParId { get; set; }
        /// <summary>
        /// 余额
        /// </summary>
        public decimal BalanceTotal { get; set; }
        /// <summary>
        /// 级别
        /// </summary>
        public int Leveal { get; set; }
        /// <summary>
        /// 排序
        /// </summary>
        public long AtypeInnerIndex { get; set; }

    }
}
View Code

6、数据上下文

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;

namespace MyWebSiteDemo.Models
{
    public class ItemDbContext:DbContext
    {
        public ItemDbContext() : 
            base("数据库Key") {}
    }
}
View Code

7、资源下载

treetable插件  提取码:  6pjw

写写博客,方便自己也方便有需要的人~~

原文地址:https://www.cnblogs.com/Yisijun/p/13208388.html