I'm trying to copy a sheet by its code name and rename the copied sheets display name and code name,
I've come up with this but it only work one time and then it gets an error because there is already a sheet with that display name and codename, is there a why i can just add value + 1 to the end of the names?
Sub TESTONE()
Dim MySheetName As String
MySheetName = "Rename Me"
VBA_Copy_Sheet.Copy After:=ActiveSheet
ActiveSheet.Name = MySheetName
ActiveSheet.Tab.ColorIndex = 3
Dim wks As Worksheet
Set wks = ActiveSheet
ThisWorkbook.VBProject.VBComponents(wks.CodeName).Name = "BidSheet"
End Sub
I wish, it helps to you
Sub TESTONE()
Dim MySheetName As String
Dim MyCodeName As String
Dim wks As Worksheet
MySheetName = "Rename Me"
MyCodeName = "BidSheet"
If VBA_Copy_Sheet = Empty Then
Set VBA_Copy_Sheet = ActiveSheet
End If
VBA_Copy_Sheet.Copy After:=ActiveSheet
ActiveSheet.Name = GetNewSheetName(MySheetName, 0)
ActiveSheet.Tab.ColorIndex = 3
Set wks = ActiveSheet
MyCodeName = GetNewCodeName(MyCodeName, 0)
ThisWorkbook.VBProject.VBComponents(wks.CodeName).Name = MyCodeName
End Sub
Function GetNewSheetName(ByVal newName As String, ByVal n As Integer) As String
Dim ws As Worksheet
Dim modifiedName As String
modifiedName = newName & n
For Each ws In ActiveWorkbook.Worksheets
If ws.Name = modifiedName Then
n = n + 1
modifiedName = GetNewSheetName(newName, n)
Exit For
End If
Next
GetNewSheetName = modifiedName
End Function
Function GetNewCodeName(ByVal newName As String, ByVal n As Integer) As String
Dim ws As Worksheet
Dim modifiedName As String
modifiedName = newName & n
For Each ws In ActiveWorkbook.Worksheets
If ws.CodeName = modifiedName Then
n = n + 1
modifiedName = GetNewCodeName(newName, n)
Exit For
End If
Next
GetNewCodeName = modifiedName
End Function
You could store a counter in a range name and use that to increment your sheet, i.e:
Dim strName As String
Dim strCnt As String
Dim MySheetName As String
strName = "SheetCnt"
On Error Resume Next
strCnt = ActiveWorkbook.Names(strName).Value
On Error GoTo 0
If Len(strCnt) = 0 Then
ActiveWorkbook.Names.Add strName, 1
Else
strCnt = Replace(strCnt, "=", Chr(32)) + 1
ActiveWorkbook.Names(strName).RefersTo = strCnt
End If
MySheetName = "Rename Me " & strCnt
Related
I've been working on the code below for a while now and I'm almost done. It's taking 3 cells of data from one sheet, copying it in another, saving a copy based on the name in the first sheet and then looping until completed for all filled rows.
The snag I'm hitting is that when the first loop completes and it needs to select the WB that holds the data (the selection is needed for the function) it can't select it due to a fault in WsStam.Cells(row, iKolomnrCorpID).EntireRow.Select. When I debug, switch to the WB and run code it does work.
It's probably something stupid I'm missing. I appreciate your help!
Sub motivatieFormOpmaken()
Dim wbMotivTemp As Workbook
Dim wsMotiv As Worksheet
Dim PathOnly, mot, FileOnly As String
Dim StrPadSourcenaam As String
Dim WsStam As Worksheet
Dim WbStam As Workbook
Dim LastRow As Long
Set wbMotivTemp = ThisWorkbook
Set wsMotiv = ActiveSheet
StrHoofdDocument = ActiveWorkbook.Name
StrPadHoofdDocument = ActiveWorkbook.Path
StrPadSourcenaam = StrPadHoofdDocument & "\" & c_SourceDump
If Not FileThere(StrPadSourcenaam) Then
MsgBox "Document " & StrPadSourcenaam & " is niet gevonden."
Exit Sub
End If
Application.ScreenUpdating = False
Workbooks.Open FileName:=StrPadSourcenaam
Set WbStam = ActiveWorkbook
Set WsStam = WbStam.Worksheets("Stambestand")
Application.Run "Stambestand.xlsm!unhiderowsandcolumns"
Worksheets("stambestand").Activate
iLaatsteKolom = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).Column
iLaatsteRij = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).row
VulKolomNr
If KolomControle = False Then Exit Sub
Cells(1, iKolomnrVerwijderen_uit_de_tellingen).AutoFilter Field:=iKolomnrVerwijderen_uit_de_tellingen, Criteria1:="0"
LastRow = Cells(1, iKolomnrCorpID).End(xlDown).row
Dim row As Long
row = 2
With WsStam
Do Until row > iLaatsteRij
If .Cells(row, iKolomnrCorpID).RowHeight > 0 Then
WsStam.Cells(row, iKolomnrCorpID).EntireRow.Select 'It crashes at this line, after the first loop
wsMotiv.Range("motiv_cid") = Cells(row, iKolomnrCorpID).Text
wsMotiv.Range("motiv_naam") = Cells(row, iKolomnrNaam).Text
wsMotiv.Range("motiv_ldg") = Cells(row, iKolomnrHuidigeLeidingGevende).Text
n = naamOpmaken
wbMotivTemp.Activate
ActiveWorkbook.SaveAs FileName:=StrPadHoofdDocument & "\Docs\" & n & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End If
row = row + 1
Loop
End With
End Sub
Function naamOpmaken() As String
Dim rng As Range
Dim row As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
iRijnummer = rng.row
If iRijnummer > 1 Then
naam = Cells(iRijnummer, iKolomnrNaam).Text
ldg = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
cid = Cells(iRijnummer, iKolomnrCorpID).Text
Dim Position As Long, Length As Long
Dim n As String
Position = InStrRev(naam, " ")
Length = Len(naam)
n = Right(naam, Length - Position)
End If
naamOpmaken = n + "-" + ldg + "-" + cid
End Function
you have to activate a worksheet before selecting a cell of
since you're jumping between sheets you have to add
WsStam.Activate
right before
WsStam.Cells(row, iKolomnrCorpID).EntireRow.Select
BTW, you don't seem to need that selection at all so you may want to try and comment that line!
Hopefully you may find this useful for the future.
I've had a look through your code and made some updates so you shouldn't have to select any sheets and that problem line is removed completely. I've also added a new function at the bottom which will find the last cell on any sheet you reference.
Option Explicit 'Very important at top of module.
'Ensures all variables are declared correctly.
Sub motivatieFormOpmaken()
Dim wbMotivTemp As Workbook
Dim wsMotiv As Worksheet
' Dim PathOnly, mot, FileOnly As String
'''''''''''''''''''
'New code.
Dim PathOnly As String, mot As String, FileOnly As String
'''''''''''''''''''
Dim StrPadSourcenaam As String
'''''''''''''''''''
'New code.
Dim StrHoofdDocument As String
Dim StrPadHoofdDocument As String
Dim c_SourceDump As String
c_SourceDump = "MyFileName.xlsx"
Dim KolomControle As Boolean
'''''''''''''''''''
Dim WsStam As Worksheet
Dim WbStam As Workbook
Dim LastRow As Long
Set wbMotivTemp = ThisWorkbook
Set wsMotiv = ActiveSheet
StrHoofdDocument = ActiveWorkbook.Name
StrPadHoofdDocument = ActiveWorkbook.Path
StrPadSourcenaam = StrPadHoofdDocument & "\" & c_SourceDump
If Not FileThere(StrPadSourcenaam) Then
MsgBox "Document " & StrPadSourcenaam & " is niet gevonden."
Else
' Exit Sub
' End If
Application.ScreenUpdating = False
' Workbooks.Open Filename:=StrPadSourcenaam
' Set WbStam = ActiveWorkbook
'''''''''''''''''''
'New code.
Set WbStam = Workbooks.Open(Filename:=StrPadSourcenaam)
'''''''''''''''''''
Set WsStam = WbStam.Worksheets("Stambestand")
' Application.Run "Stambestand.xlsm!unhiderowsandcolumns"
'''''''''''''''''''
'New code as possible replacement for "unhiderowsandcolumns"
WsStam.Cells.EntireColumn.Hidden = False
WsStam.Cells.EntireRow.Hidden = False
'''''''''''''''''''
' Worksheets("stambestand").Activate
' iLaatsteKolom = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).Column
' iLaatsteRij = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).row
'''''''''''''''''''
'New code. You may want to check for filters before finding last row?
iLaatsteKolom = LastCell(WsStam).Column
iLaatsteRij = LastCell(WsStam).row
'''''''''''''''''''
VulKolomNr 'No idea - getting deja vu here.
' If KolomControle = False Then Exit Sub
'''''''''''''''''''
'New code.
If KolomControle Then
'''''''''''''''''''
WsStam.Cells(1, iKolomnrVerwijderen_uit_de_tellingen).AutoFilter Field:=iKolomnrVerwijderen_uit_de_tellingen, Criteria1:="0"
' LastRow = Cells(1, iKolomnrCorpID).End(xlDown).row
'''''''''''''''''''
'New code. The function will return the last filtered row.
LastRow = LastCell(WsStam).row
'''''''''''''''''''
Dim row As Long
row = 2
With WsStam
Do Until row > iLaatsteRij
If .Cells(row, iKolomnrCorpID).RowHeight > 0 Then
'''''''''''''''''''
'I don't think you even need this line.
' WsStam.Cells(row, iKolomnrCorpID).EntireRow.Select 'It crashes at this line, after the first loop
' wsMotiv.Range("motiv_cid") = Cells(row, iKolomnrCorpID).Text
' wsMotiv.Range("motiv_naam") = Cells(row, iKolomnrNaam).Text
' wsMotiv.Range("motiv_ldg") = Cells(row, iKolomnrHuidigeLeidingGevende).Text
'''''''''''''''''''
'New code. Note the "." before "Cells" which tells it that cell is on "WsStam" (in the "With")
' Also formatting the cell to text - will need to update as required.
wsMotiv.Range("motiv_cid") = Format(.Cells(row, iKolomnrCorpID), "0000")
wsMotiv.Range("motiv_naam") = Format(.Cells(row, iKolomnrNaam), "0000")
wsMotiv.Range("motiv_ldg") = Format(.Cells(row, iKolomnrHuidigeLeidingGevende), "0000")
'Do you mean this to save on each loop?
' n = naamOpmaken
' wbMotivTemp.Activate
' ActiveWorkbook.SaveAs Filename:=StrPadHoofdDocument & "\Docs\" & n & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
'''''''''''''''''''
'New code. Combines the above three lines.
wbMotivTemp.SaveAs Filename:=StrPadHoofdDocument & "\Docs\" & naamOpmaken(WsStam) & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End If
row = row + 1
Loop
End With
'''''''''''''''''''
'New code. End of "If KolomControle" block.
End If
'''''''''''''''''''
''''''''''''''''
'New code - end of "If Not FileThere" block.
'Give procedure a single exit point.
End If
End Sub
'Added the worksheet as an argument to the procedure.
'This is then passed from the main procedure and you don't need to select the sheet first.
Function naamOpmaken(wrkSht As Worksheet) As String
Dim rng As Range
Dim row As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
'''''''''''''''''''
'New code
Dim naam As String
Dim ldg As String
Dim cid As String
'''''''''''''''''''
iRijnummer = rng.row
If iRijnummer > 1 Then
' naam = Cells(iRijnummer, iKolomnrNaam).Text
' ldg = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
' cid = Cells(iRijnummer, iKolomnrCorpID).Text
'''''''''''''''''''
'New code - not reference to the worksheet, and using default value of cell.
' may need to add "FORMAT" to get numericals in correct format.
naam = wrkSht.Cells(iRijnummer, iKolomnrNaam)
ldg = wrkSht.Cells(iRijnummer, iKolomnrHuidigeLeidingGevende)
cid = wrkSht.Cells(iRijnummer, iKolomnrCorpID)
'''''''''''''''''''
Dim Position As Long, Length As Long
Dim n As String
Position = InStrRev(naam, " ")
Length = Len(naam)
n = Right(naam, Length - Position)
End If
'If n and ldg are numbers this will add them rather than stick them together.
' naamOpmaken = n + "-" + ldg + "-" + cid
''''''''''''''''
'New code
naamOpmaken = n & "-" & ldg & "-" & cid
''''''''''''''''
End Function
'New function to find last cell containing data on sheet.
Public Function LastCell(wrkSht As Worksheet) As Range
Dim lLastCol As Long, lLastRow As Long
On Error Resume Next
With wrkSht
lLastCol = .Cells.Find("*", , , , xlByColumns, xlPrevious).Column
lLastRow = .Cells.Find("*", , , , xlByRows, xlPrevious).row
If lLastCol = 0 Then lLastCol = 1
If lLastRow = 0 Then lLastRow = 1
Set LastCell = wrkSht.Cells(lLastRow, lLastCol)
End With
On Error GoTo 0
End Function
I'm working with some legacy code I'd like to build on and I can't seem to figure out the following: Why does the function AantalZichtbareRows return 1? Where It says For Each row In rng.Rows the row count is 1500 something (and so is the actual excel I'm working with).
I'm specifically puzzeled by n = r.Areas.Count. This is where the 1 originates.
Sub motivatieFormOpmaken()
Public iLaatsteKolom As Integer
Public iLaatsteRij As Integer
Public iKolomnrCorpID As Integer
Public iKolomnrNaam As Integer
Public iKolomnrHuidigeFunctie As Integer
Const StBestand = "Stambestand.xlsm"
Const motivatie = "Template motivatieformulier opstapregeling.xlsx"
Dim wbMotivTemp As Workbook
Dim wsMotiv As Worksheet
Dim PathOnly, mot, FileOnly As String
Dim StrPadSourcenaam As String
Set wbMotivTemp = ThisWorkbook
Set wsMotiv = ActiveSheet
StrHoofdDocument = ActiveWorkbook.Name
StrPadHoofdDocument = ActiveWorkbook.Path
StrPadSourcenaam = StrPadHoofdDocument & "\" & c_SourceDump
If Not FileThere(StrPadSourcenaam) Then
MsgBox "Document " & StrPadSourcenaam & " is niet gevonden."
Exit Sub
End If
Application.ScreenUpdating = False
Workbooks.Open FileName:=StrPadSourcenaam
Application.Run "Stambestand.xlsm!unhiderowsandcolumns"
Worksheets("stambestand").Activate
iLaatsteKolom = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).Column
iLaatsteRij = Worksheets("stambestand").Cells.SpecialCells(xlLastCell).row
VulKolomNr
If KolomControle = False Then Exit Sub
Aantalregels = AantalZichtbareRows
Dim rng As Range
Dim row As Range
Dim StrFileName As String
'If Aantalregels > 1 Then
Set rng = Selection.SpecialCells(xlCellTypeVisible)
For Each row In rng.Rows
iRijnummer = row.row
If iRijnummer > 1 Then
wsMotiv.Range("motiv_cid") = Cells(iRijnummer, iKolomnrCorpID).Text
wsMotiv.Range("motiv_naam") = Cells(iRijnummer, iKolomnrNaam).Text
wsMotiv.Range("motiv_ldg") = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
n = naamOpmaken
wbMotivTemp.Activate
ActiveWorkbook.SaveAs FileName:=StrPadHoofdDocument & "\Docs\" & n & ".xlsm", FileFormat:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End If
Next row
End Sub
Function naamOpmaken() As String
Dim rng As Range
Dim row As Range
Set rng = Selection.SpecialCells(xlCellTypeVisible)
iRijnummer = rng.row
If iRijnummer > 1 Then
naam = Cells(iRijnummer, iKolomnrNaam).Text
ldg = Cells(iRijnummer, iKolomnrHuidigeLeidingGevende).Text
cid = Cells(iRijnummer, iKolomnrCorpID).Text
Dim Position As Long, Length As Long
Dim n As String
Position = InStrRev(naam, " ")
Length = Len(naam)
n = Right(naam, Length - Position)
End If
naamOpmaken = n + "-" + ldg + "-" + cid
End Function
Public Function AantalZichtbareRows() As Integer
Dim rwCt As Long
Dim r As Range
Dim n As Long
Dim I As Long
Set r = Selection.SpecialCells(xlCellTypeVisible)
n = r.Areas.Count
For I = 1 To n
rwCt = rwCt + r.Areas(I).Rows.Count
Next I
AantalZichtbareRows = rwCt
End Function
Range.areas specifies the number of selection areas. Range.Areas
I tested your code and it works as expected. You can have a single selection area containing 1500 rows. Example: "A1:A1500" Or you can have a selection containing 2 areas with three rows each for a total of 6 rows. Example: "A1:A3" and "C4:C6".
This code might help you understand how the method returns information about the selected cells.
Public Function AantalZichtbareRows() As Integer
Dim rwCt As Long
Dim rwCt2 As Long
Dim r As Range
Dim n As Long
Dim I As Long
Set r = Selection.SpecialCells(xlCellTypeVisible)
n = r.Areas.Count
For I = 1 To n
rwCt = rwCt + r.Areas(I).Rows.Count
Next I
Set r = Selection
n = r.Areas.Count
For I = 1 To n
rwCt2 = rwCt2 + r.Areas(I).Rows.Count
Next I
Debug.Print n & " areas selected."
Debug.Print rwCt2 & " rows selected."
Debug.Print rwCt & " visible rows selected."
Debug.Print (rwCt2 - rwCt) & " hidden rows selected."
AantalZichtbareRows = rwCt
End Function
How to put these lines into a single line ?
1,2,3,4......26
B2,C2,D2,.......Z2
Sheets("1").Range("B2:B300").Copy Sheets("Result").Range("B2")
Sheets("2").Range("B2:B300").Copy Sheets("Result").Range("C2")
Sheets("3").Range("B2:B300").Copy Sheets("Result").Range("D2")
Sheets("4").Range("B2:B300").Copy Sheets("Result").Range("E2")
Sheets("5").Range("B2:B300").Copy Sheets("Result").Range("F2")
.
.
.
Sheets("25").Range("B2:B300").Copy Sheets("Result").Range("Y2")
Sheets("26").Range("B2:B300").Copy Sheets("Result").Range("Z2")
Do a for loop:
For x = 1 to 26
Sheets(Cstr(x)).Range("B2:B300").Copy Sheets("Result").Cells(2,x+1)
next x
I think the following method helps to you
Sub GetCopyOfColumnB()
Dim ws As Worksheet
Dim resultPageName As String
Dim isTherePage As Boolean
Dim i As Integer
resultPageName = "Result"
isTherePage = False
For Each ws In ActiveWorkbook.Sheets
If ws.Name = resultPageName Then
isTherePage = True
End If
Next
If isTherePage = False Then
Worksheets.Add After:=Sheets(ActiveWorkbook.Sheets.Count)
Worksheets(Worksheets.Count).Name = resultPageName
End If
i = 1
For Each ws In ActiveWorkbook.Sheets
If ws.Name <> resultPageName Then
ws.Range("B2:B300").Copy Sheets("Result").Cells(2, i)
i = i + 1
End If
Next
End Sub
A lot of the below code is duplicated for each cell I'm pasting to a new worksheet.
As an educational exercise, can anyone show me how I might shorten it?
Sub RowForTracker()
Worksheets.Add(After:=Worksheets(1)).Name = "ForTracker"
Sheets("Summary").Range("C2").Copy
Sheets("ForTracker").Range("A1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("C6").Copy
Sheets("ForTracker").Range("B1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("C8").Copy
Sheets("ForTracker").Range("C1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("C3").Copy
Sheets("ForTracker").Range("D1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("H8").Copy
Sheets("ForTracker").Range("E1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("H9").Copy
Sheets("ForTracker").Range("F1").PasteSpecial Paste:=xlPasteValues
Sheets("Summary").Range("C5").Copy
Sheets("ForTracker").Range("G1").PasteSpecial Paste:=xlPasteValues
End Sub
another additional examples how you can achieve CopyPaste
Sub test1()
Dim S As Worksheet: Set S = Sheets("Summary")
Dim T As Worksheet: Set T = Sheets("ForTracker")
With T
.[A1] = S.[C2]
.[B1] = S.[C6]
.[C1] = S.[C8]
.[D1] = S.[C3]
.[E1] = S.[H8]
.[F1] = S.[H9]
.[G1] = S.[C5]
End With
End Sub
variant using array
Sub test2()
Dim S As Worksheet: Set S = Sheets("Summary")
Dim T As Worksheet: Set T = Sheets("ForTracker")
Dim CopyPaste, x%
x = 0
With S
CopyPaste = Array(.[C2], .[C6], .[C8], .[C3], .[H8], .[H9], .[C5])
End With
For Each oCell In T.[A1:G1]
oCell.Value = CopyPaste(x): x = x + 1
Next
End Sub
variant using split string
Sub test3()
Dim S As Worksheet: Set S = Sheets("Summary")
Dim T As Worksheet: Set T = Sheets("ForTracker")
Dim CopyPaste$
With S
CopyPaste = .[C2] & "|" & .[C6] & "|" & .[C8] & "|" & .[C3] & "|" & .[H8] & "|" & .[H9] & "|" & .[C5]
End With
T.[A1:G1] = Split(CopyPaste, "|")
End Sub
variant using dictionary
Sub test4()
Dim S As Worksheet: Set S = Sheets("Summary")
Dim T As Worksheet: Set T = Sheets("ForTracker")
Dim CopyPaste As Object: Set CopyPaste = CreateObject("Scripting.Dictionary")
Dim oCell As Range, Key As Variant, x%
x = 1
For Each oCell In S.[C2,C6,C8,C3,H8,H9,C5]
CopyPaste.Add x, oCell.Value: x = x + 1
Next
x = 0
For Each Key In CopyPaste
T.[A1].Offset(, x).Value = CopyPaste(Key)
x = x + 1
Next
End Sub
Well, if you want to just simplify it, you can do this:
Sub Main()
Dim wsS As Worksheet
Dim wsT As Worksheet
Set wsS = Sheets("Summary")
Set wsT = Sheets("ForTracker")
wsT.Range("A1").Value = wsS.Range("C2").Value
wsT.Range("B1").Value = wsS.Range("C6").Value
wsT.Range("C1").Value = wsS.Range("C8").Value
wsT.Range("D1").Value = wsS.Range("C3").Value
wsT.Range("E1").Value = wsS.Range("H8").Value
wsT.Range("F1").Value = wsS.Range("H9").Value
wsT.Range("G1").Value = wsS.Range("C5").Value
End Sub
It may not be necessary this time, but as you said, you wished for an educational excersise, you could create a procedure just for copying cell values from one to another. It could look like this:
Sub CopyValue(CopyFrom As Range, PasteTo As Range)
PasteTo.Value = CopyFrom.Value
End Sub
And you would call it like this:
CopyValue wsS.Range("C2"), wsT.Range("A1")
Or alternativelly, if you wanted to be extra clear, like this:
CopyValue CopyFrom:=wsS.Range("C2"), PasteTo:=wsT.Range("A1")
One way
Dim target As Range, item As Range, i As Long
With Worksheets.Add(After:=Worksheets(1))
.Name = "ForTracker"
Set target = .Range("A1")
End With
For Each item In Sheets("summary").Range("C2,C6,C8,C3,H8,H9,C5")
target.Offset(0, i).value = item.value
i = i + 1
Next
Try this:
Sub RowForTracker()
Dim wksSummary As Worksheet
Dim wksForTracker As Worksheet
Worksheets.Add(After:=Worksheets(1)).Name = "ForTracker"
Set wksSummary = Sheets("Summary")
Set wksForTracker = Sheets("ForTracker")
With wksForTracker
.Range("A1").Value = wksSummary.Range("C2").Value
.Range("B1").Value = wksSummary.Range("C6").Value
.Range("C1").Value = wksSummary.Range("C8").Value
.Range("D1").Value = wksSummary.Range("C3").Value
.Range("E1").Value = wksSummary.Range("H8").Value
.Range("F1").Value = wksSummary.Range("H9").Value
.Range("G1").Value = wksSummary.Range("C5").Value
End With
End Sub
I currently have a spreadsheet that parses a HL7 message string using "|" as a delimiter. The String that comes before the first "|" becomes the sheet name (Segment). The code executes on each line of the string (Each segment is parsed). The problem is that sometimes there are multiple segments with the same name. So instead of a new sheet being created, all segments are lumped into the same sheet with that name. What I am trying to do is have the code create a new sheet for each segment and if there it is already present, add sheet name with an incremented number.
Sample Message:
MSH|^~\&|SR|500|CL|500|20140804150856-0500||SIU^S14|5009310|P|2.3|||AL|NE|USA
SCH|10262|10262|""|S14^(SCHEDULED)^L|44950^APPENDECTOMY^C4||^^^201408081345-0500^^^^^^2||30|MIN^MINUTES|^^^201408081345-0500^201408081415-0500|10000000034^ROISTAFF^CHIEF^O||||||||
PID|1|5000|50^^^USVHA&&0363^NI^FACILITY ID&500&L^^20140804~666^^^USSSA&&0363^SS^FACILITY ID&500&L~^^^USDOD&&0363^TIN^VA FACILITY ID&500&L~^^^USDOD&&0363^FI^FACILITY ID&500&L~736^^^USVHA&&0363^PI^VA FACILITY ID&500&L|736|DATA^PATIENT^^^^^L||19540214|M|||123 main Street^^SW RS^FL^33332^USA^P^^~^^^^^^N|||||||4221^764|666|||||N||||||N||
PV1|1|I|||||||||||||||||||||||||||||||||||||500|
OBX|1|CE|^SPECIALTY^||^GENERAL||||||S|||||
OBX|2|CE|^PATIENT CLASS^||^INPATIENT^L||||||S|||||
DG1|1|I9|540.1|ABSCESS OF APPENDIX||P
DG1|2|I9||APPENDICITIS||PR
RGS|1|A|
AIS|1|A|44950^APPENDECTOMY^C4||||
AIP|1|A|1000^PHYSICIAN^KT^|^SURGEON^99||||PENDING
AIP|2|A|1000^NURSE^ONE^|^1ST ASST.^99||||PENDING
AIP|3|A|1000^NURSE^TWO^|^2ND ASST.^99||||PENDING
AIP|4|A|1000^ATTENDING^ONE^|^ATT. SURGEON^99||||PENDING
AIP|5|A|115^DATA^PROVIDERONE^|^PRIN. ANES.^99||||PENDING
AIP|6|A|1000^DATA^PATHOLOGIST^|^ANES. SUPER.^||||PENDING
AIL||500^^^OR1|^OPERATING ROOM||||PENDING
Option Explicit
Const HL7_DELIMITER_FIELD = "|"
Const HL7_DELIMITER_SEGMENT = vbLf
Sub DoHL7Parsing(sMessage As String)
Dim vSegments As Variant, vCurSeg As Variant
Dim vFields As Variant, rCurField As Range, iIter As Integer
Dim wsSeg As Worksheet
vSegments = VBA.Split(sMessage, HL7_DELIMITER_SEGMENT)
For Each vCurSeg In vSegments
vFields = VBA.Split(vCurSeg, HL7_DELIMITER_FIELD)
If WorksheetExists(vFields(0), ThisWorkbook) Then
On Error Resume Next
For iIter = 1 To UBound(vFields)
Set rCurField = ThisWorkbook.Worksheets(vFields(0)).Range("A65536").End(xlUp).Offset(1, 0)
rCurField.Value = vFields(0)
rCurField.Offset(0, 1).Value = (rCurField.Row - 1)
rCurField.Offset(0, 2).NumberFormat = "#"
rCurField.Offset(0, 2).Value = vFields(iIter)
Next iIter
On Error Resume Next
ElseIf Not WorksheetExists(vFields(0), ThisWorkbook) Then
Worksheets.Add(After:=Worksheets(Worksheets.Count)).Name = vFields(0)
For iIter = 1 To UBound(vFields)
Set rCurField = ThisWorkbook.Worksheets(vFields(0)).Range("A65536").End(xlUp).Offset(1, 0)
rCurField.Value = vFields(0)
rCurField.Offset(0, 1).Value = (rCurField.Row - 1)
rCurField.Offset(0, 2).NumberFormat = "#"
rCurField.Offset(0, 2).Value = vFields(iIter)
Next iIter
'MsgBox "Invalid or unkown segment: " & vFields(0)
End If
Next vCurSeg
On Error Resume Next
End Sub
Public Function WorksheetExists(ByVal WorksheetName As String, Optional InWorkbook As Workbook) As Boolean
Dim Sht As Worksheet
WorksheetExists = False
If Not InWorkbook Is Nothing Then
For Each Sht In InWorkbook.Worksheets
If Sht.Name = WorksheetName Then WorksheetExists = True
Next Sht
Else
For Each Sht In ActiveWorkbook.Worksheets
If Sht.Name = WorksheetName Then WorksheetExists = True
Next Sht
End If
On Error Resume Next
End Function
The trick here is to just count the number of sheets whose Left(ShtName,3) value is equal to vFields(0). Based on the count, add 1 and append to end of vField(0). With this approach, you don't even need the dirty On Error Resume Next because you won't be targeting the same sheet twice, which can bring down your line count considerably.
For the sheet counting, add the following function to your module:
Function CountSheetsWithName(ShtName As String) As Long
Dim WS As Worksheet, Res As Long
Res = 0
For Each WS In ThisWorkbook.Worksheets
If Left(WS.Name, 3) = ShtName Then
Res = Res + 1
End If
Next
CountSheetsWithName = Res
End Function
Update your DoHL7Parsing subroutine as follows:
Sub DoHL7Parsing(sMessage As String)
Dim vSegments As Variant, vCurSeg As Variant
Dim vFields As Variant, rCurField As Range, iIter As Integer
Dim wsSeg As Worksheet, sShtName As String
vSegments = VBA.Split(sMessage, HL7_DELIMITER_SEGMENT)
Application.ScreenUpdating = False
For Each vCurSeg In vSegments
vFields = VBA.Split(vCurSeg, HL7_DELIMITER_FIELD)
For iIter = 1 To UBound(vFields)
sShtName = vFields(0) & (CountSheetsWithName(CStr(vFields(0))) + 1) ' Append the count + 1 to end of name.
Sheets.Add(After:=Sheets(Sheets.Count)).Name = sShtName
Set rCurField = ThisWorkbook.Worksheets(sShtName).Range("A" & Rows.Count).End(xlUp).Offset(1, 0)
rCurField.Value = vFields(0)
rCurField.Offset(0, 1).Value = (rCurField.Row - 1)
rCurField.Offset(0, 2).NumberFormat = "#"
rCurField.Offset(0, 2).Value = vFields(iIter)
Next iIter
Next vCurSeg
Application.ScreenUpdating = True
End Sub
Result:
Hope this helps.