VBA - Using Average function in Sheets.Range - excel

I've tried searching a few different threads but wasn't able to get a solution.
My macro is going to transfer data from one sheet to another. I need to use the AVERAGE function to get the average of a range (on the other sheet)
I'm getting a RUN TIME ERROR 438 error and can't figure out why. I tried using Application.WorksheetFunction but this doesn't bear the correct result and works on the MAX function but not the AVERAGE. I saw a few solutions that involve creating a loop and variables, but I assumed a simple solution should be possible.
Code below:
Option Explicit
Sub Step8CopytoLean()
Dim wblean As Workbook
Dim wbmaster As Workbook
Set wblean = Workbooks("SLA Reporting Lean.xlsx")
Set wbmaster = Workbooks("SLA Reporting MasterFile.xlsx")
Workbooks("Lean.xlsx").Activate
Worksheets("Data").Delete
Workbooks("MasterFile.xlsx").Activate
Worksheets("Data").Copy After:=Workbooks("Lean.xlsx").Sheets("Summary")
Workbooks("Lean.xlsx").Sheets("Summary").Activate
wblean.Sheets("Summary").Range("E4").Value = wbmaster.Sheets("Summary").Range("K20")
wblean.Sheets("Summary").Range("F4").Value = wbmaster.Sheets("Summary").Range("M20")
wblean.Sheets("Summary").Range("E5:E6").Value = wbmaster.Sheets("Summary").Average(Range("K9:K11")) 'line with error
wblean.Sheets("Summary").Range("F5").Value = wbmaster.Sheets("Summary").Max(Range("M8:M11")) 'line with error

Modify the below and try:
Application.WorksheetFunction.Average(ThisWorkbook.Worksheets("Sheet1").Range("A1:A10"))
Something like this:
wblean.Sheets("Summary").Range("E5:E6").Value = Application.WorksheetFunction.Average(wbmaster.Worksheets("Summary").Range("K9:K11"))
wblean.Sheets("Summary").Range("F5").Value = Application.WorksheetFunction.Max(wbmaster.Worksheets("Summary").Range("M8:M11"))

Related

commentsthreaded.count property not available in excel 365 vba

I am trying to adjust some workbook audit code for the new threaded comments. Basically the code would cycle through all workbook comments (notes) and consolidate them into a new sheet at the end of the workbook.
With what is now notes, I use the following (noting cmt1 is declared as a comment object and wsSource is a worksheet object)
For Each cmt1 In wsSource.Comments
'Collect comment data for testing/pasting
strSheetname = wsSource.Name
strCmt = cmt1.Text
strCellref = cmt1.Parent.Address
strContent = cmt1.Parent.Formula
etc.
Now with threaded comments, the same type of approach didn't work. I am trying to do a numerical loop using a counter and having code like the below:
For x = 1 to wsSource.commentsthreaded.count
However the count property doesn't work. According to the nmicrosoft website, it should be one of the 4 available properties.
https://learn.microsoft.com/en-us/office/vba/api/excel.commentsthreaded
Does anyone else have this issue? Any way to fix it?
Issue resolved - it looks like the problem was the Excel version. I was running 1904 and it now works since updating to 1906.

VBS for Excel to count and specific word and use it for a loop

I need little help again.
I have an excel file and I have to do some formatting for further processing.
I stuck at one point:
find a word / or string
get back the number how often it is used in the excel
use this number to put it into a loop
I hope this is possible with VBscript, because I cannot use VBA.
This is how the code looks like, but I doesn't work
Dim objExcel
Set Excel = CreateObject("Excel.Application")
Excel.Visible = True
excel.workbooks.open "C:\Users\............."
excel.Rows("1:34").Select
excel.Selection.Delete
excel.Columns("A:A").Select
excel.Selection.Delete
excel.Range("A1").Select
Number = excel.countIf "A:A", "Ent.Date"
for i = 1 to Number
excel.Cells.Find("Ent.Date").Activate
excel.Activecell.Offset(-1,0).Select
excel.Activecell.resize(RowSize +3).EntireRow.Select
excel.Selection.Delete
next
Please help me.
Thanks
You are close. CountIf() is a method of the WorksheetFunction class in your Excel application. So:
Number = Excel.WorksheetFunction.CountIf("A:A", "Ent.Date")
Unrelated. All of this .Active .Select is unnecessary. Humans Select and Activate, but your script doesn't need to.
Instead:
Set Excel = CreateObject("Excel.Application")
Excel.Visible = True
excel.workbooks.open "C:\Users\............."
excel.Rows("1:34").Delete
excel.Columns("A:A").Delete
Number = excel.WorksheetFunction.CountIf(Excel.Range("A:A"), "Ent.Date")
for i = 1 to Number
excel.Cells.Find("Ent.Date").Offset(-1,0).resize(RowSize +3).EntireRow.Delete
next
Also (and this might be more preference) instead of looping with For you could instead us a While loop:
Set Excel = CreateObject("Excel.Application")
Excel.Visible = True
excel.workbooks.open "C:\Users\............."
excel.Rows("1:34").Delete
excel.Columns("A:A").Delete
Do While excel.WorksheetFunction.CountIf(Excel.Range("A:A"), "Ent.Date") >= 1
excel.Cells.Find("Ent.Date").Offset(-1,0).resize(RowSize +3).EntireRow.Delete
Loop
That causes a little extra overhead since it runs that countif on each loop, but it feels more succinct and less potential for error since you seem to be resizing the range returned by Find() to be more rows and then deleting them all... which means you might be picking off rows that also contain your search criteria, which means you are looping too much in your For Loop. But... perhaps your sheet is set up in such a way that this condition doesn't happen.

Excel VBA - Get chart data range

I want to add data to a bunch of existing charts. Assume that each chart has a different number of data series and that the location of the raw data is somewhere in the same workbook. Here's what I'm starting with:
For iChart = 1 To iCount
ActiveSheet.ChartObjects("Chart " & iChart).Activate
intSeries = 1
Do Until ActiveChart.SeriesCollection(intSeries).Name = ""
Set rXVal = ActiveChart.SeriesCollection(intSeries).XValues '<- Object Required error
Set rXVal = Range(rXVal, rXVal.End(xlDown))
Set rYVal = ActiveChart.SeriesCollection(intSeries).Values
Set rYVal = Range(rYVal, rYVal.End(xlDown))
ActiveChart.SeriesCollection(intSeries).XValues = rXVal
ActiveChart.SeriesCollection(intSeries).Values = rYVal
intSeries = intSeries + 1
Loop
Next iChart
I know that ActiveChart...XValues = rXVal works, but I'm getting an "Object Required" error on the Set rXVal = ActiveChart....XValues line. I'm assuming that since a range went in to define the data series, I can get that range back out again and then add to it.
UPDATE
To clarify things a little, I have accelerometers in 8 places and FFT software setup to record peak vibration response in 4 separate frequency bands. This yields 32 data points per sample. When exporting, the software spits out an Excel workbook with 4 sheets; one for each frequency band. Each sheet has the accelerometer names going across and sample numbers going down.
I have succeeded using this syntax:
Dim rXVal() As Variant
rXVal = ActiveChart.SeriesCollection(intSeries).XValues
UPDATE
In this case you get an array, because your given statement (ActiveChart.SeriesCollection(intSeries).XValues) is an array and not a range. This is what you see in Locals window if you dig into Series object of ActiveChart.SeriesCollection(intSeries):
(in my dummy data I have rows named r1, r2, r3, r4.)
What I want to say, XValues does not have any property which would indicate its occupied range.
If you actually need a range, I would suggest getting it from the formula property. And the way I would suggest is replacing your error causing line with this one:
Set rXVal = Range(Split(ActiveChart.SeriesCollection(intSeries).Formula, ",")(1))
Next, I see you trying to get the range for Values. Similarly, use this:
Set rYVal = Range(Split(ActiveChart.SeriesCollection(intSeries).Formula, ",")(2))
Another thing.
The following lines will cause you an error finally:
intSeries = 1
Do Until ActiveChart.SeriesCollection(intSeries).Name = ""
...some code...
intSeries = intSeries + 1
Loop
Do change them with:
For intSeries = 1 To ActiveChart.SeriesCollection.Count
...some code...
Next
Yet another thing.
Consider using With and End With, as you repeat a lot ActiveChart.SeriesCollection(intSeries). Then your code will be much more readable, as you would just skip this long line! Wouldn't that be awesome???
This works fine for me:
Dim rXVal() As Variant
Dim rXValMin, rXValMax As Double
rXVal = ActiveChart.SeriesCollection(intSeries).XValues
rXValMin = WorksheetFunction.Min(rXVal)
rXValMax = WorksheetFunction.Max(rXVal)

Excel VBA Missing Reference - PI Osisoft

I have an VBA code where I use many objects from PISDK, which I have to add as reference to my project.
I must explicitly declare the variables otherwise the code won't work. I don't know why. Excel throws an error ("types doesn't match") if I declare, for example, pt as object instead of PIPoint.
Here is part of my code:
Dim srv As Server
Dim pt As PIPoint
Dim pv As PIValue
Dim dt As New PITimeFormat
The problem is: when user doesn't have this reference installed, Excel gives me an compilation error, so it's impossible to catch and handle this error. Since this code runs on a user-defined function, as soon as the user opens the workbook, he gets stuck with compiling errors.
I must be able to catch this error.
I can't find documentations to fully implement late binding on this code. I don't know if it's really possible to do it. I know it could solve my problem.
Also, I know I could check if the reference is installed, thru:
thisworkbook.vbproject.references
But if the user doesn't allow access to the vbaProject object under Excel options, I am not able to do this.
Any idea?
I managed to solve my problem declaring everything as object and then using createobject afterwards.
The main problem doing this was using functions, like this one:
I have the function "arcValue". It takes three arguments:
arcValue(TimeStamp as PITimeFormat, Mode as RetrievelTypeConstants, Optional asynchStatus as PIAyncnStatus)
The way I use it doing early binding is:
dim pt as PIPoint
dim pv as PIValue
set pv = pt.data.arcValue("01/09/2014 17:00:00", rtInterpolated)
This works. But when I do:
Dim myPISDK As Object
Dim srv As Object
Dim pt As Object
Dim pd as Object
Dim pv as Object
Set myPISDK = CreateObject("PISDK.PISDK")
Set pv = CreateObject("PISDK.PIValue")
Set srv = myPISDK.Servers.defaultserver
Set pd = pt.DATA
Set pt = srv.PIPoints("piTAG")
Set pv = pd.ArcValue("01/09/2014 17:00:00", rtInterpolated)
It doesn't work. But why?
There were two problems:
First: When I use late binding (createobject) I don't have access to "rtInterpolated" constant, so I have to use its equivalent number.
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3)
But this still doesn't work. So I had to do this to make it work:
Set pv = pd.ArcValue("01/09/2014 17:00:00", 3, Nothing)
And then everything started working. I don't know why, but VBA makes me write something do all parameters, even if they are optional.
This way, I am able to detect erros in runtime, so I used this code:
If myPISDK Is Nothing Then
piVerified = "Erro PI"
Exit Function
End If
Also, I had to remove all references (they are not used anymore, anyway) because it was causing malfunction on other parts of my code not related to this one when the references were missing.
You can use something like that:
Sub NotUsed()
Dim pt As PIPoint
End Sub
Function ReferenceCheck() As Boolean
On Error GoTo NoRef
pt = Acrobat.AV_DOC_VIEW ' PIPoint
ReferenceCheck = True
Exit Function
NoRef:
ReferenceCheck = False
End Function
Sub Test()
If ReferenceCheck Then NotUsed
End Sub
The function refer to a proprieties of the object. If the reference it's ok return true otherwise false.
In the phase of init you can check like that.
The sub NotUsed, don't create Error because not called...
In my sample I use the ADOBE Object ...

object defined error with assigning named range to array

i am trying t assign the values of a named range to an array of variants. I get an application or object defined error almost at the level of assignment code
Material = ThisWorkbook.Names("RMInStoreName").RefersToRange
i got this example from here and have used it before sucessfully.
I am still trying to figure out why this error is showing up, i seem to have run out of ideas, anybody can help me point in the right direction will realy save me alot
The code is below
Here is the code
Sub MonitorStore()
Dim ThreshHold As Variant, InStore As Variant, StatusReport As Variant
Dim Material As Variant 'is the name of the material
Status As Variant
'status is a variable which holds data on wether the user has seen msg and
'wants to supress msg
'the ThreshHold is the minimum allowed in store below which messages are firerd
'InStore is the volume of materials currently in store
'and be told of another error after solving error one, report all at once
Material = ThisWorkbook.Names("RMInStoreName").RefersToRange
ThreshHold = ThisWorkbook.Names("RMThreshHold").RefersToRange
InStore = ThisWorkbook.Names("RMInStore").RefersToRange
Status = ThisWorkbook.Names("RMStatus").RefersToRange
'other code.............
'dont expect error from unexecuted code
End Sub
Thanks for help
Stephen
The most likely reason is that you don't have all of the named ranges defined in the workbook.
You can verify the named ranges using the Formula tab.
Formula --> Name Manager
RefersToRange will return a range object. Its the value you are after then:
Material = ThisWorkbook.Names("RMInStoreName").RefersToRange.Value
or you can use:
Material = Evaluate("RMInStoreName")
or:
Material = Evaluate(ThisWorkbook.Names("RMInStoreName").RefersTo).Value

Resources