• Hi All

    Please note that at the Chandoo.org Forums there is Zero Tolerance to Spam

    Post Spam and you Will Be Deleted as a User

    Hui...

  • When starting a new post, to receive a quicker and more targeted answer, Please include a sample file in the initial post.

Macro that after sorting, will copy entire rows to separate sheets in workbook

HollyOsburn

New Member
Hello -


I am trying to find a method that will allow my users to import a text file into Excel, then copy rows to corresponding sheets within a template workbook based on the value found in column A. This is related to HL7 validation, and it works very well when the users manually filter and copy/paste. What I'm hoping to do is cut down on the manual steps for them. I'm attaching a sample of the manual workbook (this is NOT real data, no actual personal information, health info, etc.) to hopefully make it clear what I am attempting to automate. I've tried following the example spreadsheets from here on how to copy from one sheet to another and I'm not quite getting it. Here are the basic steps manually performed now:


1. File to be analyzed (.txt) is imported onto the SampleADTFile tab.

2. Entire sheet is filtered.

3. User selects a single value in column A (MSH, PID, PV1, IN1, DG1)

4. All rows with that value are displayed, so user copies all these rows and pastes to the corresponding Tab in the workbook, using Paste Special, Values and Number format.


I've tried just recording a Macro, but I can't figure out how to take that recorded macro and adjust to work.


Anyone feel like helping me out with this? It will be very much appreciated.


Thank you,


Holly


https://www.dropbox.com/s/4pwk1gd3bm8od9l/Analysis_Workbook.xlsx


and in case that doesn't work, here in my "shared" folder too.


https://www.dropbox.com/s/gy1xavii0yk1lam/Analysis_Workbook.xlsx
 
Hi, HollyOsburn!


I have a few doubts, let me see if you could make me get rid of them:

a) In 1) you referred to SampleADTFile tab but in the uploaded workbook it seems to be "Sample Data"?

b) The text file is yet imported in that worksheet or it should be opened from a file?

c) It should be filtered in any way?

d) Data should be added to existing in worksheets MSH, PID, PV1, DG1, IN1, or previous should be cleared first?

e) In "Sample Data" worksheet, for each header group MSH there will be only none one entry of MSH, PID, PV1, DG1, IN1, or might be more than one?

f) Anything to do with worksheet "ADT Sample Analysis"?


Regards!


PS: Uploaded file available at first link without any trouble.
 
Huge apologies for giving such a bad example!


A. In the sample workbook, the tab is "Sample Data"

B. This workbook has the text already imported. The user manually imports into this tab in the current process.

C. The way the text files exist, the first column will always denote the HL7 type of row such as MSH, PID, PV1, etc. Any values other than those listed on the tabs in the example should be ignored, as would blank rows.

D. Currently we only load one file at a time to a workbook, so the first time the text file is imported, there would be no values on the MSH, PID, PV1 etc. tabs. If we re-import using the same template, then yes, the original values should be cleared off the destination tabs.

E. There usually will be many rows for MSH, PID, ETC.

F. The ADT Sample Analysis is where the user today manually discusses any issues with the data. Ideally I will figure out a way to populate that sheet eventually! My hope is to look to the type of ADT message (Found on the MSH tab) and as long as there is a single value or more of each type A01-A10, to check the box, but this is far down the road. If I can just get these to copy over for the users, they will be delighted, as will I.
 
I think I'm getting closer to figuring out how to load the file. I have found an example of how to provide a file import dialog box and I'm working on that part right now. :)
 
Hi, HollyOsburn!


Give a look at this file:

https://dl.dropboxusercontent.com/u/60558749/Macro%20that%20after%20sorting%2C%20will%20copy%20entire%20rows%20to%20separate%20sheets%20in%20workbook%20-Analysis_Workbook%20%28for%20HollyOsburn%20at%20chandoo.org%29.xlsm

This is the code in module Módulo1 called by clicking on cyan button in worksheet "Sample Data":

-----

Option Explicit

Sub FillTabs()
'
' constants
' worksheets & ranges
' SD
Const ksWSSampleData = "Sample Data"
Const kiTitleSD = 0
Const ksTypeMSH = "MSH"
Const ksTypePID = "PID"
Const ksTypePV1 = "PV1"
Const ksTypeDG1 = "DG1"
Const ksTypeIN1 = "IN1"
' MSH
Const ksWSMSH = "MSH"
Const ksMSH = "MSHTable"
Const kiTitleMSH = 3
' PID
Const ksWSPID = "PID"
Const ksPID = "PIDTable"
Const kiTitlePID = 3
' PV1
Const ksWSPV1 = "PV1"
Const ksPV1 = "PV1Table"
Const kiTitlePV1 = 3
' DG1
Const ksWSDG1 = "DG1"
Const ksDG1 = "DG1Table"
Const kiTitleDG1 = 3
' IN1
Const ksWSIN1 = "IN1"
Const ksIN1 = "IN1Table"
Const kiTitleIN1 = 3
'
' declarations
Dim rngSD As Range
Dim rngMSH As Range, rngPID As Range, rngPV1 As Range, rngDG1 As Range, rngIN1 As Range
Dim lSD As Long, lMSH As Long, lPID As Long, lPV1 As Long, lDG1 As Long, lIN1 As Long
Dim sType As String
'
' start
' application
With Application
.DisplayAlerts = False
.ScreenUpdating = False
End With
' ranges
Set rngSD = Worksheets(ksWSSampleData).Cells
Set rngMSH = Worksheets(ksWSMSH).Range(ksMSH)
Set rngPID = Worksheets(ksWSPID).Range(ksPID)
Set rngPV1 = Worksheets(ksWSPV1).Range(ksPV1)
Set rngDG1 = Worksheets(ksWSDG1).Range(ksDG1)
Set rngIN1 = Worksheets(ksWSIN1).Range(ksIN1)
' clear
With rngMSH
If .Rows.Count > kiTitleMSH Then Range(.Rows(kiTitleMSH + 1), .Rows(.Rows.Count)).ClearContents
lMSH = kiTitleMSH
End With
With rngPID
If .Rows.Count > kiTitlePID Then Range(.Rows(kiTitlePID + 1), .Rows(.Rows.Count)).ClearContents
lPID = kiTitlePID
End With
With rngPV1
If .Rows.Count > kiTitlePV1 Then Range(.Rows(kiTitlePV1 + 1), .Rows(.Rows.Count)).ClearContents
lPV1 = kiTitlePV1
End With
With rngDG1
If .Rows.Count > kiTitleDG1 Then Range(.Rows(kiTitleDG1 + 1), .Rows(.Rows.Count)).ClearContents
lDG1 = kiTitleDG1
End With
With rngIN1
If .Rows.Count > kiTitleIN1 Then Range(.Rows(kiTitleIN1 + 1), .Rows(.Rows.Count)).ClearContents
lIN1 = kiTitleIN1
End With
lSD = 1
'
' process
With rngSD
Do Until .Cells(lSD, 1).Value = "" And .Cells(lSD + 1, 1).Value = ""
' type
sType = .Cells(lSD, 1).Value
' distribute
Select Case sType
Case ksTypeMSH
lMSH = lMSH + 1
.Rows(lSD).Copy
rngMSH.Rows(lMSH).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypePID
lPID = lPID + 1
.Rows(lSD).Copy
rngPID.Rows(lPID).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypeDG1
lDG1 = lDG1 + 1
.Rows(lSD).Copy
rngDG1.Rows(lDG1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypePV1
lPV1 = lPV1 + 1
.Rows(lSD).Copy
rngPV1.Rows(lPV1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypeIN1
lIN1 = lIN1 + 1
.Rows(lSD).Copy
rngIN1.Rows(lIN1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ""
Case Else
MsgBox "Invalid type identifier <" & sType & "> at row " & _
lSD + kiTitleSD, vbApplicationModal + vbExclamation + vbOKOnly, _
"Warning"
End Select
' cycle
lSD = lSD + 1
Loop
End With
'
' end
' ranges
Set rngIN1 = Nothing
Set rngDG1 = Nothing
Set rngPV1 = Nothing
Set rngPID = Nothing
Set rngMSH = Nothing
Set rngSD = Nothing
' application
With Application
.CutCopyMode = False
.DisplayAlerts = True
.ScreenUpdating = True
End With
' beep
Beep
'
End Sub

-----


Just advise if any issue.


Regards!


PS: I didn't understand F., if need anything about it please elaborate a bit more and provide an example.
 
This is beautiful! I think that I have seen a setting described where it can hide the actions going on with the copies (no screen blinking)? But it does exactly what I need it to do. I have also added a button to let the user select the text file to bring to the Sample Data tab. Here is how I did that:

[pre]
Code:
Sub ImportTextFile()
Dim fName As String

fName = Application.GetOpenFilename("Text Files (*.txt), *.txt")
If fName = "False" Then Exit Sub

With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & fName, _
Destination:=Range("$A$1"))
.Name = "sample"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, _
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
[/pre]
 
Hi, HollyOsburn!


Glad you solved it. Thanks for your feedback and for your kind words too. And welcome back whenever needed or wanted.


Please download again the updated file from same previous link. Code posted earlier updated too. The setting you referred is the Application.ScreenUpdating value.


Regards!
 
Hi, HollyOsburn!


Regarding worksheet "ADT Sample Analysis" you have a lot of shapes there (150 checkboxes and a dropdown), it'd be advisable if you assign them proper names. Here's the command used to retrieve them and their order, name, left and top values:

-----

[pre]
Code:
for i=1 to 51:?i,activesheet.shapes(i).name, activesheet.shapes(i).left, activesheet.shapes(i).top:next i
1            Check Box 101  8,25          166,5
2            Check Box 102  8,25          182,25
3            Check Box 103  8,25          196,5
4            Check Box 104  8,25          213,75
5            Check Box 105  8,25          227,25
6            Check Box 106  8,25          241,5
7            Check Box 107  8,25          256,5
8            Check Box 108  8,25          272,25
9            Check Box 109  8,25          287,25
10           Check Box 110  8,25          301,5
11           Check Box 111  42,75         334,5
12           Check Box 112  6,75          334,5
13           Check Box 113  113,25        334,5
14           Check Box 114  77,25         334,5
15           Check Box 115  42,75         349,5
16           Check Box 116  6,75          349,5
17           Check Box 117  113,25        349,5
18           Check Box 118  77,25         349,5
19           Check Box 119  42,75         364,5
20           Check Box 120  6,75          364,5
21           Check Box 121  113,25        364,5
22           Check Box 122  77,25         364,5
23           Check Box 123  42,75         379,5
24           Check Box 124  6,75          379,5
25           Check Box 125  113,25        379,5
26           Check Box 126  77,25         379,5
27           Check Box 127  42,75         394,5
28           Check Box 128  6,75          394,5
29           Check Box 129  113,25        394,5
30           Check Box 130  77,25         394,5
31           Check Box 131  180           334,5
32           Check Box 132  144           334,5
33           Check Box 133  250,5         334,5
34           Check Box 134  214,5         334,5
35           Check Box 135  180           349,5
36           Check Box 136  144           349,5
37           Check Box 137  250,5         349,5
38           Check Box 138  214,5         349,5
39           Check Box 139  180           364,5
40           Check Box 140  144           364,5
41           Check Box 141  250,5         364,5
42           Check Box 142  214,5         364,5
43           Check Box 143  180           379,5
44           Check Box 144  144           379,5
45           Check Box 145  250,5         379,5
46           Check Box 146  214,5         379,5
47           Check Box 147  180           394,5
48           Check Box 148  144           394,5
49           Check Box 149  250,5         394,5
50           Check Box 150  214,5         394,5
51           Drop Down 151  0             166,5
[/pre]
-----


Regards!


EDITED


PS: Forget it, I now realize that their names are "Check Box " & 100 + Axx value.
 
Thank you again. One question - Why am I getting "Invalid Type Identifier XXX" (and YYY, ZZZ)? Is there a way to just have it ignore anything other than those values that match the tab names?
 
One additional question please. Below is my code for importing data from a text file. When I run, I want the data to paste beginning in cell A3, but what is happening is that all columns are shifting out to allow for the imported data, including the button that I added for triggering the Macro. How can I stop this? Here is the code I currently have:

[pre]
Code:
Sub ImportTextFile()
Dim fName As String

fName = Application.GetOpenFilename("Text Files (*.txt), *.txt")
If fName = "False" Then Exit Sub

With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & fName, _
Destination:=Range("$A$3"))
.Name = "sample"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlInsertDeleteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, _
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
[/pre]
 
Hi, HollyOsburn!

I added those values to test proper selection of items in column A, just in case the user uploaded any text file. You may see that there's a 'Case XXX' sentence for each valid type, then a 'Case ""' and then a 'Case Else' where the error is displayed. Just remove this last group (or both) or comment it/them.

Regards!
 
Hello! I have added in a second button that will allow the users to load the sample file onto the sample data tab, and it works exactly as I wanted. However, when I went in and added an additional tab "MRG", it no longer functions. I think I updated the code properly, and I've gone blind and insane trying to see the error, but each time I invoke the "FillTabs" macro, it stops at "Set rngMSH = Worksheets(ksWSMSH).Range(ksMSH)

" saying the range was not defined. Could you take a look and see what is the problem with this code? I've done a compare on my "works" code with "doesn't work" code and the only differences are where I have added ranges, lines, tables for MRG.

Again, my sincere thanks for your knowledge transfer on all of this. I'm trying to learn VBA on my own and you have been a huge help to me.

Option Explicit
Sub FillTabs()
'
' constants
' worksheets & ranges
' SD
Const ksWSSampleData = "Sample Data"
Const kiTitleSD = 0
Const ksTypeMSH = "MSH"
Const ksTypePID = "PID"
Const ksTypePV1 = "PV1"
Const ksTypeDG1 = "DG1"
Const ksTypeIN1 = "IN1"
Const ksTypeMRG = "MRG"
' MSH
Const ksWSMSH = "MSH"
Const ksMSH = "MSHTable"
Const kiTitleMSH = 3
' PID
Const ksWSPID = "PID"
Const ksPID = "PIDTable"
Const kiTitlePID = 3
' PV1
Const ksWSPV1 = "PV1"
Const ksPV1 = "PV1Table"
Const kiTitlePV1 = 3
' DG1
Const ksWSDG1 = "DG1"
Const ksDG1 = "DG1Table"
Const kiTitleDG1 = 3
' IN1
Const ksWSIN1 = "IN1"
Const ksIN1 = "IN1Table"
Const kiTitleIN1 = 3
' MRG
Const ksWSMRG = "MRG"
Const ksMRG = "MRGTable"
Const kiTitleMRG = 3
'
' declarations
Dim rngSD As Range
Dim rngMSH As Range, rngPID As Range, rngPV1 As Range, rngDG1 As Range, rngIN1 As Range, rngMRG As Range
Dim lSD As Long, lMSH As Long, lPID As Long, lPV1 As Long, lDG1 As Long, lIN1 As Long, lMRG As Long

Dim sType As String
'
' start
' application
With Application
.DisplayAlerts = False
.ScreenUpdating = False
End With
' ranges
Set rngSD = Worksheets(ksWSSampleData).Cells
Set rngMSH = Worksheets(ksWSMSH).Range(ksMSH)
Set rngPID = Worksheets(ksWSPID).Range(ksPID)
Set rngPV1 = Worksheets(ksWSPV1).Range(ksPV1)
Set rngDG1 = Worksheets(ksWSDG1).Range(ksDG1)
Set rngIN1 = Worksheets(ksWSIN1).Range(ksIN1)
Set rngMRG = Worksheets(ksWSMRG).Range(ksMRG)
' clear
With rngMSH
If .Rows.Count > kiTitleMSH Then Range(.Rows(kiTitleMSH + 1), .Rows(.Rows.Count)).ClearContents
lMSH = kiTitleMSH
End With
With rngPID
If .Rows.Count > kiTitlePID Then Range(.Rows(kiTitlePID + 1), .Rows(.Rows.Count)).ClearContents
lPID = kiTitlePID
End With
With rngPV1
If .Rows.Count > kiTitlePV1 Then Range(.Rows(kiTitlePV1 + 1), .Rows(.Rows.Count)).ClearContents
lPV1 = kiTitlePV1
End With
With rngDG1
If .Rows.Count > kiTitleDG1 Then Range(.Rows(kiTitleDG1 + 1), .Rows(.Rows.Count)).ClearContents
lDG1 = kiTitleDG1
End With
With rngIN1
If .Rows.Count > kiTitleIN1 Then Range(.Rows(kiTitleIN1 + 1), .Rows(.Rows.Count)).ClearContents
lIN1 = kiTitleIN1
End With
With rngMRG
If .Rows.Count > kiTitleMRG Then Range(.Rows(kiTitleMRG + 1), .Rows(.Rows.Count)).ClearContents
lMRG = kiTitleMRG
End With
lSD = 1
'
' process
With rngSD
Do Until .Cells(lSD, 1).Value = "" And .Cells(lSD + 1, 1).Value = ""
' type
sType = .Cells(lSD, 1).Value
' distribute
Select Case sType
Case ksTypeMSH
lMSH = lMSH + 1
.Rows(lSD).Copy
rngMSH.Rows(lMSH).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypePID
lPID = lPID + 1
.Rows(lSD).Copy
rngPID.Rows(lPID).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypeDG1
lDG1 = lDG1 + 1
.Rows(lSD).Copy
rngDG1.Rows(lDG1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypePV1
lPV1 = lPV1 + 1
.Rows(lSD).Copy
rngPV1.Rows(lPV1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypeIN1
lIN1 = lIN1 + 1
.Rows(lSD).Copy
rngIN1.Rows(lIN1).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ksTypeMRG
lMRG = lMRG + 1
.Rows(lSD).Copy
rngMRG.Rows(lMRG).PasteSpecial Paste:=xlPasteValues, _
Operation:=xlNone, skipBlanks:=False, Transpose:=False
Case ""
Case Else
MsgBox "Invalid type identifier <" & sType & "> at row " & _
lSD + kiTitleSD, vbApplicationModal + vbExclamation + vbOKOnly, _
"Warning"
End Select
' cycle
lSD = lSD + 1
Loop
End With
'
' end
' ranges
Set rngMRG = Nothing
Set rngIN1 = Nothing
Set rngDG1 = Nothing
Set rngPV1 = Nothing
Set rngPID = Nothing
Set rngMSH = Nothing
Set rngSD = Nothing
' application
With Application
.CutCopyMode = False
.DisplayAlerts = True
.ScreenUpdating = True
End With
' beep
Beep
'
End Sub
Sub ImportSample()

Dim fName As String

fName = Application.GetOpenFilename("Text Files (*.txt), *.txt")
If fName = "False" Then Exit Sub

With ActiveSheet.QueryTables.Add(Connection:="TEXT;" & fName, _
Destination:=Range("$A$2"))
.Name = "sample"
.FieldNames = True
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.RefreshStyle = xlOverwriteCells
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = False
.RefreshPeriod = 0
.TextFilePromptOnRefresh = False
.TextFilePlatform = 437
.TextFileStartRow = 1
.TextFileParseType = xlDelimited
.TextFileTextQualifier = xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = False
.TextFileTabDelimiter = False
.TextFileSemicolonDelimiter = False
.TextFileCommaDelimiter = False
.TextFileSpaceDelimiter = False
.TextFileOtherDelimiter = "|"
.TextFileColumnDataTypes = Array(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, _
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)
.TextFileTrailingMinusNumbers = True
.Refresh BackgroundQuery:=False
End With
End Sub
 
Hmm. Double check and make sure the MSHTable hasn't change it's name? Might be good to use the Name Manager and make sure everything is still defined the way you think it should be. Code seems to run ok on my machine, so doing a lot of guessing. =(
 
You have been most kind. Can you point me in the direction of a good place to start my VBA education? I am going to go through some of the classes on this site, but do you have any suggestions on the "Best way to learn"? This is all incredibly helpful, and I'm learning so much by trying to just figure my way out of things that DON'T work, but do you have any favorite reference materials etc?
 
Question - I am going to take this same workbook, and I would like to be able select the name for sample data on the ADT_Analysis tab, have the filename display (not the path, just the filename) and then at the same time, have the data in that file import onto the Sample Data tab.


Instead of giving me code on how to do this, could you give me a 'hint' on what I need to do? For example - I'm thinking that the macro that I trigger now to load the file, actually goes out and when I select the filename, it uses "TEXT" to create a link to a new Excel Query and pastes it also into the Import dialog box. So, I think I might be able to also use that "TEXT" reference to populate the value in the ADT_Analysis Filename box.


I'm going to try to get that piece working.
 
Hi, HollyOsburn!

If you decide to take the next step and fill the ADT Analysis worksheet checkbox controls I strongly recommend you to change all form controls by ActiveX controls. That'll make your life much easier.

Regards!

PS: After the KeyMaster wrote this:

http://chandoo.org/forums/topic/best-books-on-excel-vba#post-35043

... what could we, simple mortals, say?
 
Back
Top