Quantcast
Channel: 知乎日报
Viewing all articles
Browse latest Browse all 20608

工作被效率更高的机器抢了是什么体验?

$
0
0

日报标题:职场新人的福利,学好了,要做一小时的表格几分钟就搞定

知乎用户,BI开发/数据挖掘/CPDA

看到这个话题,我决定送给职场新人一个福利~~

我刚毕业那会,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 & ":" & rowx).AutoFilter Field:=colx, Criteria1:="<>" & Itm, Operator:=xlAnd '筛选列,筛选值为不符合当前省份

Sht.Range(Sht.Cells(rowx + 1, colx), Sht.Cells(StRow, colx)).SpecialCells(xlCellTypeVisible).Delete Shift:=xlUp '删除被筛选出来的行(删掉不为当前省份的行)

Sht.Range(rowx & ":" & rowx).AutoFilter '取消筛选

ActiveWindow.SmallScroll Down:=-StRow

ActiveWindow.SmallScroll ToRight:=-100

If Dir(Wb1.Path & "\拆分\", vbDirectory) = "" Then MkDir ThisWorkbook.Path & "\拆分\" '看看当前文件夹内是否存在"拆分"文件夹,如果没有就创建一个

Pth = Wb1.Path & "\拆分\" & Itm & "-" & namex & ".xls"

Wb2.SaveAs Filename:=Pth, FileFormat:=xlExcel8, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False, CreateBackup:=False

Wb2.Close '关闭表格

Next

Set Pro = Nothing '释放变量

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 '打开屏幕更新

Application.DisplayAlerts = True '打开提示事件

End Sub

Sub 通用发送邮件()

'On Error Resume Next

Dim cm As Variant

UserForm1.Show

UserName = UserForm1.ComboBox1

UserPass = UserForm1.TextBox1.Value

With Application.FileDialog(msoFileDialogFolderPicker)

.InitialFileName = ActiveWorkbook.Path & "\"

If .Show = -1 Then

Pth = Application.FileDialog(msoFileDialogFolderPicker).SelectedItems.Item(1) & "\"

End If

End With

'定义文件夹

Dim FS, F, FF, Fil, BName, EName

Set FS = CreateObject("Scripting.FileSystemObject")

Set F = FS.GetFolder(Pth)

Set FF = F.Files

If FF Is Nothing Or F Is Nothing Then

MsgBox ("文件或文件夹错误,请查证在本文件目录内存在'拆分'文件夹,并且已经生成拆分文件")

Exit Sub

End If

'保存文件信息

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), "-") - 1)

Next

Set Sht = ThisWorkbook.Sheets("邮件联系人")

colnew = Sht.Cells(1, Columns.Count).End(xlToLeft).Column + 1 '联系人空白列(用于记录发送结果)

Sht.Cells(1, colnew).Value = Pth & Chr(10) & Date & " " & Time & " 发送结果"

tex = InputBox("请输入邮件正文自定义段")

For m = 1 To i

Err.Clear

linkman = ""

emailx = ""

Set bbb = Sht.Range("a:a").Find(FN(m, 3))

If bbb Is Nothing Then

rownew = Sht.Range("a60000").End(xlUp).Row + 1

Sht.Cells(rownew, 1).Value = FN(m, 3)

Sht.Cells(rownew, colnew).Value = "未找到发件人"

mg = mg & FN(m, 3) & Left(" ", 10 - Len(FN(m, 3)) * 2) & "未找到发件人" & Chr(13)

GoTo line5

End If

For n = 1 To Sht.Range("a60000").End(xlUp).Row '循环查找联系人姓名和邮件地址

If FN(m, 3) = Sht.Cells(n, 1).Value Then

linkman = linkman & Sht.Cells(n, 2).Value & "、"

emailx = emailx & Replace(Sht.Cells(n, 7).Value, ";", "") & ","

End If

Next

If Len(emailx) < 2 Then '如果邮件地址是空,那就不发送本城市

bbb.Offset(0, colnew - 1).Value = "无邮件地址"

mg = mg & FN(m, 3) & Left(" ", 10 - Len(FN(m, 3)) * 2) & "无邮件地址" & Chr(13)

GoTo line5

End If

linkman = Left(linkman, Len(linkman) - 1) '删掉最后一个符号

emailx = Left(emailx, Len(emailx) - 1)

Set cm = CreateObject("CDO.Message") '创建对象

cm.From = UserName '设置发信人的邮箱

cm.To = emailx '设置收信人的邮箱

cm.Subject = FN(m, 1) '设定邮件的主题

cm.TextBody = "亲爱的 ********:" _

& Chr(10) & " 附件为 " & FN(m, 1) & ",请查收。" & Chr(10) & tex _

& Chr(10) & "谢谢!" _

& Chr(10) & " _______________________________________________________" _

& Chr(10) & " ** 部门 " _

& Chr(10) & " 姓名 " _

& Chr(10) & " 手机:********* " _

& Chr(10) & " 电话:********* " _

& Chr(10) & " Email:********* " _

& Chr(10) & " 地址:****************** " '邮件正文

cm.AddAttachment Pth & FN(m, 1) & "." & FN(m, 2) '添加附件

stUl = "http://schemas.microsoft.com/cdo/configuration/"

With cm.Configuration.Fields

.Item(stUl & "smtpserver") = "http://mail.qq.com" 'SMTP 服务器地址

.Item(stUl & "smtpserverport") = 25 'SMTP 服务器端口

.Item(stUl & "sendusing") = 2 '发送端口

.Item(stUl & "smtpauthenticate") = 1

.Item(stUl & "sendusername") = UserName '发送方邮箱名称

.Item(stUl & "sendpassword") = UserPass '发送方邮箱密码"

.Update

End With

cm.Send '发送

'生成反馈信息

If Err.Number = 0 Then

mg = mg & FN(m, 3) & Left(" ", 10 - Len(FN(m, 3)) * 2) & "发送成功" & Chr(13)

bbb.Offset(0, colnew - 1).Value = "发送成功"

Else

mg = mg & FN(m, 3) & Left(" ", 10 - Len(FN(m, 3)) * 2) & "发送失败" & Chr(13)

bbb.Offset(0, colnew - 1).Value = "发送失败"

End If

Set cm = Nothing '发送成功后即时释放对象

line5:

Next

MsgBox (Left(mg, Len(mg) - 1)) '确认结果

End Sub

再贴一个给职场小白

前面拆分,肯定有合并,再贴一个合并工作簿的代码,也超级简单的哦。

开始:

新建一个空白工作簿

还是一样右击 sheet——查看代码,这次不用建立模块,直接把代码贴进去即可

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

数据是这样的

点击文件夹执行后

按确定后,数据就好了。

对了,工作簿名称不一样也不要紧哦

比如这样……

代码:

Sub 文件合并()

Application.ScreenUpdating = False

'On Error Resume Next

Dim Pth As String

Set wst1 = ActiveSheet

row1 = 0

wst1.Cells.Delete Shift:=xlUp

'打开文件夹

Dim shell, s

Set shell = CreateObject("Shell.Application")

Set fl = shell.BrowseForFolder(0, "请选择文件夹", 0, Pth)

If fl Is Nothing Then Exit Sub

Pth = fl.self.Path & "\"

'定义文件夹

Dim FS, F, FF, Fil, BName, EName

Set FS = CreateObject("Scripting.FileSystemObject")

Set F = FS.GetFolder(Pth)

Set FF = F.Files

For Each Fil In FF

BName = FS.GetBaseName(Fil)

EName = FS.GetExtensionName(Fil)

If EName = "xls" Or EName = "xlsx" Or EName = "XLS" Or EName = "XLSX" Then

Workbooks.Open (Fil)

Set wst2 = ActiveSheet

Set wb = ActiveWorkbook

strow = wst2.UsedRange.Rows.Count

If row1 = 0 Then

wst2.Rows("1:" & strow).Copy wst1.Cells(row1 + 1, 1)

row1 = row1 + strow

Else

wst2.Rows("2:" & strow).Copy wst1.Cells(row1 + 1, 1)

row1 = row1 + strow - 1

End If

Application.CutCopyMode = False

wb.Close (False)

End If

Next

MsgBox ("完成")

End Sub

拆分 or 合并 or 群发邮件,是三个独立的宏,都可以灵活运用。建议大家复制保存为 TXT 文档或者存到一个 Excel 里面,作为工具使用,不用每次黏贴复制了。

最后

1、我是女生

2、我早就从那家公司离职了,平时工作忙和妹子没再联系,走之前给她写了一堆程序,覆盖她工作中 50% 的 Excel 处理

3、只是同事之间的帮忙,而且我也喜欢研究。为什么要扯到感情,大家那么喜欢童话故事?

4、我不是专业写 VBA 的

花了两个小时一个一个截图 + 写注释,你能不能点个赞再走 n(*≧▽≦*)n


Viewing all articles
Browse latest Browse all 20608

Trending Articles