VBA编程:项目Spec相关内容的批量处理

在临床试验项目中,SDTM、ADaM的SPEC一般保存在EXCEL文档中。SPEC的创建和维护,有许多规则明确、机械重复的步骤。对于这些内容,如果能实现自动化批量处理,将会大大缩短工作时间、提高工作效率。

这篇文章,会展示3个使用VBA编程对EXCEL Spec进行批量处理的示例:

  1. 在每张Sheet中批量添加Analysis列名
  2. 不同版本Spec的变量更新标记
  3. 不同版本Spec的相同变量的内容提取

文章内容以介绍VBA程序思路、分享代码为主,不会聚焦具体语法细节。希望借助具体案例,为读者VBA的学习提供一些启发与帮助。

若读者想从零学习VBA编程,我推荐杨洋老师在网易云课堂的《全民一起VBA》系列课程。杨老师的课程,是我所接触到的最通俗易懂、最易上手的VBA课程

0. VBA的简单介绍

什么是VBA?百度百科的解释如下:

VBA (Visual Basic for Applications) 是Visual Basic的一种宏语言,是在其桌面应用程序中执行通用的自动化(OLE)任务的编程语言。

VBA是微软公司针对Office系列办公软件,推出的VB语法的编程语言。当我们使用Office软件进行机械重复的操作时,可以使用VBA写一些小程序来自动处理这些重复的操作,从而提高处理效率。

虽然,之前也介绍过SAS对EXCEL的批量处理,但就代码复杂程度来讲,同样的功能,VBA实现起来就要简洁的多得多。同时,针对大批量EXCEL Sheet的处理,VBA处理的速度也比SAS快得多。

VBA是一种面向对象的程序语言,主要语法会说明有几类事物 (类,Class),事物各自有什么属性 (Attribute),事物又能做什么事情 (方法,Method)。按照各个概念的组合,就会产生具体的事物——对象 (Object)。

VBA常用有4个类 (Class),具体如下:

  • Application,代表EXCEL系统本身
  • WorkBook,代表一个Excel文件
  • Worksheet,代表一张工作表
  • Range, 代表单元格组成的区域

下面具体介绍几个VBA功能示例,

1. 在每张Sheet中批量添加Analysis列名

有的公司一个Product的项目可能共用一个Excel Spec,每一个Analysis都会在这个Spec中的特定列进行内容的更新与修改,并且每一列都有一个特定的列名。

具体来讲,每当新开展一个Analysis,就需要在对应数据集的Sheet的末尾添加一列,即第一行末尾单元格中写入一个列名

具体到VBA编程中,有两个要点:

  • 第一,如何判断到达首行末尾;
  • 第二,如果首行已经存在对应列名,就不需要再次添加。

是否添加列名的关键在于,当前首行是否已经存在对应列名。这里可以指定一个指示变量变量exist = 0,对第一行单元格进行循环判断,如果存在等于列名的值,变量exist赋值为1。如果循环结束,不存在列名值,则在末尾单元格添加列名。

代码中使用While结构进行循环,跳出循环时,计数变量K (Cells(1, k)) 恰好指向末尾第一个空白单元格。当指定列名不存在时,可以直接赋值。

在填入列名后,代码中也会设置字体大小、加粗,单元格的填充色、上下左右对齐,以及列宽。

Option Explicit

Sub Add_New_col()
  Dim k, exist
  Dim spec As Workbook, adam as Worksheet

  Set spec = Workbooks.Open("/xxx/xxx/Spec.xlsx")

  For Each adam In spec.Worksheets
    k = 1
    exist = 0

    'Check new col name if exist
    Do While adam.Cells(1, k) <> ""
      If UCase(Trim(adam.Cells(1, k))) = "ANALYSIS NAME" Then
        exist = exist + 1
      End If
      k = k + 1
    Loop

    'Add new column name
    if exist = 0 Then
       adam.Cells(1, k) = "Analysis Name"

      With adam.Cells(1, k).Font
          .Size = 9
          .Bold = True
      End With

      adam.Cells(1, k).Interior.Color = 49407

      'Alignment
      With adam.Cells(1, k)
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlCenter
      End With

      adam.Columns(k).ColumnWidth = 25
    End if
  Next adam
End Sub

2. 不同版本Spec的变量更新标记

有时,某些Analysis的Spec与其他Spec内容相关,例如,ISS的相关分析是多个单独研究分析综合在一起,需要定期查看、比较单个研究Spec的更新变化。这里的更新可能涉及变量的新增、变量的属性变化等。

下面以新增变量为例,演示如何使用VBA编程高亮新增变量行。

程序的思路是,假设Spec_a的变量都是新增的、之前不存在的(exist = 0),然后遍历Spec_a中所有Sheet的所有第一列的变量名称。当选定Spec_a的一个变量时,会接着遍历Spec_b中相同Sheet名称中的所有变量,当出现相同变量名称时,变量exist赋值为1,即该变量在Spec_b中存在。

Spec_a中的一个变量循环结束后,如果exist = 0,那么就表明这个变量不在Spec_b中,即该变量为Spec_a中的新增变量,对其所在行标记为高亮。

演示代码如下:

Option Explicit

Sub Check_New_Var_In_Spec()
  Dim k,kk,exist 
  Dim spec_a As Workbook, spec_b As Workbook, adam_a As Worksheet, adam_b As Worksheet

  set spec_a = Workbooks.Open("/xxx/xxxx/spec_a.xlsx")
  set spec_b = Workbooks.Open("/xxx/xxxx/spec_b.xlsx")

  For Each adam_a In spec_a.Worksheets
    For Each adam_b In spec_b.Worksheets
      If Left(adam_a.name, 2) = "AD" and adam_a.name = adam_b.name Then
        k = 2
        'For each variables in adam_a
        Do While adam_a.Cells(k, 1) <> ""
          kk = 2
          exist = 0
          'For each variables in adam_b
          Do While adam_b.Cells(kk, 1) <> ""
            If adam_a.Cells(k, 1) = adam_b.Cells(KK, 1) Then
              exist = exist + 1
            End If

            kk = kk + 1
          Loop

          'The variable exist in spec_a but not in adam_b
           If exist = 0 Then
            adam_a.Rows(k).Interior.Color = 49407
           End If
          
           k = k + 1
        Loop
      End if
    Next adam_b
  Next adam_a
End Sub

3. 不同版本Spec的相同变量的内容提取

有时,某一Spec中变量衍生规则需要直接从另一个Spec中提取,但由于两个Spec所含的变量并非完全相同。这样,变量的位置、顺序就不同,导致无法批量复制粘贴。如果人工对单个变量进行复制粘贴,整个过程就太过繁琐,这时候,考虑使用VBA编程实现。

VBA实现以上内容的思路与标记新变量的思路类似,循环遍历两个Sheet中的变量。循环到相同的两变量时,把其中的一个变量的Derivation Rule赋值到另一个变量中。

不过,与标记新变量不同的是,新变量标记只需要获取行的信息,而具体内容的获取需要知晓对应单元格的行列信息。行的信息与变量名称的行信息相同,列的信息为对应的分析列名。为了使VBA程序简洁,我通过编写函数,单独获取列信息。

'Get Analysis column number
Function Get_col_Num(Worksheet, name)

  Dim k, col_num, col_nam
  k = 1
  col_num = 0
  col_nam = name

  Dim wb As Worksheet
  Set wb = Worksheet

  Do While wb.Cells(1, k) <> ""
    If UCase(Trim(wb.Cells(1,k))) = UCase(Trim(col_nam)) Then
      col_num = k
    End if
    
    k = k + 1
  Loop

  Get_col_Num = col_num
End Function

函数可以将判断结果进行传输,直接在后续程序中引用,主体程序如下:

Sub Get_Derivation()
  
  Dim k, kk, nam1, nam2
  nam1 = "Analysis A"
  nam2 = "Analysis B"
  
  Dim spec_a As Workbook, spec_b As Workbook, adam_a As Worksheet, adam_b As Worksheet
  set spec_a = Workbooks.Open("/xxx/xxxx/spec_a.xlsx")
  set spec_b = Workbooks.Open("/xxx/xxxx/spec_b.xlsx")

  For Each adam_a In spec_a.Worksheets
    For Each adam_b In spec_b.Worksheets
      If Left(adam_a.name, 2) = "AD" and adam_a.name = adam_b.name Then

        speca_col_num = Get_Col_Num(adam_a, nam1)
        specb_col_num = Get_Col_Num(adam_b, nam2)
        k = 2

        'For each variables in adam_a
        Do While adam_a.Cells(k, 1) <> ""
          kk = 2

          'For each variables in adam_b
          Do While adam_b.Cells(kk, 1) <> ""
            If adam_a.Cells(k, 1) = adam_b.Cells(KK, 1) Then
              If Left(adam_b.name, 2) = "AD" And specb_col_num > 0 And speca_col_num > 0 Then
               adam_b.Cells(kk, specb_col_num) = adam_a.Cells(k, speca_col_num)
               adam_b.Cells(kk, specb_col_num).Interior.Color = vbYellow 
              End If
            End If

            kk = kk + 1
          Loop
          
           k = k + 1
        Loop
      End if
    Next adam_b
  Next adam_a

End Sub

总结

文章介绍了3个使用VBA编程批量处理Spec内容的示例,对于规则明确、机械重复的步骤,使用VBA编程将会大大提高工作效率,缩短工作时间。希望这篇文章,对读者日常EXCEL Spec的处理有所启发和帮助。

感谢阅读, 欢迎关注:SAS茶谈!
若有疑问,欢迎评论交流!
欢迎点赞、转发!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容