我想要实现的目标
我有两张纸:'仪表板'和'临时计算' 仪表板包含所有员工详细信息,范围“N1”“N2”包含日期 现在,宏将填充员工数据并生成日历日历,如下图所示 'temp calc'的项目详细信息包含开始日期结束日期。(此处删除不在介于仪表板表单的n1和n2日期之间的日期)。
现在从仪表板表中引用它们的empid,并使用填充在仪表板表格中的第一天,我遍历临时计算表中的emp id并返回员工当前正在为特定日期工作的项目数量的计数。如下图所示。
我是如何做到的:
代码.....
Option Explicit
Sub Count()
' x= no of columns(dashboard calender)
' y= no of rows(dashboard emp id)
' z= no of rows(temp calc sheet emp id)
Application.ScreenUpdating = False
'Clear calender data
Range("Q4").Select
Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
Selection.ClearContents
Dim i, j, k, l, d, x, y, z, Empid As Long
Dim currentdate, startdate, enddate As Date
x = (Range("n2") - Range("n1")) + 1
y = Application.WorksheetFunction.counta(Range("A:A")) - 1
z = Application.WorksheetFunction.counta(Worksheets("Temp Calc").Range("A:A")) - 1
For i = 1 To y Step 1 'To loop through the emp_id in dashboard.
For j = 1 To x Step 1 'To loop through the calender in dashboard daywise.
d = 0
For k = 1 To z Step 1 'To loop through the emp_id i temp calc sheet.
Empid = ActiveSheet.Cells(i + 3, 1).Value
currentdate = Cells(3, 16 + j).Value
startdate = Worksheets("Temp calc").Cells(k + 1, 3).Value
enddate = Worksheets("Temp calc").Cells(k + 1, 4).Value
If (Worksheets("Temp calc").Cells(k + 1, 1).Value) = Empid Then
If (currentdate >= startdate) And (currentdate <= enddate) Then 'To check whether the first column date falls within the project start and end date
d = d + 1
End If
End If
Next
Worksheets("Dashboard").Cells(i + 3, j + 16) = d
Next
Next
Range("q4").Select
Application.ScreenUpdating = True
End Sub
我的问题:代码完成了这项工作,但我有两个问题。
太慢了
有时候工作簿会说不响应,也不会做工作。我检查过它在后台不起作用。我让程序一夜之间运行,但没有响应。
可能的解决方案:
使用两个数组:一个数组用于在仪表板中存储empid,第二个数组用于存储在仪表板中生成的日历。然后将其与临时计算表中的数据进行比较,并将计数返回到数组2并将其写回 问题是我刚刚开始阅读有关数组的内容,而我还在学习
我对可能的替代方案持开放态度:
欢呼声,
马修
答案 0 :(得分:2)
有几个内置函数可以非常高效地完成这项工作。我将在此列出几个:
任何这些都应该让你的代码充分快速 - 我的个人偏好是选项3 ...如果你不喜欢选项3的布局,而你不能“只是这样”,那么创建隐藏工作表中的数据透视表,并将数据从那里复制到所需的工作表。
顺便说一句 - 像COUNTA("A:A"
这样的事情可能很慢,因为这意味着要查看列中的所有150万个单元格。如果行是连续的,您应该能够执行以下操作:
COUNTA(RANGE("A1", [A1].End(xlDown)))
或(如果不是连续的)
numRows = ActiveSheet.Cells.SpecialCells(xlLastCell).Row
COUNTA(RANGE("A1", [A1].OFFSET(numRows,0)))
答案 1 :(得分:0)
这对我有用.....希望对有同样问题的其他人有所帮助.. 非常感谢所有帮助我的人以及每个人的建议和答案......:)
Sub assginment_count()
Dim a, i As Long, ii As Long, dic As Object, w, e, s
Dim StartDate As Date, EndDate As Date
Set dic = CreateObject("Scripting.Dictionary")
' use dic as a "mother dictionary" object to store unique "Employee" info.
dic.CompareMode = 1
' set compare mode to case-insensitive.
a = Sheets("temp calc").Cells(1).CurrentRegion.Value
' store whole data in "Temp Calc" to variable "a" to speed up the process.
For i = 2 To UBound(a, 1)
' commence loop from row 2.
If Not dic.exists(a(i, 1)) Then
Set dic(a(i, 1)) = CreateObject("Scripting.Dictionary")
' set child dictionary to each unique "Emp Id"
End If
If Not dic(a(i, 1)).exists(a(i, 3)) Then
Set dic(a(i, 1))(a(i, 3)) = _
CreateObject("Scripting.Dictionary")
' set child child dictionary to each unique "Startdt" to unique "Emp Id"
End If
dic(a(i, 1))(a(i, 3))(a(i, 4)) = dic(a(i, 1))(a(i, 3))(a(i, 4)) + 1
' add 1(count) to a unique set of "Emp Id", "Startdt" and "Finishdt", so that it enables to count as
' different match even if multiple same unique set of "Emp Id", "Startdt" and "Finishdt" appears.
Next
With Sheets("dashboard")
StartDate = .[N1].Value: EndDate = .[N2].Value
With .Range("a3").CurrentRegion.Resize(, .Rows(3).Find("*", , , , xlByRows, xlPrevious).Column)
' finding the data range, cos you have blank column within the data range.
.Columns("q").Resize(.Rows.count - 3, .Columns.count - 16).Offset(3).Value = 0
' initialize the values in result range set to "0".
a = .Value
' store whole data range to an array "a"
For i = 4 To UBound(a, 1)
' commence loop from row 4.
If dic.exists(a(i, 1)) Then
' when mother dictionary finds "Employee"
For Each e In dic(a(i, 1))
' loop each "Startdt"
For Each s In dic(a(i, 1))(e)
' loop corresponding "Finishdt"
If (e <= EndDate) * (s >= StartDate) Then
' when "Startdt" <= EndDate and "Finishdt" >= StartDate
For ii = 17 To UBound(a, 2)
' commence loop from col.Q
If (a(3, ii) >= e) * (s >= a(3, ii)) Then
' when date in the list matches to date between "Startdt" and "Finishdt"
a(i, ii) = a(i, ii) + dic(a(i, 1))(e)(s)
' add its count to corresponding place in array "a"
End If
Next
End If
Next
Next
End If
Next
.Value = a
' dump whole data to a range.
End With
End With
End Sub