如何逐行使用高级过滤

时间:2018-04-29 03:38:13

标签: excel excel-vba filtering vba

人员履行职责日期的excel文件如图所示。标记职责为X

pic

如何使用过滤获取特定人员的职责日期?

有没有办法让每个人的姓名连同他们的工作日期在一张单独的表格中?

2 个答案:

答案 0 :(得分:0)

我认为你要做的是:

逆透视:

  1. 选择数据,然后在Insert菜单上选择Table
  2. Data菜单上点击From Table/Range
  3. 查询窗口将会打开。选择您需要提取的列。根据您的数据,要突出显示的列是“ 类型 ”和“ 案例数
  4. Tranform菜单上选择Unpivot Columns
  5. 如果现在看起来正确,请关闭查询编辑器(接受更改)。
  6. 另一个例子:

    如果您的目标是从获取此

    https://getbootstrap.com/docs/4.0/components/forms/

    ... this (或 ):

    unpivot1

    ...那么您想要做的事情被称为 Unpivot

    如何取消隐藏“交叉表样式”数据:

    unpivot2

    您可以找到UnPivot demo上写出的步骤,还有更多a question I answered here

答案 1 :(得分:0)

通过数组过滤方法

你需要逐行过滤结果(例如Tessy Paul- 4月18日,4月27日,4月30日,4月2日,5月18日),但IMO你不会通过高级过滤器获取它们方法。相反,我展示了一种使用数组获取源数据的替代方法(通过VBA循环一个范围很慢)并通过(=重新编码)数据> Application.Filter“x”标记的项目匹配为职责

基本步骤

首先,只需分配预定义的范围参考,即可将所有数据写入变量二维数据字段数组 - 请参阅第[2]节:

Dim v   As Variant  ' or simply: Dim v
Dim rng As Range    
'set rng = ...
v = rng.Value2  ' or simply: v = rng

此外,可以通过Application.Filter过滤数组,但有一些限制:

  • a)除了隔离的细胞数据和
  • 之外,您还需要一些其他信息
  • b)你需要一个1-dim数组。

  • ad a)为了在过滤时识别姓名和工作日期,只需将这些信息与分隔符一起添加(例如“#”,请参阅第[3]节)。     这允许您稍后通过循环遍历每个数组项来拆分过滤后的数据 - 请参阅[4]和[5]部分。

  • ad b)要从2-dim数组中获取1-dim数组,可以通过Application.Index函数提取行或列。     在下面的示例中,我将结果分配给另一个名为vi的数组。     例如:如果要提取如4.1节所示的行,则第二个参数标识从1开始的行号,第三个参数列号只是获取0:     然后,您可以将Filter函数应用于此新标注的源数组和匹配字符串“x#”,以通过 x 字符获取定义为 Duty 的所有数据,选定的分隔符

    vi = VBA.filter(Application.Index(v,i,0),“x#”,True,False)

注意:

匹配字符串由两个字符(“x#”)组成,因为“x”也可以是名称的一部分(例如亚历山大)。

作为行式过滤的补充:
要提取列,请参阅第5.1节,因为这需要通过Application.Transpose进行额外调整。

每个提取的行或列数组将写回到目标工作表,并通过Visual Basic编辑器(VBE)中即时窗口中Join中的Debug.Print函数显示

代码示例

Option Explicit

Sub DutiesPerName()
' Site: https://stackoverflow.com/questions/50083149/how-can-i-use-advance-filtering-row-wise
' [0] Declare variables
  Dim a()
  Dim ws    As Worksheet, ws2 As Worksheet
  Dim rng   As Range, i As Long, j As Long, r As Long, c As Long
  Dim v, vi, temp
' [1] define sheetname and data range
' 1.0 set worksheet object to memory
  Set ws = ThisWorkbook.Worksheets("MyDataSheet")  ' << change to your data sheet name
  Set ws2 = ThisWorkbook.Worksheets("MyDutySheet") ' << change to your target sheet name
' 1.1 get rows and columns
  r = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
  c = ws.Range("A1").End(xlToRight).Column
' 1.2 Alternative code line: Set rng = ws.UsedRange
  Set rng = ws.Range(ws.Range(ws.Cells(1, 1), ws.Cells(r, c)).Address)
' [2] create a variant 1-based 2-dim datafield array
  v = rng.Value2
' [3] CODE duty items by appending "#" plus date and name info
  For i = 2 To UBound(v)                ' start loop from 2nd row
      v(i, 1) = "x#" & v(i, 1)          ' mark name captions to get them filtered, too
      For j = 3 To UBound(v, 2)         ' start inner loop from 3rd column
          If v(i, j) = "x" Then         ' code found duty items
             v(i, j) = v(i, j) & "#" & Format(v(1, j), "dd-mmm-yy") & "#" & v(i, 1) & "#" & j
             'Debug.Print "v(" & i & "," & j & ")=""" & v(i, j) & """"
          End If
      Next j
  Next i
' mark date captions with "x#" to get them filterd, too
  For j = 3 To UBound(v, 2)
        v(1, j) = "x###" & Format(Val(v(1, j)), "dd-mmm-yy")
  Next j
' -----------------------
' [4] Duty Dates per Name:
' -----------------------
  ws2.Cells.Clear: ws2.Range("A1") = "Name": ws2.Range("B1") = "Duty Dates ..."
  For i = 2 To UBound(v, 1)             ' start loop from 2nd row
  ' 4.1 filter redimensioned 1-dim ROW array via "x#"
    vi = VBA.filter(Application.Index(v, i, 0), "x#", True, False)
    For j = LBound(vi) To UBound(vi)
        vi(j) = Split(vi(j), "#")(1)    ' extracts date from e.g. "x#15-Jan-19#x#Paul#2"
    Next j
    ' write dates per name into target worksheet ws2
    ws2.Range("A1").Offset(i - 1, 0).Resize(1, UBound(vi) + 1) = vi
    Debug.Print "Row# " & i & " (" & _
                ws2.Range("A1").Offset(i - 1, 0).Resize(1, UBound(vi) + 1).Address & ") 1 Name + " & UBound(vi) & " Dates: " & _
                Join(vi, ", ")
   Next i
   Debug.Print
' -----------------------
' [5] Names per Duty Date:
' -----------------------
  ws2.Range("A1").Offset(r + 2, 0) = "Duty Date": ws2.Range("A1").Offset(r + 2, 1) = "Names ..."
  For i = 3 To UBound(v, 2)             ' start loop from 3rd column
  ' 5.1 filter redimensioned 1-dim COLUMN array via "x#"
    vi = VBA.filter(Application.Transpose(Application.Index(v, 0, i)), "x#", True, False)
    For j = LBound(vi) To UBound(vi)
        temp = Split(vi(j), "#")
        vi(j) = temp(3)                  ' extracts Name from e.g. "x#15-Jan-19#x#Albert#3"
    Next j
    ' write each names per date into target worksheet ws2
    If UBound(vi) > -1 Then
       ws2.Range("A1").Offset(r + i, 0).Resize(1, UBound(vi) + 1) = vi
       Debug.Print "Col# " & i & " (" & _
                   ws2.Range("A1").Offset(r + i, 0).Resize(1, UBound(vi) + 1).Address & ") 1 Date + " & UBound(vi) & " Names: " & _
                   Join(vi, ", ")
    End If
   Next i

End Sub