金桔
金币
威望
贡献
回帖0
精华
在线时间 小时
|
两年后的更新,时隔两年,我联合我的VBA老师推出了VBA课程,哈哈!欢迎大家关注!
POINT小数点数据:小数点Excel-VBA课程正式上线——————————————————
更新:建议下载文件,链接:http://pan.baidu.com/s/1dERLTPR 密码:0h3q
————————————————————
看到这个话题,我决定送给职场新人一个福利~~
我刚毕业那会,Excel数据透视表都不会,后来进入DBA部门用得更少了。
工作过程中一个做excel的妹子找我抱怨,做一个表要花一两个小时,甚至三四个小时,请教我能否想想办法,我用R写个程序可以。考虑到妹子家里公司都要做事,不太想安装R。我想到了VBA,在大学时学过一点VB,正好练练手。
花一天整理妹子的需求,用一周学习,然后就写出了
3个自定义函数
2个自动更新数据
后来写着写着就顺手,经常帮妹子写报表自动化程序。
导致妹子对我产生依赖性,她每天就想按几个键然后工作都完成了。
我建议她可以看看我的代码,我都写好注释了,你可以按照注释去改参数,就不用天天问我了,但妹子看不懂,我教了几遍遂放弃。
对了上面说的福利,当然是贴代码,这份福利给文职类的处理excel的新人,程序员不要捣乱。
情景1:一个工作簿,你按照地区或者部门等你自己的需要拆成不同的工作簿(需求是不是很简单,nonono,单独做一个当然简单,但是我贴出来肯定是这个代码是通用的。比如你想拆第几行开始娜一列都可以,会有选项让你一步一步选择)
情景2:比如拆完,有30张表,你想发给30个不同的人看?你是不是要同时写30封邮呢
关于情景1,的工作时间:如果一张总表有三十城市,要按照城市拆成三十个工作簿,不断复制+改工作簿名,个人觉得至少得二十分钟吧,还有容易出错的概率。
关于情景2的工作时间:这个就更麻烦了。三十个城市名,要下发给三十个不同分公司的人,而且不同分公司的人,不是只有一个人。你第一次发,如果邮箱有群组还好,但是你始终得写三十封邮件,还要注意选择工作簿不能出错,邮件主题内容不能出错。预估这个工作时间至少得一个小时,平均一封邮件2分钟。
情景1+情景2时间=一小时二十分钟(据我观察,历史五个人做这件事出错率100%,不是城市名写错了,就发错工作簿了)
不知道大家看懂了没= =
好了开始写步骤贴代码,我会尽量用最通俗的语言讲清逻辑关系
步骤1:建立两个sheet,点击sheet ,右击查看代码(先检查excel是否启用宏,要启用宏哦)



插入窗体和模块,按模块,把以下这串代码复制进去

再按窗体,设置成这样

然后看到代码,拉到最后,能看到一个是邮件签名,一个是邮箱配置,你自己填上即可,邮件内容可以自己改

截止到这步,代表所有准备工作都完成了,咱们开始测试吧^_^
29个城市,我拆成29个工作簿,点击宏





按完确定大概10秒后,跟你excel同个文件夹内,会生成拆分的文件夹,你点进去

已经生成了,如果没有想要发邮件的同学,在这里就可以结束啦。

打开工作簿看看,拆分如何

想把三十个工作簿发送邮件的同学,注意看下面,转到通讯录的那个sheet,



这里点击一次文件夹,直接按确定,不用双击进入文件夹


按完确定后,这时候按照工作簿数来算时间,基本上每秒一个城市,也就是一个工作簿。等到这个提示出来之后,你就可以直接看到结果了。

然后你在看,是否有收到邮件
打开你的邮箱

收到啦

整套点击+运行大约三分钟
代码:
Sub 通用拆分()
'On Error Resume Next
Application.ScreenUpdating = False '关闭屏幕更新
Application.DisplayAlerts = False '关闭提示事件,防止删除表格时提示
Dim Pro, Wb1, Wb2, St1, Sht, Rng, Itm, StRow, Pth
Set Wb1 = ThisWorkbook
Set St1 = ActiveSheet
a = MsgBox("当前文件为:" & Wb1.Name & Chr(10) & "当前表格为:" & St1.Name & Chr(10) & Chr(10) & "点击 确定 继续运行," & Chr(10) & "点击 取消 退出程序。", 1)
If a = 2 Then '如果点了取消,就退出程序
Exit Sub
End If
b = InputBox("请输入拆分列表头所在的单元格位置。" & Chr(10) & "例如:要拆分的列位于C列,表头是第3行,就输入“C3”")
If b = "" Then
MsgBox ("未输入拆分表头,程序退出")
Exit Sub
End If
rowx = St1.Range(b).Row
colx = St1.Range(b).Column
Set Pro = CreateObject("Scripting.Dictionary") '建立一个以省份为关键字的字典
StRow = St1.Cells.Find("*", SearchOrder:=xlByRows, LookIn:=xlValues, SearchDirection:=xlPrevious).EntireRow.Row '确定当前文件行数
St1.Range(rowx & ":" & rowx).AutoFilter Field:=colx, Criteria1:="*" '取消筛选
For Each Rng In St1.Range(St1.Cells(rowx + 1, colx), St1.Cells(StRow, colx)) '
If Not Pro.exists(Rng.Value) And Not IsError(Rng.Value) Then Pro.Add Rng.Value, Rng.Value '判断当前表格的值是否在字典内,如果不在,就添加到字典内
Next
namex = InputBox("请输入文件名的自定义字段," & Chr(10) & "例如输入“收款明细”,就会生成“上海-收款明细.xlsx”文件", "", St1.Name)
For Each Itm In Pro.Items '针对字典内的每个值进行一次操作(每个省份循环一次)
St1.Copy
Set Wb2 = ActiveWorkbook
Set Sht = ActiveSheet
Sht.Range(rowx & &#34;:&#34; & rowx).AutoFilter Field:=colx, Criteria1:=&#34;<>&#34; & Itm, Operator:=xlAnd &#39;筛选列,筛选值为不符合当前省份
Sht.Range(Sht.Cells(rowx + 1, colx), Sht.Cells(StRow, colx)).SpecialCells(xlCellTypeVisible).Delete Shift:=xlUp &#39;删除被筛选出来的行(删掉不为当前省份的行)
Sht.Range(rowx & &#34;:&#34; & rowx).AutoFilter &#39;取消筛选
ActiveWindow.SmallScroll Down:=-StRow
ActiveWindow.SmallScroll ToRight:=-100
If Dir(Wb1.Path & &#34;\拆分\&#34;, vbDirectory) = &#34;&#34; Then MkDir ThisWorkbook.Path & &#34;\拆分\&#34; &#39;看看当前文件夹内是否存在&#34;拆分&#34;文件夹,如果没有就创建一个
Pth = Wb1.Path & &#34;\拆分\&#34; & Itm & &#34;-&#34; & namex & &#34;.xls&#34;
Wb2.SaveAs Filename:=Pth, FileFormat:=xlExcel8, Password:=&#34;&#34;, WriteResPassword:=&#34;&#34;, ReadOnlyRecommended:=False, CreateBackup:=False
Wb2.Close &#39;关闭表格
Next
Set Pro = Nothing &#39;释放变量
Set Wb1 = Nothing
Set Wb2 = Nothing
Set St1 = Nothing
Set Sht = Nothing
Set Rng = Nothing
Set Itm = Nothing
Set StRow = Nothing
Set Pth = Nothing
Application.ScreenUpdating = True &#39;打开屏幕更新
Application.DisplayAlerts = True &#39;打开提示事件
End Sub
Sub 通用发送邮件()
&#39;On Error Resume Next
Dim cm As Variant
UserForm1.Show
UserName = UserForm1.ComboBox1
UserPass = UserForm1.TextBox1.Value
With Application.FileDialog(msoFileDialogFolderPicker)
.InitialFileName = ActiveWorkbook.Path & &#34;\&#34;
If .Show = -1 Then
Pth = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems.Item(1) & &#34;\&#34;
End If
End With
&#39;定义文件夹
Dim FS, F, FF, Fil, BName, EName
Set FS = CreateObject(&#34;Scripting.FileSystemObject&#34;)
Set F = FS.GetFolder(Pth)
Set FF = F.Files
If FF Is Nothing Or F Is Nothing Then
MsgBox (&#34;文件或文件夹错误,请查证在本文件目录内存在&#39;拆分&#39;文件夹,并且已经生成拆分文件&#34;)
Exit Sub
End If
&#39;保存文件信息
Dim FN(1 To 10000, 1 To 3)
i = 0
For Each Fil In FF
i = i + 1
FN(i, 1) = FS.GetBaseName(Fil)
FN(i, 2) = FS.GetExtensionName(Fil)
FN(i, 3) = Left(FN(i, 1), InStr(1, FN(i, 1), &#34;-&#34;) - 1)
Next
Set Sht = ThisWorkbook.Sheets(&#34;邮件联系人&#34;)
colnew = Sht.Cells(1, Columns.Count).End(xlToLeft).Column + 1 &#39;联系人空白列(用于记录发送结果)
Sht.Cells(1, colnew).Value = Pth & Chr(10) & Date & &#34; &#34; & Time & &#34; 发送结果&#34;
tex = InputBox(&#34;请输入邮件正文自定义段&#34;)
For m = 1 To i
Err.Clear
linkman = &#34;&#34;
emailx = &#34;&#34;
Set bbb = Sht.Range(&#34;a:a&#34;).Find(FN(m, 3))
If bbb Is Nothing Then
rownew = Sht.Range(&#34;a60000&#34;).End(xlUp).Row + 1
Sht.Cells(rownew, 1).Value = FN(m, 3)
Sht.Cells(rownew, colnew).Value = &#34;未找到发件人&#34;
mg = mg & FN(m, 3) & Left(&#34; &#34;, 10 - Len(FN(m, 3)) * 2) & &#34;未找到发件人&#34; & Chr(13)
GoTo line5
End If
For n = 1 To Sht.Range(&#34;a60000&#34;).End(xlUp).Row &#39;循环查找联系人姓名和邮件地址
If FN(m, 3) = Sht.Cells(n, 1).Value Then
linkman = linkman & Sht.Cells(n, 2).Value & &#34;、&#34;
emailx = emailx & Replace(Sht.Cells(n, 7).Value, &#34;;&#34;, &#34;&#34;) & &#34;,&#34;
End If
Next
If Len(emailx) < 2 Then &#39;如果邮件地址是空,那就不发送本城市
bbb.Offset(0, colnew - 1).Value = &#34;无邮件地址&#34;
mg = mg & FN(m, 3) & Left(&#34; &#34;, 10 - Len(FN(m, 3)) * 2) & &#34;无邮件地址&#34; & Chr(13)
GoTo line5
End If
linkman = Left(linkman, Len(linkman) - 1) &#39;删掉最后一个符号
emailx = Left(emailx, Len(emailx) - 1)
Set cm = CreateObject(&#34;CDO.Message&#34;) &#39;创建对象
cm.From = UserName &#39;设置发信人的邮箱
cm.To = emailx &#39;设置收信人的邮箱
cm.Subject = FN(m, 1) &#39;设定邮件的主题
cm.TextBody = &#34;亲爱的********:&#34; _
& Chr(10) & &#34; 附件为 &#34; & FN(m, 1) & &#34;,请查收。&#34; & Chr(10) & tex _
& Chr(10) & &#34;谢谢!&#34; _
& Chr(10) & &#34; _______________________________________________________&#34; _
& Chr(10) & &#34; **部门 &#34; _
& Chr(10) & &#34; 姓名 &#34; _
& Chr(10) & &#34; 手机:********* &#34; _
& Chr(10) & &#34; 电话:********* &#34; _
& Chr(10) & &#34; Email:********* &#34; _
& Chr(10) & &#34; 地址:****************** &#34; &#39;邮件正文
cm.AddAttachment Pth & FN(m, 1) & &#34;.&#34; & FN(m, 2) &#39;添加附件
stUl = &#34;http://schemas.microsoft.com/cdo/configuration/&#34;
With cm.Configuration.Fields
.Item(stUl & &#34;smtpserver&#34;) = &#34;http://mail.qq.com&#34; &#39;SMTP服务器地址
.Item(stUl & &#34;smtpserverport&#34;) = 25 &#39;SMTP服务器端口
.Item(stUl & &#34;sendusing&#34;) = 2 &#39;发送端口
.Item(stUl & &#34;smtpauthenticate&#34;) = 1
.Item(stUl & &#34;sendusername&#34;) = UserName &#39;发送方邮箱名称
.Item(stUl & &#34;sendpassword&#34;) = UserPass &#39;发送方邮箱密码&#34;
.Update
End With
cm.Send &#39;发送
&#39;生成反馈信息
If Err.Number = 0 Then
mg = mg & FN(m, 3) & Left(&#34; &#34;, 10 - Len(FN(m, 3)) * 2) & &#34;发送成功&#34; & Chr(13)
bbb.Offset(0, colnew - 1).Value = &#34;发送成功&#34;
Else
mg = mg & FN(m, 3) & Left(&#34; &#34;, 10 - Len(FN(m, 3)) * 2) & &#34;发送失败&#34; & Chr(13)
bbb.Offset(0, colnew - 1).Value = &#34;发送失败&#34;
End If
Set cm = Nothing &#39;发送成功后即时释放对象
line5:
Next
MsgBox (Left(mg, Len(mg) - 1)) &#39;确认结果
End Sub
——————————————————————————————————
谢谢大家的赞,那我就再贴一个给职场小白
前面拆分,肯定有合并,再贴一个合并工作簿的代码,也超级简单的哦。
开始:
新建一个空白工作簿
还是一样右击sheet——查看代码,这次不用建立模块,直接把代码贴进去即可


点击执行后,让你选择文件夹,你的先把要合并的所有工作簿放在一个文件夹内

数据是这样的


点击文件夹执行后

按确定后,数据就好了。

对了,工作簿名称不一样也不要紧哦
比如这样....

代码:
Sub 文件合并()
Application.ScreenUpdating = False
&#39;On Error Resume Next
Dim Pth As String
Set wst1 = ActiveSheet
row1 = 0
wst1.Cells.Delete Shift:=xlUp
&#39;打开文件夹
Dim shell, s
Set shell = CreateObject(&#34;Shell.Application&#34;)
Set fl = shell.BrowseForFolder(0, &#34;请选择文件夹&#34;, 0, Pth)
If fl Is Nothing Then Exit Sub
Pth = fl.self.Path & &#34;\&#34;
&#39;定义文件夹
Dim FS, F, FF, Fil, BName, EName
Set FS = CreateObject(&#34;Scripting.FileSystemObject&#34;)
Set F = FS.GetFolder(Pth)
Set FF = F.Files
For Each Fil In FF
BName = FS.GetBaseName(Fil)
EName = FS.GetExtensionName(Fil)
If EName = &#34;xls&#34; Or EName = &#34;xlsx&#34; Or EName = &#34;XLS&#34; Or EName = &#34;XLSX&#34; Then
Workbooks.Open (Fil)
Set wst2 = ActiveSheet
Set wb = ActiveWorkbook
strow = wst2.UsedRange.Rows.Count
If row1 = 0 Then
wst2.Rows(&#34;1:&#34; & strow).Copy wst1.Cells(row1 + 1, 1)
row1 = row1 + strow
Else
wst2.Rows(&#34;2:&#34; & strow).Copy wst1.Cells(row1 + 1, 1)
row1 = row1 + strow - 1
End If
Application.CutCopyMode = False
wb.Close (False)
End If
Next
MsgBox (&#34;完成&#34;)
End Sub
——————————————————————————————————————
拆分or合并or群发邮件,是三个独立的宏,都可以灵活运用。建议大家复制保存为TXT文档或者存到一个excel里面,作为工具使用,不用每次黏贴复制了。
最后
1、我是女生
2、我早就从那家公司离职了,平时工作忙和妹子没再联系,走之前给她写了一堆程序,覆盖她工作中50%的excel处理
3、只是同事之间的帮忙,而且我也喜欢研究。为什么要扯到感情,大家那么喜欢童话故事?
4、我不是专业写VBA的
花了两个小时一个一个截图+写注释,你能不能点个赞再走n(*≧▽≦*)n |
|