ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

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

[求助] 能够按指定行号、列标,动态扩展统计区域的内嵌自定义函数

[复制链接]

TA的精华主题

TA的得分主题

发表于 2019-11-11 08:04 | 显示全部楼层 |阅读模式
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 玉阳山人 于 2019-11-11 09:08 编辑

1.gif

能够按指定行号、列标,动态扩展统计区域的内嵌自定义函数.zip (25.94 KB, 下载次数: 14)

重要提示:第三参数为需要进行统计的数据区域的行号或列标,第四参数为需要进行统计的数据区域的工作表名称。
   在对同一类型的多个类似工作表进行统计计算时,经常会遇到因为行、列区域不等的制约,导致无法复制公式的现象发生,无奈得频繁修改各个工作表里所要进行统计的数据区域--如果工作表很多,既麻烦又容易出错,能不能创建一个动态区域的自定义函数,使之能够按照指定行号、列标,来自动扩展需要统计的数据区域大小呢?

   这样,如附件所示,只需复制J25:J40的条件格式到其它工作表的合适地方,右拉即可显示所有数据区域的统计结果。

   恳请神通广大的大神们,能够按附件里的运算规则和要求,创建一个自定义函数。




TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-11 11:59 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-11-11 13:45 | 显示全部楼层
  1. Option Explicit

  2. Function DTQY(StartID As Variant, EndID As Variant, Optional RowOrColID As Variant = "", Optional shName As String = "") As Variant
  3.     Dim rgCur As Range, strRowOrColID As String, strSelType As String
  4.     Dim lngCurRow As Long, lngCurCol As Long
  5.     Dim SelRow_Start As Long, SelRow_End As Long
  6.     Dim SelCol_Start As Long, SelCol_End As Long
  7.     Dim SelSh As Worksheet, arrResult As Variant
  8.    
  9.     '取得公式所在单元格的信息
  10.     Set rgCur = Application.Caller
  11.     lngCurRow = rgCur.Row
  12.     lngCurCol = rgCur.Column
  13.     '获取工作表
  14.     If Trim(shName) = "" Then
  15.         Set SelSh = rgCur.Worksheet
  16.     Else
  17.         Set SelSh = GetShByName(Trim(shName))
  18.     End If
  19.     If SelSh Is Nothing Then
  20.         DTQY = "表名不存在"
  21.         Exit Function
  22.     End If
  23.    
  24.     '判断参数类型
  25.     If IsNumeric(StartID) Then
  26.         strSelType = "ROW"
  27.     Else
  28.         strSelType = "COL"
  29.     End If
  30.     '如果参数1与参数2类型不一致,退出
  31.     If IsNumeric(StartID) <> IsNumeric(EndID) Then
  32.         DTQY = "参数1、2类型不一致"
  33.         Exit Function
  34.     End If
  35.     '如果参数1、2的类型与参数3相同,退出
  36.     If RowOrColID <> "" And (IsNumeric(StartID) = IsNumeric(RowOrColID)) Then
  37.         DTQY = "参数3类型不对"
  38.         Exit Function
  39.     End If
  40.    
  41.     '如果行号参数不对,退出
  42.     If IsNumeric(StartID) And (Val(StartID) < 1 Or Val(StartID) > Rows.Count) Then
  43.         DTQY = "参数1设置有误"
  44.         Exit Function
  45.     End If
  46.     If IsNumeric(EndID) And (Val(EndID) < 1 Or Val(EndID) > Rows.Count) Then
  47.         DTQY = "参数2设置有误"
  48.         Exit Function
  49.     End If
  50.    
  51.     '设置第三参数
  52.     strRowOrColID = Trim(UCase(RowOrColID))
  53.     '根据传入的参数,设置区域参数
  54.     Select Case strSelType
  55.         Case "ROW" '设置参数为行号
  56.             SelRow_Start = Val(StartID) '起始行
  57.             SelRow_End = Val(EndID) '结束行
  58.             '根据第三参数获取列号
  59.             If strRowOrColID <> "" Then
  60.                 lngCurCol = GetColIDByStr(strRowOrColID)
  61.             End If
  62.             '列号有误,退出
  63.             If lngCurCol = 0 Then
  64.                 DTQY = "参数3设置有误"
  65.                 Exit Function
  66.             End If
  67.             '返回选择区域
  68.             arrResult = SelSh.Range(SelSh.Cells(SelRow_Start, lngCurCol), SelSh.Cells(SelRow_End, lngCurCol))
  69.         Case "COL" '设置参数为列号
  70.             SelCol_Start = GetColIDByStr(CStr(StartID)) '起始列
  71.             SelCol_End = GetColIDByStr(CStr(EndID)) '结束列
  72.             If SelCol_Start * SelCol_End = 0 Then
  73.                 DTQY = "参数1、2设置有误"
  74.                 Exit Function
  75.             End If
  76.             '根据第三参数获取行号
  77.             If strRowOrColID <> "" Then
  78.                 lngCurRow = Val(strRowOrColID)
  79.             End If
  80.             '行号有误,退出
  81.             If lngCurRow < 1 Or lngCurRow > Rows.Count Then
  82.                 DTQY = "参数3设置有误"
  83.                 Exit Function
  84.             End If
  85.             '返回选择区域
  86.             arrResult = SelSh.Range(SelSh.Cells(lngCurRow, SelCol_Start), SelSh.Cells(lngCurRow, SelCol_End))
  87.     End Select
  88.    
  89.     '返回最终结果区域
  90.     DTQY = arrResult
  91. End Function

  92. '根据列名,返回列标索引
  93. Function GetColIDByStr(strColName As String) As Long
  94.     Dim strAddress  As String, lngLen As Long
  95.     Dim lngIndex As Long, strChar As String
  96.     Dim lngColID As Long
  97.    
  98.     strAddress = Trim(UCase(strColName))
  99.     lngLen = Len(strAddress)
  100.    
  101.     For lngIndex = 1 To lngLen
  102.         strChar = Mid(strAddress, lngIndex, 1)
  103.         If Asc(strChar) < 65 Or Asc(strChar) > 90 Then
  104.             GetColIDByStr = 0
  105.             Exit Function
  106.         End If
  107.         lngColID = lngColID + (((Asc(strChar) - 65) Mod 26) + 1) * (26 ^ (lngLen - lngIndex))
  108.     Next
  109.    
  110.     If lngColID > Columns.Count Then
  111.         GetColIDByStr = 0
  112.         Exit Function
  113.     End If
  114.    
  115.     GetColIDByStr = lngColID
  116. End Function
  117. '根据表名返回工作表
  118. Function GetShByName(strShName As String) As Worksheet
  119.     Dim sh As Worksheet
  120.     For Each sh In Sheets
  121.         If sh.Name = strShName Then
  122.             Set GetShByName = sh
  123.             Exit Function
  124.         End If
  125.     Next
  126.     Set GetShByName = Nothing
  127. End Function

复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-11 20:40 | 显示全部楼层
本帖最后由 玉阳山人 于 2019-11-11 21:23 编辑

1.gif

老师:列区域公式
    1.DTQY(5,22)外套MAX,MIN,AVERAGE,MODE,COUNT都能显示正确结果;但在输入=COUNTIF(DTQY(5,22),3),发生#VALUE!错误。      
2.输入第三、四参数时,必须前后加"引号,=MAX(DTQY(5,22,"K","通用公式")),才能显示正确结果;不加双引号,=MAX(DTQY(5,22,K,通用公式)),否则就会显示#VALUE!错误?能不能修改成不加双引号,如=MAX(DTQY(5,22,K,通用公式))就能显示正确结果?
   3.由于是统计计算,所以应该显示所有结果,不必设置不显示0。 1.gif

    行区域公式:=DTQY(J,Q)无论外套
MAX,MIN,AVERAGE,MODE,COUNT哪个公式,怎么都显示#VALUE!错误?






TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-12 07:54 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2019-11-12 08:55 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
1、要有一些基本常识,字符型 与 数值型【DTQY("J","Q")】
2、原来考虑是简单的处理,返回的是数组,给你改为返回range对象
  1. Option Explicit

  2. Function DTQY(StartID As Variant, EndID As Variant, Optional RowOrColID As Variant = "", Optional shName As String = "") As Variant
  3.     Dim rgCur As Range, strRowOrColID As String, strSelType As String
  4.     Dim lngCurRow As Long, lngCurCol As Long
  5.     Dim SelRow_Start As Long, SelRow_End As Long
  6.     Dim SelCol_Start As Long, SelCol_End As Long
  7.     Dim SelSh As Worksheet, arrResult As Variant
  8.    
  9.     '取得公式所在单元格的信息
  10.     Set rgCur = Application.Caller
  11.     lngCurRow = rgCur.Row
  12.     lngCurCol = rgCur.Column
  13.     '获取工作表
  14.     If Trim(shName) = "" Then
  15.         Set SelSh = rgCur.Worksheet
  16.     Else
  17.         Set SelSh = GetShByName(Trim(shName))
  18.     End If
  19.     If SelSh Is Nothing Then
  20.         DTQY = "表名不存在"
  21.         Exit Function
  22.     End If
  23.    
  24.     '判断参数类型
  25.     If IsNumeric(StartID) Then
  26.         strSelType = "ROW"
  27.     Else
  28.         strSelType = "COL"
  29.     End If
  30.     '如果参数1与参数2类型不一致,退出
  31.     If IsNumeric(StartID) <> IsNumeric(EndID) Then
  32.         DTQY = "参数1、2类型不一致"
  33.         Exit Function
  34.     End If
  35.     '如果参数1、2的类型与参数3相同,退出
  36.     If RowOrColID <> "" And (IsNumeric(StartID) = IsNumeric(RowOrColID)) Then
  37.         DTQY = "参数3类型不对"
  38.         Exit Function
  39.     End If
  40.    
  41.     '如果行号参数不对,退出
  42.     If IsNumeric(StartID) And (Val(StartID) < 1 Or Val(StartID) > Rows.Count) Then
  43.         DTQY = "参数1设置有误"
  44.         Exit Function
  45.     End If
  46.     If IsNumeric(EndID) And (Val(EndID) < 1 Or Val(EndID) > Rows.Count) Then
  47.         DTQY = "参数2设置有误"
  48.         Exit Function
  49.     End If
  50.    
  51.     '设置第三参数
  52.     strRowOrColID = Trim(UCase(RowOrColID))
  53.     '根据传入的参数,设置区域参数
  54.     Select Case strSelType
  55.         Case "ROW" '设置参数为行号
  56.             SelRow_Start = Val(StartID) '起始行
  57.             SelRow_End = Val(EndID) '结束行
  58.             '根据第三参数获取列号
  59.             If strRowOrColID <> "" Then
  60.                 lngCurCol = GetColIDByStr(strRowOrColID)
  61.             End If
  62.             '列号有误,退出
  63.             If lngCurCol = 0 Then
  64.                 DTQY = "参数3设置有误"
  65.                 Exit Function
  66.             End If
  67.             '返回选择区域
  68.             Set arrResult = SelSh.Range(SelSh.Cells(SelRow_Start, lngCurCol), SelSh.Cells(SelRow_End, lngCurCol))
  69.         Case "COL" '设置参数为列号
  70.             SelCol_Start = GetColIDByStr(CStr(StartID)) '起始列
  71.             SelCol_End = GetColIDByStr(CStr(EndID)) '结束列
  72.             If SelCol_Start * SelCol_End = 0 Then
  73.                 DTQY = "参数1、2设置有误"
  74.                 Exit Function
  75.             End If
  76.             '根据第三参数获取行号
  77.             If strRowOrColID <> "" Then
  78.                 lngCurRow = Val(strRowOrColID)
  79.             End If
  80.             '行号有误,退出
  81.             If lngCurRow < 1 Or lngCurRow > Rows.Count Then
  82.                 DTQY = "参数3设置有误"
  83.                 Exit Function
  84.             End If
  85.             '返回选择区域
  86.             Set arrResult = SelSh.Range(SelSh.Cells(lngCurRow, SelCol_Start), SelSh.Cells(lngCurRow, SelCol_End))
  87.     End Select
  88.    
  89.     '返回最终结果区域
  90.     Set DTQY = arrResult
  91. End Function

  92. '根据列名,返回列标索引
  93. Function GetColIDByStr(strColName As String) As Long
  94.     Dim strAddress  As String, lngLen As Long
  95.     Dim lngIndex As Long, strChar As String
  96.     Dim lngColID As Long
  97.    
  98.     strAddress = Trim(UCase(strColName))
  99.     lngLen = Len(strAddress)
  100.    
  101.     For lngIndex = 1 To lngLen
  102.         strChar = Mid(strAddress, lngIndex, 1)
  103.         If Asc(strChar) < 65 Or Asc(strChar) > 90 Then
  104.             GetColIDByStr = 0
  105.             Exit Function
  106.         End If
  107.         lngColID = lngColID + (((Asc(strChar) - 65) Mod 26) + 1) * (26 ^ (lngLen - lngIndex))
  108.     Next
  109.    
  110.     If lngColID > Columns.Count Then
  111.         GetColIDByStr = 0
  112.         Exit Function
  113.     End If
  114.    
  115.     GetColIDByStr = lngColID
  116. End Function
  117. '根据表名返回工作表
  118. Function GetShByName(strShName As String) As Worksheet
  119.     Dim sh As Worksheet
  120.     For Each sh In Sheets
  121.         If sh.Name = strShName Then
  122.             Set GetShByName = sh
  123.             Exit Function
  124.         End If
  125.     Next
  126.     Set GetShByName = Nothing
  127. End Function
复制代码

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-12 09:49 | 显示全部楼层
本帖最后由 玉阳山人 于 2019-11-12 09:53 编辑
lsdongjh 发表于 2019-11-12 08:55
1、要有一些基本常识,字符型 与 数值型【DTQY("J","Q")】
2、原来考虑是简单的处理,返回的是数组,给你 ...

image.png
      老师:   还有一点需要修改--由于是统计计算,所以应该显示所有结果,当计算结果为0时,应该显示0,不能设置为空白【L42:Q43里土黄色填充的空格应该显示0才对】。

   修改了这一点,就尽善尽美了!

TA的精华主题

TA的得分主题

发表于 2019-11-12 09:51 | 显示全部楼层
玉阳山人 发表于 2019-11-12 09:49
老师:
         还有一点需要修改--由于是统计计算,所以应该显示所有结果,当计算结果为0时,应该显示 ...

又是一个基本常识:自带函数自己处理!

评分

1

查看全部评分

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-12 10:05 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
本帖最后由 玉阳山人 于 2019-11-12 10:08 编辑
lsdongjh 发表于 2019-11-12 09:51
又是一个基本常识:自带函数自己处理!

举例:如L42,求L$15:L$22的最小值,如果输入公式=MIN(L$15:L$22),明显能看到计算结果为0;但当输入公式=MIN(DTQY(5,22))时,计算结果仍然为0,却被设置为不显示0值,想不通这是什么原因造成的? 1.gif

TA的精华主题

TA的得分主题

 楼主| 发表于 2019-11-12 10:20 | 显示全部楼层
lsdongjh 发表于 2019-11-12 09:51
又是一个基本常识:自带函数自己处理!

1.gif

老师:委实想不明白为什么--输入常规公式=MIN(L$5:L$22) 能明显看到0,输入公式=MIN(DTQY(L$5:L$22)),其0值却不显示?
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

关闭

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

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

GMT+8, 2024-4-20 03:09 , Processed in 0.058923 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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