ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: office2008

[分享] 透视表汇总多工作簿数据!(令人惊叹的功能!)--第二部

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2009-4-25 14:08 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
对于有编程的人员来说一点都不难!!

TA的精华主题

TA的得分主题

 楼主| 发表于 2009-4-27 21:01 | 显示全部楼层

回复 6楼 yanjie 的帖子

不好意思,yanjie 版主 最近比较忙,所以耽搁了几天,对不住了。


Option Explicit

Sub 多工作表透视汇总()
    Dim pc As PivotCache
    Dim pt As PivotTable
    Dim str As String
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
    Dim sql As String
    Dim oFileName As String
    Dim arr() As Variant
    Dim brr() As Variant
    Dim sqlstr As String
    Dim str2 As String
    Dim dic As Object
    Dim Conn As New ADODB.Connection
    oFileName = Dir(ThisWorkbook.Path & "\*.xls")
    Application.ScreenUpdating = False
    Set dic = CreateObject("scripting.dictionary")                                        '创建字典
                                    '删除先前的所有数据透视表,目的在编辑代码时易于调试!
    For Each pt In Sheet1.PivotTables
        pt.TableRange2.Clear    '在没有页字段时可采用TableRange1.Clear方法来清除透视表 _
                                。pt.TableRange2表示全选透视表单元格!
    Next pt
                                      '设置透视表的缓存,采用PivotCaches.Add方法,确定数据源的类型为引用外部数据源!
    Set pc = ActiveWorkbook.PivotCaches.Add(SourceType:=xlExternal)

    With pc
                                                       '使用connection确定外部数据源的连接方式为ODBC, _
                                                        文件类型为excel文件,确定数据源的位置和默认文件夹的位置!
        .Connection = Array("ODBC;DSN=excel files;DBQ=" & ThisWorkbook.FullName & ";DefaultDir=" & ThisWorkbook.Path)

        .CommandType = xlCmdSql                            '返回命令类型!本例为返回excel的SQL命令。

        sql = "SELECT @ FROM `" & ThisWorkbook.Path & "\"
        Do While oFileName <> ""
            If oFileName <> ThisWorkbook.Name Then
                Conn.Open "Provider=Microsoft.Jet.OLEDB.4.0; " _
                        & " extended properties=excel 8.0;" _
                        & " Data Source=" & ThisWorkbook.Path & "\" & oFileName
                Dim Cat As New ADOX.Catalog                   '引用ADOX 操作库,表,字段 等对象
                Set Cat.ActiveConnection = Conn
                Dim cTab As ADOX.Table                        '定义表
                Dim fld As ADOX.Column                        '定义字段
                For Each cTab In Cat.Tables                   '循环库中每个表
                    str = ""
                    For Each fld In cTab.Columns              '循环表中每个字段
                        If fld <> "F1" Then                   '如果为空表,则字段名为"F1",实用表不会以"F1"为字段
                              '去掉部门名称,科目代码两个固定字段外判断字段是否存在,不存在则执行加入字典
                            If Not dic.exists(fld.Name) And fld.Name <> "部门名称" And fld.Name <> "科目代码" Then
                                dic(fld.Name) = ""
                                sqlstr = sqlstr & "  " & fld.Name  '用 sqlstr 记住即将在 SQL语句中用到的SELECT中的字段,且不重复用的"  "连接成字符串
                            End If
                            str = str & "  " & fld.Name  '    记录不同表中的字段,用"  "连接成字符串,这里包括 部门名称,科目代码,和 sqlstr 不同的
                           
                                                              
                            '本来应该在 循环库中每个表 时加入字典的,但因为在 循环库中每个表时不能判断表是否为空, _
                            所以只能在 表中循环每个字段时判断,如果为"F1"则过滤,这样就可把空表忽略过去
                           
                            If Not dic.exists(oFileName & cTab.Name & "表") Then
                                i = i + 1
                                dic(oFileName & cTab.Name & "表") = i    '加入字典,并计算数量(实际就是每个非空表的并表明是出自于哪个工作簿)
                                ReDim Preserve arr(1 To i)               '定义一个数组,与上面符合表的数量相等
                                arr(i) = sql & Left(oFileName, Len(oFileName) - 4) & "`.`" & cTab.Name & "`"  '逐一加入arr数组sql语句
                                If Not dic.exists(oFileName & "工作簿") Then   '这里加"工作簿"和"表"一样的没有多大意义,仅仅是区分, _
                                                                                本来应用两个字典以上,现在用一个怕混淆,所以加些词以区分而已
                                    j = j + 1
                                    dic(oFileName & "工作簿") = ""
                                    If j > 1 Then arr(i) = "] " & arr(i)     '这里用"] "实际就是把每个不同工作簿用"] "隔开,可按 F8 查看, _
                                                                             为的是在以后SQL语句中 用" / UNION ALL " 替换" UNION ALL ] "
                                End If
                            End If
                        End If
                    Next
                    ReDim Preserve brr(1 To i)                  '在上面相应的产生arr(i)的同时也产生brr(i)
                    If str <> "" Then brr(i) = str             ' 如果没有 If str <> "" Then , 那么brr(i)将不会忽略空表,而arr(i)是 _
                                                               忽略空表的,最后 每个 brr(i) 不会对应 每个arr(i),所以这里 请用 F8 逐条运行'
                                                               '由 If str <> "" Then 保证 每个 brr(i) 也是有效的并可对应 arr(i), _
                                                                另外每个 brr(i) 就是 每个表的 所有字段 ,查看上面的 str 是如何得来的
                Next
                Conn.Close
            End If
            oFileName = Dir()
        Loop
        For k = 1 To i                           ' i 等于 每个工作簿每个有数值的工作表的总和,全面我们已经做了
            str2 = ""
            For j = 0 To UBound(Split(sqlstr, "  "))  ' 用 Split 函数 把 在字符串中用"  "联合的每个字段再用 "  " 分离出来
                If InStr(brr(k), Split(sqlstr, "  ")(j)) Then   '查找每个brr(k)数组(即每个表)中是否含有某些字段
                    If str2 <> "" Then str2 = str2 & ","         ' 如果找到,并且不为第一个则 用"," 号连接,大家想一下select语 _
                                                                   句中的每个字段是否用"," 号隔开
                    str2 = str2 & Split(sqlstr, "  ")(j)           '大家可以测试 用这种方法测试普通字符串连接操作,","号不会在两边
                Else
                    If str2 <> "" Then str2 = str2 & ","
                    str2 = str2 & " 0 as " & Split(sqlstr, "  ")(j)   '如果没找到,按照SQL语句以及数据透视表如果数据为空则默认为计数 _
                                                                      汇总,如果为0则会默认为数量汇总,所以为 " 0 as 字段1 " 的形式
                End If
                                                          '每个 brr(k) 就是最上面 每个 brr(i) ,就是 k 就是最上面的 i
            Next
            arr(k) = Replace(arr(k), "@", " 部门名称,科目代码," & str2)   '每个arr(k) 就是最上面的 每个 arr(i),把 每个arr(k)中的 sql字符( SELECT @ FROM )中 _
                                                                           的 [@]  替换成 [部门名称,科目代码," & str2],str2我们知道是什么了吧,前面已求, _
                                                                           这样整个SQL语句就比较完整了
        Next
        str = Replace(Join(arr, "  / UNION ALL "), " UNION ALL ] ", " / UNION ALL ")  '用 JOIN 函数 把arr数组中各元素 用"  / UNION ALL " 连接, _
                                                                                   以前在每个工作簿间都有 "] "隔开,就形成 _
                                                                                   << select ......from ... / UNION ALL  select ......from .../ UNION ALL ] select ......from ...>>
                                                                                    '从上面的sql语句可以看出一个工作簿的每个工作表只用 " / UNION ALL " 连接 ,而不同工作簿的(即上一个工作 _
                                                                                    簿的最后一个工作表 和 下一个工作簿的 第一工作表 之间 是用 " / UNION ALL ] " 连接 ,是不一样的 . _
                                                                                    这样的话 ,再用 " / UNION ALL " 替换 " UNION ALL ] " ,这样一个完整的 SQL语句就完成了,形成 _
                                                                                    << select ......from ... / UNION ALL  select ......from ...// UNION ALL  select ......from ...>>
        .CommandText = Split(str, "/")                                             '如果在用Split函数 再加上 "/"字符分离拨开,那么表与表之间工作簿与工作簿之间完全符合 数据透视表的要求了,哈哈!

    End With
   
    Set pt = pc.CreatePivotTable(tabledestination:=Sheet1.Cells(4, 1), tablename:="pt1")
   
    pt.ManualUpdate = True     '停止透视表的计算,为快速向透视表添加字段做准备!

                               '使用AddFields方法为数据表添加行,列和页字段,本例中“Data” _
                                为虚拟的数据字段,表示数据字段放置在透视表的列区域!
    pt.AddFields RowFields:="部门名称", ColumnFields:="Data"
   
    k = 0
    For i = 1 To pt.PivotFields.Count
        If pt.PivotFields(i) <> "部门名称" And pt.PivotFields(i) <> "科目代码" Then
            k = k + 1
            With pt.PivotFields(i)
                .Orientation = xlDataField
                .Position = k
                .Name = " " & pt.PivotFields(i)
            End With
        End If
    Next

    pt.ManualUpdate = False        '透视表添加完字段后,重新计算数据透视表,以显示正确结果。
    pt.ManualUpdate = True
    Application.ScreenUpdating = True
   
    Set pt = Nothing               '释放变量占用的内存!
    Set pc = Nothing

End Sub


最好把代码复制到原来的附件下替换原来的,不替换也可多做个宏罢了,但愿对大家有帮助。

[ 本帖最后由 office2008 于 2009-4-27 21:07 编辑 ]

评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2009-4-27 22:44 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-5-6 22:13 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-6-23 13:15 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-6-23 15:34 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-9-2 23:50 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-11-16 23:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2009-11-17 21:18 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2010-2-9 13:09 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
一个字:难。
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

最新热点上一条 /1 下一条

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-4-20 03:23 , Processed in 0.044850 second(s), 7 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表