Please can anyone help me !!!!
I have this function that calls data from an external excel workbook and places the value into the application under test, I need it to loop through all the values in the excel sheet row by row
Below is the link to the framework and the function I am trying to use and need it to loop through the values in the excel sheet. PLS HELP.
MANY THANKS
http://www.automationrepository.com/2013/08/designing-hybrid-framework-in-qtp-part-3/
'================================================================================
'Function name - fnFetchDataFromExcelSheet
'Description - This function retrieves the data from the excel sheet based upon the column name
'================================================================================
Function fnFetchDataFromExcelSheet(strColumnName)
Dim sColValue
'Initialize the return the value to "empty" string
fnFetchDataFromExcelSheet = "empty"
'Add a new blank sheet into the QTP data table
'Excel data will be copied into this blank sheet
DataTable.AddSheet("dtDataSheet")
'Import the data from the excel sheet into the QTP data table
DataTable.ImportSheet sExcelWorkbookPath, sSheetName, "dtDataSheet"
'Find the value from the data table
sColValue = DataTable.Value(strColumnName, "dtDataSheet")
'Return the value back to the calling function
fnFetchDataFromExcelSheet = sColValue
'Remove Reference
DataTable.DeleteSheet("dtDataSheet")
End Function
This function you have posted from a site is not correct logically!
First, You need to pass both sSheetName & strColumnName to the function.
Even if we ignore that it is a miss by mistake Or Assume that sSheetName is a global variable (so need to pass this to function), For each and every call to this function, It imports a sheet to the datatable, gets the value in the first row for the given cell and agains delete it(!!!). It would affect the performance very badly. You will also get the same value everytime!!
I would say, Ignore the function. Follow these steps.
1) First you need to import the excel into your datatable.
DataTable.ImportSheet /path/to/excel, /name/of/the/sheet, "dtDataSheet"
/path/to/excel & /name/of/the/sheet should be in " "
2) get the Row count
intRowcount=DataTable.GetSheet("dtDataSheet").RowCount
3) Use a simple For loop
For iLoop = 1 To intRowcount
DataTable.GetSheet("dtDataSheet").SetCurrentRow iLoop
Msgbox DataTable.value("ColumnName","dtDataSheet") 'Replace the msgbox with what you want
Next
Related
I am trying to create a dynamic autofilter in excel which could be applied across all the sheets (total: 5) in the excel based on what filter the user selects in 1st sheet.
For Example: I have 5 sheets in an excel all with different columns and 1 "primary key" column.
Sheet1 = Headers - PK, Col1, Col2 ...
Sheet2 = Headers - PK, Col6, Col7 ...
.
.
Sheet5 = Headers - PK, Col20, Col21 ...
The filter should work like, the user creates a filter on the column headers on sheet1 via selecting the header and then Home > Sort & Filter. Once we have filters on header, the user can then selects multiple values (check boxes) on the 1st column (PK) and now wants that filter to be applied across all sheets on the PK column.
I was able to create an autofilter but it is actually static and does not change based on user input.
Version: MS OFfice Excel 2010
VB Macro:
Sub apply_autofilter_across_worksheets()
Dim xWs As Worksheet
On Error Resume Next
For Each xWs In Worksheets
xWs.Range("A1").AutoFilter 1, "=Sheet1!$A$1"
Next
End Sub
I am relatively new to excel. In this case, the column I am filtering on, on the first sheet is a number, so the array I am trying to use in the criteria seems to be a text.
Not exactly the solution I was looking for but I think I can get the end-user work with this setup. I ended up creating a separate sheet altogether which would be used as a reference filter. To populate the data in this sheet, the user can copy whatever data he need from sheet1 to filter upon for example - first 5 records he want to filter upon.
Populate the REFERENCE sheet with the data he needs to filter upon.
Pre-Created, dynamic named range. In this case - Critlist
Run the macros below and filter on all sheets.
Note: In this case, I puposefully used the 2nd column ($B) from the REFERENCE sheet to create this dynamic list since my filter will loop through all the sheets and filter on 1st column. Once it reaches the reference sheet, it wont find the 1st column and so can exit cleanly.
I used the reference below to help on this situation. Couple of lessons learned -
1. The array used in the link is myarray which works fine for their use case as per the sample file, but I had to use myarray(i, 1) when I was looping though it - Reference #3. Not sure why would it need two-dimensional array to work.
2. The array created in Reference #1 is Range of values - sheet.Range("").Value whereas in my case I created an array as sheet.Range("") i.e. without the value.
VB Macros:
Option Explicit
Public Sub apply_autofilter_across_worksheets()
Dim myarray As Variant, xWs As Worksheet, wsL As Worksheet, i As Long
Set wsL = Worksheets("REFERENCE")
myarray = wsL.Range("CritList")
For i = LBound(myarray, 1) To UBound(myarray, 1)
myarray(i, 1) = CStr(myarray(i, 1))
Next
For Each xWs In Worksheets
xWs.Range("$A$1").AutoFilter _
Field:=1, _
Criteria1:=Application.WorksheetFunction.Transpose(myarray), _
Operator:=xlFilterValues
Next
End Sub
EDIT:
I think I have found a better way doing it even without creating an additional sheet (the way I was hoping to do ideally). It is the same concepts with creating the same list, however in this case, instead of creating it separately, I created it on the 1st sheet I want to drive the selection/filtering from. Then by using .SpecialCells(xlCellTypeVisible).EntireRow we can only select what is visible on the sheet i.e. the filtered criteria and then apply it to the remaining sheets in the loop. In this case, even if it overwrites the 1st sheet, it should not be a problem since it is already filtered the way we want. This should also be repeatable since every time the reference list changes, it should dynamically update the rest of the filters by running the macros.
VB Code:
Option Explicit
Public Sub Filter_RFX()
Dim myarray As Variant, xWs As Worksheet, wsL As Worksheet, i As Long
Set wsL = Worksheets("Sheet1")
myarray = wsL.Range("CritList").SpecialCells(xlCellTypeVisible).EntireRow
For i = LBound(myarray, 1) To UBound(myarray, 1)
myarray(i, 1) = CStr(myarray(i, 1))
Next
For Each xWs In Worksheets
xWs.Range("$A$1").AutoFilter _
Field:=1, _
Criteria1:=Application.WorksheetFunction.Transpose(myarray), _
Operator:=xlFilterValues
Next
End Sub
Reference:
1. http://www.contextures.com/xlNames01.html#videodynamic
http://blog.contextures.com/archives/2010/12/15/excel-autofilter-with-criteria-in-a-range/
http://www.java2s.com/Code/VBA-Excel-Access-Word/Data-Type/UseLBoundandUBoundinforstatement.htm
I have a huge spreadsheet of bird species sighting data, each column name is the name of a species and each row in column A is a number associated with a geographical location where the species count was taken. so each cell under each species is a count of how many times it was seen at its respective location.
What I want is a function that will give me a list of column names that had values >0 at that location. Everything I've found has shown me how to find the first value >0 but I want a list that could contain like 50 species names.
The idea at the end is that for each geographical point I just have a list of species that have been seen there. I'm assuming the function would start with INDEX from what I've read but not sure how to proceed.
If VBA is the only way forward, that's fine but I am very new to it so suggestions on what would accomplish this would be welcome.
As #Jeeped gave in the comment above, here is the answer adapted to your situation, from his post of the linked answer.
Since you are handling 50 columns, the handling is creating a VBA User Defined Function.
This is how you create one:
Press Alt+F11.
When the VBE opens, in the menus select Insert ► Module (Alt+I,M).
Paste the following into the window.
Public Function conditional_concat(rSTRs As Range, rCRITs As Range, Optional sDELIM As String = ", ")
Dim c As Long, sTMP As String
For c = 1 To Application.Min(rSTRs.Cells.Count, rCRITs.Cells.Count)
If CBool(rCRITs(c).Value2) Then _
sTMP = sTMP & rSTRs(c).Value & sDELIM
Next c
conditional_concat = Left(sTMP, Application.Max(Len(sTMP) - Len(sDELIM), 0))
End Function
Save the workbook.
Now you can use this function in the formula for the cells on your worksheet.
In your case, add the following into the second row in the "species found" column (BB is being your last column of species):
=conditional_concat(A$1:BB$1, A2:BB2)
Then you can copy-paste this on the rest of the rows.
Consider this User Defined Function:
Public Function Headerr(rIN As Range) As String
Dim r As Range
Headerr = ""
For Each r In rIN
If r.Value > 0 Then Headerr = Headerr & "," & r.EntireColumn.Cells(1).Value
Next r
If Headerr <> "" Then Headerr = Mid(Headerr, 2)
End Function
For example:
This example uses only five columns, but that is not a limit.
User Defined Functions (UDFs) are very easy to install and use:
ALT-F11 brings up the VBE window
ALT-I
ALT-M opens a fresh module
paste the stuff in and close the VBE window
If you save the workbook, the UDF will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the UDF:
bring up the VBE window as above
clear the code out
close the VBE window
To use the UDF from Excel:
=myfunction(A1)
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
and for specifics on UDFs, see:
http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx
Macros must be enabled for this to work!
I basically created an Excel VBA application that manipulate Excel worksheets, so in the code, I use the string "Sheet1" to refer to the first sheet of a workbook, but when I try to use this application with the same code with a french version of Excel, it doesn't work until I translate "Sheet1" to "Feuil1". So my question is, is there a way to automatically adapt the code to any version of Excel ?
You can use the following ways to get a sheet from code:
(1) using by Sheets(sheet_index)
This way cannot be adapt because it take the sheet by sheet index (sheet index are start from 1). When sheet are change place, it cannot access the right sheet.So, it should not use.
For example: Set Feuil1Sheet = Sheets(1)
(2) using by (Name) of VBA editor
I think this way should not use never, because it takes the sheet by code name which can only visible by VBA editor(it shows as (Name) field in sheet properties). I think you are using this way for getting the first sheet. So, you not get the right sheet. One thing you need to know is that code name of every first sheet may not be Sheet1 always. It can be Sheet2 or Sheet4, etc.
For example: Set Feuil1Sheet = Sheet1
(3) using Worksheets("sheet-name") or Sheets("sheet-name")
This last way is a very compatible way and can be adapt in anywhere Excel because it take the sheet by its name. So, If names are equal, you will get the right sheet. So, use this for getting the sheet.
For example: Set Feuil1Sheet = Worksheets("Feuil1") or Set Feuil1Sheet = Sheets("Feuil1")
The only possible way I can think of to always reference "sheet1" in the local language is the following code.
Option Explicit
Public Sub GetLocalNameForNewSheets()
Dim strSheetName As String
Dim i As Long
i = ActiveWorkbook.Sheets.Count
ActiveWorkbook.Sheets.Add After:=Worksheets(i)
strSheetName = ActiveWorkbook.Worksheets(i + 1).Name
Application.DisplayAlerts = False
ActiveWorkbook.Worksheets(i + 1).Delete
Application.DisplayAlerts = True
Debug.Print strSheetName
For i = 1 To Len(strSheetName)
While IsNumeric(Mid(strSheetName, i, 1))
strSheetName = Replace(strSheetName, Mid(strSheetName, i, 1), "")
Wend
Next i
Debug.Print strSheetName
Debug.Print strSheetName & "1"
End Sub
Basically, I am asking Excel to create a new sheet and name it for me. Then, I am getting the new name which is "sheet" in the local language and remove from the string the number part. At the end, you can add the number "1" to reference the first sheet.
The scenario is as follows:
I have an excel (.xls) file with data. (eg. A.xls)
The Data on this excel file are on a single worksheet (Sheet 1).
The number of columns in this file is fixed i.e. 8
However, the number of rows containing data may vary from time to time. (This file is updated by another program from time to time)
Now, I have another excel file (eg. B.xls) with similar type of data but not same as the contents of A.xls.
The number of columns in B.xls is 8 as well. However, the number of rows containing data are unknown.
I want to copy the contents of A.xls, 2nd row onwards (excluding the 1st row containing the column headers) and append/paste the same to the B.xls file, without over-writing the existing data on B.xls.
With all these details in mind, I want to write a vbscript to automate this task.
Please help.
Thanks a lot, in advance.
It needs a lot of cleanup, but something like this should work. I'll clean it up a bit and then make an edit.
Sub CopyRows()
' Choose the name of the Second Workbook and last column.
' It must be in the same directory as your First Workbook.
secondWorkbook = "B.xls"
lastColumn = "H"
' A couple more variables
currentWorkbook = ThisWorkbook.Name
Workbooks.Open ThisWorkbook.Path & "\" & secondWorkbook
' In the First Workbook, find and select the first empty
' cell in column A on the first Worksheet.
Windows(currentWorkbook).Activate
With Worksheets(1).Columns("A:A")
Set c = .Find("", LookIn:=xlValues)
If Not c Is Nothing Then
' Select and copy from A2 to the end.
secondAddress = Replace(c.Address, "$A$", "")
Range("A2:" & lastColumn & CStr(CInt(secondAddress) - 1)).Select
Selection.Copy
End If
End With
' Activate the Second Workbook
Windows(secondWorkbook).Activate
With Worksheets(1).Columns("A:A")
Set c = .Find("", LookIn:=xlValues)
If Not c Is Nothing Then
' Select and paste the data from First Workbook
Range(c.Address).Select
ActiveSheet.Paste
End If
End With
End Sub
Update: That should do the trick. I copied from the wrong workbook the first time around, too. Let me know if you have questions.
This is something the Macro Recoder could have written for you. You would come out with different approach.
Turn on recording. Open A.xls and B.xls. Move down one row on a. Press Shift+End then →, then Shift+End+↓. Then Ctrl+C to copy your data. Switch back to B. End+↓, ↓. Ctrl+V to paste. Turn off recording.
You can record in Excel.
Alt+T,M,R
then Home key then ↑. Stop recording.
Look what Excel wrote
Selection.End(xlUp).Select
or if you had of recorded Go To dialog
Application.Goto Reference:="R1C1"
or if you had of recorded Ctrl+Home
Range("A1").Select
To convert to vbscript
Record the steps in excel macro recorder. You have to rewrite it a bit because it uses a type of syntax that vbs doesn't.
This applies (I don't have a medium9) xlRangeAutoFormatAccounting4 in vba.
Selection.AutoFormat Format:=xlRangeAutoFormatAccounting4, Number:=True, _
Font:=True, Alignment:=True, Border:=True, Pattern:=True, Width:=True
So first look up constants in vba's object browser. xlRangeAutoFormatAccounting4 = 17
Then look the function up in object browser and look at the bottom for the function definition,.
Function AutoFormat([Format As XlRangeAutoFormat = xlRangeAutoFormatClassic1], [Number], [Font], [Alignment], [Border], [Pattern], [Width])
So the vba becomes in vbs (and vbs works in vba) (and as you can see you can work out the correct way without needing to look the function up usually)
Selection.AutoFormat 17, True, True, True,True, True, True
So your code becomes
objXLWs.Range("A3").CurrentRegion.Select.AutoFormat 17, True, True, True,True, True, True
So I have a cell with the formula =A+B, A and B are external values for which the external spreadsheet is no longer open. I was wondering if excel remembers the formula elements and if it was possible to get those element values into other cells. i.e.
Row Formula Value
1 =A+B 45
2 =ELEMENT(A1, 1) 10
3 =ELEMENT(A1, 2) 35
I can't imagine it being that simple though? I could seperate out the formula in vba using the + as a pivot, but this is not ideal as it would require the external spreadsheet to be reopened. If the external spreadsheet has to be reopened then I needn't bother trying to seperate the formula in the first place. I hope this makes sense and has an answer.
Your formula is already accessing those values in order to sum them in the open workbook. You do NOT need to re-open the workbook in order to evaluate the reference values, nor to parse the formula in the active workbook.
Assuming your formula references a closed workbook, with a simple sum function like:
='C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!$A$1 + ='C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!$B$1
You can parse the formula either in VBA or using string functions on the worksheet. As you note, for this example, parsing by the + operator will suffice. Since I think you understand how to do this, my example does not demonstrate how to parse the formula.
As long as you know or can obtain the references from the formula, you should be able to access those cells' values via formula, or programmatically in VBA using ExecuteExcel4Macro.
Sub GetValsFromClosedWorkbook()
Dim fileName As String
Dim filePath As String
Dim sheetName As String
Dim cellref As String
Dim myFormula As String
'This example might be one of the two arguments in your "A+B" formula:
' 'C:\Users\david_zemens\Desktop\[test.xlsx]Sheet1'!A1
'## Assume you can properly parse the formula to arrive at these:
fileName = "test.xlsx"
filePath = "C:\Users\david_zemens\Desktop\"
sheetName = "Sheet1"
cellref = "A1"
'Concatenate in to R1C1 notation
myFormula = "='" & filePath & "[" & fileName & "]" & sheetName & "'!" & _
Range(cellref).Address(, , xlR1C1)
'## First, demonstrate that we can evaluate external references:
With Range("B1")
.Value = myFormula
MsgBox .Value
.Clear
End With
'## Evaluate the formula using ExecuteExcel4Macro:
MsgBox ExecuteExcel4Macro(Replace(myFormula, "=", vbNullString))
End Sub
Additional info
http://spreadsheetpage.com/index.php/tip/a_vba_function_to_get_a_value_from_a_closed_file/
Update
Based on OP's question of how this works (comments, below), I am not certain of how it works behind the scenes but here is my guess/explanation:
Firstly, keep in mind that a cell may have various properties like .Text, .Value, .Value2, .Formula etc. which in one way or another represent its contents.
The values aren't in the active file until the formula is evaluated, at which point Excel queries the external file and returns the current Value at that reference. Now the active file contains that Value as well as a Formula reference the external file.
As you continue working the active file preserves the Value and the reference, but may only update the value when prompted. For example, when you re-open the linked workbook, you will be prompted whether to "update external links".
if you say no, it will use the previously stored values (still preserves the Formula, it just doesn't evaluate it.
if you say yes, it will re-evaluate the formula (in case the value in the external file has changed) and return the new .Value
So, that's what I suspect is happening. If you're asking "How does Excel access the data inside an un-opened workbook" I don't really know how I just know that it does.