I have API functions in my excel that fetch live stock prices. I want to save the first live price at 9:15 am in a column, but as this value is fetched through a function, I am unable to modify another cell value. I tried calling subroutine inside the function, but it crashes the excel.
How can this be achieved?
I want the value exactly at 9:15 and not the values before or after that.
Can something like DictKeys be used?
My Code
Public Function GetRTD(Exch As String, TrdSymbol As String, Field As String)
On Error Resume Next
If Exch = "" Then
GetRTD = ""
Exit Function
End If
If TrdSymbol = "" Then
GetRTD = ""
Exit Function
End If
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = False
Dim Prfx As String
Prfx = TrdSymbol & "." & Exch
GetRTD = WorksheetFunction.RTD("Kite.RtdServer", "", Prfx, Field)
Exit Function
End Function
Related
I've got a really odd case… hopefully someone is able to help me out, I've search many forums looking for a solution, the closest I could find related to it (kinda) is here, though I've tried all the suggestions to no avail…
I'm trying to run a function to return a data list in a string delimitated by a semicolon from an oracle stored function. (This value function call seems to work fine).
I then loop through the string for each data value and print it to a blank table (0 rows) declared in my subroutine. which I use to load into an access data base. (just trust it make sense in the big picture…).
The issue, fundamentally is that no information is printed into the table. However when I step through the code it works fine.
After troubleshooting I THINK (see my test scenarios below code) the issue comes up after the listrows.add line... though not obviously.
I don't think this line is executed by the time the first value is trying to print to the table.
The most confusing part is I'm running through 2 nearly identical procedures (call function -> Return value -> print values to table) immediately before this portion of the code and they work without fail.
Code Excerpt:
'run function to get string ... this works
DoEvents ' not in original design
RelRtnStr = Prnt(Cat, "A Third Oracle Function Name")
DoEvents ' not in original design
RelChopVar = RelRtnStr
StrFldCnt = 0
Checking = True ''' CodeBreak Test 1
DoEvents ' not in original design
AppendRlLmTbl.ListRows.Add ''''''''This isn't appearing to work...
DoEvents ' not in original design
Debug.Print Now ' not in original design
Application.Wait (Now + TimeValue("0:00:3")) ' not in original design
Debug.Print Now ' not in original design
While StrFldCnt < 80 And (Len(RelChopVar) - Len(Replace(RelChopVar, ";", ""))) > 0 And Checking
'## Count String Position
StrFldCnt = StrFldCnt + 1
'## Find Current String Value & Remainder String
If InStr(RelChopVar, ";") <> 0 Then
'Multiple Values Left
FldVal = Replace(Left(RelChopVar, InStr(RelChopVar, ";")), ";", "")
RelChopVar = Right(RelChopVar, Len(RelChopVar) - InStr(RelChopVar, ";"))
Else
'Last Value
FldVal = RelChopVar
Checking = False
End If
'## Get Field Name For Current Value & Print to Table
FldNm = CStr(RefRtrn(2, CStr(StrFldCnt))) ''' CodeBreak Test 2
AppendRlLmTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal '''CodeBreak 2 error thrown
Debug.Print StrFldCnt & FldNm & FldVal
Wend
AppendRlLmTbl.ListColumns("Catalogue").DataBodyRange.Value = Cat
So far I've tested a ton of options suggested online, not necessarily understanding each test... This is what I've gleaned.
If I step through the code, it works
If I set a breakpoint at "CodeBreak Test 1" and "F5" the rest, it works …
If I set a breakpoint at "CodeBreak Test 2" I get an "Object with variable not set" error thrown …
Things I've tried …
Wrapping anything and everything with DoEvents
setting a wait time after the listObjects.add row
Validated the code performs the While loop when running the "full procured" (as opposed to stepping through)
The worst part, I have no idea why the object won't declare properly when setting a break point after the add row line but sets properly when break point is set before and has no error thrown when running the full procedure (I have no on error declarations.)...
It of course must be related in my mind but I can't find any information online and unfortunately have no formal VBA background and 1 undergrad course as a programming background in general. Aka I'm out of my depth and super frustrated.
PS. first post, so please be nice :p
Full Code Below:
Option Explicit
'## Here's my attempt to clean up and standardize the flow
'## Declare my public variables
' WorkBook
Public WB As Workbook
' Sheets
Public Req2ByWS As Worksheet
Public ReqSpecsWS As Worksheet
Public ReqInstrcWS As Worksheet
Public ConfigReqWS As Worksheet
Public AppendReqWS As Worksheet
Public AppendRlLmWS As Worksheet
' Objects (tables)
Public ReqConfigTbl As ListObject
Public SpecConfigTbl As ListObject
Public CurrRegIDTbl As ListObject
Public AppendReqTbl As ListObject
Public AppendRlLmTbl As ListObject
'## ##
'## Get Data from Tom's Functions ##
Sub GetSpotBuyData()
'## Preliminary Config ##
'## Turn OFF Warnings & Screen Updates
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'## Set global Referances to be used in routine
' WorkBooks
Set WB = Workbooks("MyWb.xlsm")
' WorkSheets
Set Req2ByWS = WB.Sheets("MyWb Pg1")
Set ReqSpecsWS = WB.Sheets("MyWb Pg2")
Set ConfigReqWS = WB.Sheets("MyWb Pg3")
Set AppendReqWS = WB.Sheets("MyWb Pg4")
Set AppendRlLmWS = WB.Sheets("MyWb Pg5")
' Tables
Set ReqConfigTbl = ConfigReqWS.ListObjects("MyWS Tbl1")
Set SpecConfigTbl = ConfigReqWS.ListObjects("MyWS Tbl2")
Set CurrRegIDTbl = ConfigReqWS.ListObjects("MyWS Tbl3")
Set AppendReqTbl = AppendReqWS.ListObjects("MyWS Tbl4")
Set AppendRlLmTbl = AppendRlLmWS.ListObjects("MyWS Tbl5")
'## Declare Routine Specefic Variables
Dim Doit As Variant
Dim Checking As Boolean
Dim Cat As String
Dim CatRtnStr As String
Dim CatChopVar As String
Dim SpecRtnStr As String
Dim SpecChopVar As String
Dim RelRtnStr As String
Dim RelChopVar As String
Dim FldVal As String
Dim FldNm As String
Dim StrFldCnt As Integer
'## 1) General Set-Up ##
'## Unprotect tabs (loop through All Tabs Unprotect)
Doit = Protct(False, WB, "Mypassword")
'## Refresh Data
Doit = RunUpdateAl(WB)
'## 2) Find the Catalgue we are playing with ##
'## Grab Catalogue input from ISR
If [Catalogue].Value = "" Then
MsgBox ("Please Enter a Catalogue")
GoTo ExitSub
Else
Cat = [Catalogue].Value
End If
'## 3) Run Toms Function and print the results to the form & Append Table ##
'## 3a) Do it for Cat Info Function
'## Get Cat Info String From Function
CatRtnStr = Prnt(Cat, "An Oracle Functions Name")
CatChopVar = CatRtnStr
If CatChopVar = "No Info" Then
MsgBox ("No Info Found in Catalogue Data Search.")
GoTo SkipCatInfoPrint
End If
'## Loop Through Data String & Write to Form
StrFldCnt = 0
Checking = True
AppendReqTbl.ListRows.Add
While Checking
'## Count String Position
StrFldCnt = StrFldCnt + 1
'## Find Current String Value & Remainder String
If InStr(CatChopVar, ";") <> 0 Then
'Multiple Values Left
FldVal = Replace(Left(CatChopVar, InStr(CatChopVar, ";")), ";", "")
CatChopVar = Right(CatChopVar, Len(CatChopVar) - InStr(CatChopVar, ";"))
Else
'Last Value
FldVal = CatChopVar
Checking = False
End If
'## Get Field Name For Current Value & Print to Form
FldNm = CStr(RefRtrn(1, CStr(StrFldCnt)))
If FldNm <> "CustomerSpecification" And FldNm <> "ShiptoAddress" Then
'Take Value as is
Req2ByWS.Range(FldNm).Value = FldVal
AppendReqTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal
ElseIf FldNm = "CustomerSpecification" Then
'Replace : with New Line
FldVal = Replace(FldVal, " : ", vbLf)
Req2ByWS.Range(FldNm).Value = FldVal
AppendReqTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal
ElseIf FldNm = "ShiptoAddress" Then
'Replace - with New Line
FldVal = Replace(FldVal, " - ", vbLf)
Req2ByWS.Range(FldNm).Value = FldVal
AppendReqTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal
End If
Wend
'## 3b) Do it for Spec Function
SkipCatInfoPrint:
'## Get Spec Info String From Function
SpecRtnStr = Prnt(Cat, "Another Oracle Functions Name")
SpecChopVar = SpecRtnStr
If SpecChopVar = "No Info" Then
MsgBox ("No Info Found in Data Search.")
GoTo SkipSpecInfoPrint
End If
'## Loop Through Data String & Write to Form
StrFldCnt = 0
Checking = True
While StrFldCnt < 80 And (Len(SpecChopVar) - Len(Replace(SpecChopVar, ";", ""))) > 0 And Checking
'## Count String Position
StrFldCnt = StrFldCnt + 1
'## Find Current String Value & Remainder String
If InStr(SpecChopVar, ";") <> 0 Then
'Multiple Values Left
FldVal = Replace(Left(SpecChopVar, InStr(SpecChopVar, ";")), ";", "")
SpecChopVar = Right(SpecChopVar, Len(SpecChopVar) - InStr(SpecChopVar, ";"))
Else
'Last Value
FldVal = SpecChopVar
Checking = False
End If
'## Get Field Name For Current Value & Print to Form
FldNm = CStr(RefRtrn(2, CStr(StrFldCnt)))
ReqSpecsWS.Range(FldNm).Value = FldVal
AppendReqTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal
Wend
'## 3c) Do it for Rel Limits Function
SkipSpecInfoPrint:
'## Get Rel Limits String From Function
RelRtnStr = Prnt(Cat, "A Third Functions Name")
RelChopVar = RelRtnStr
If RelChopVar = "No Info" Then
MsgBox ("No Info Found in Data Search.")
GoTo ExitSub
End If
'## Loop Through Data String & Write to Form
StrFldCnt = 0
Checking = True
AppendRlLmTbl.ListRows.Add
While StrFldCnt < 80 And (Len(RelChopVar) - Len(Replace(RelChopVar, ";", ""))) > 0 And Checking
'## Count String Position
StrFldCnt = StrFldCnt + 1
'## Find Current String Value & Remainder String
If InStr(RelChopVar, ";") <> 0 Then
'Multiple Values Left
FldVal = Replace(Left(RelChopVar, InStr(RelChopVar, ";")), ";", "")
RelChopVar = Right(RelChopVar, Len(RelChopVar) - InStr(RelChopVar, ";"))
Else
'Last Value
FldVal = RelChopVar
Checking = False
End If
'## Get Field Name For Current Value & Print to Form
FldNm = CStr(RefRtrn(2, CStr(StrFldCnt)))
AppendRlLmTbl.ListColumns(FldNm).DataBodyRange.Value = FldVal
Wend
AppendRlLmTbl.ListColumns("SpecificFieldName").DataBodyRange.Value = Cat
'## 4) Re-Format and Clean Up Program ##
ExitSub:
'## Clean-Up Formatting
Req2ByWS.Range("F:F", "C:C").ColumnWidth = 30
Req2ByWS.UsedRange.Rows.AutoFit
Req2ByWS.UsedRange.Columns.AutoFit
Req2ByWS.Range("G:G").ColumnWidth = 15
Req2ByWS.Range("J:R").ColumnWidth = 12
Req2ByWS.Range("D:D").ColumnWidth = 12
'## Protect tabs (loop through All Tabs Protect)
'Doit = Protct(True, WB, "Mypassword", Req2ByWS.Name)
'Req2ByWS.Unprotect ("Mypassword")
'Application.Wait (Now + TimeValue("0:00:10"))
Req2ByWS.Select
'## Turn ON Warnings & Screen Updates
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
I stupidly had an enable background refresh for that specific table. An early call to refresh all data triggered the refresh, code would execute and the refresh would finally complete shortly after the code finished executing... in break mode the refresh would complete prior too. Thanks PEH for helping me look into this.
I have an excel workbook where the user imports text files into a "Data Importation Sheet". The number of files imported is dependent on how files the user wants to import. So far my workbook works great but I have hit one bump. When the user imports a file an identifier (i.e. 1, 2, 3, etc) gets assigned to that data set. Then the user selects an option from a dropdown box and calculations and plots will automatically be produced. The user also has the option to "Clear all data" where when this is selected all worksheets are cleared and if the user imports new files (after clicking the "clear all data" button) the identifier value restarts at 1. Here is my code for the identifier/counting how many files have been imported..
Public Sub Macro(Optional reset As Boolean = False)
Static i As Integer
If reset Then
i = -1
i = i + 1
Exit Sub
End If
i = i + 1
Worksheets("Hidden").Cells(i + 1, 1).FormulaR1C1 = "=" & i
Worksheets("Hidden").Cells(2, 2).FormulaR1C1 = "=" & i
End Sub
The problem I have ran into now is data will need to be imported into this sheet at a later date so when I save this file and reopen it then import more files the identifier/count for file imports restarts at 1 which I do not want to happen. I want to be able to just keep adding more files and have the code continue, I do not want to have to clear all the imported data and restart. Any ideas as to how I can do this? TIA.
I'd create a standalone function to manage the sequence. Store the value in a Workbook Name entry.
Note - if you had to manage multiple sequences you could promote the name of the sequence to a parameter instead of using a Constant within the Function.
Function NextSequence(Optional reset As Boolean = False)
Const COUNTER_NAME As String = "NM_COUNTER"
Dim nm As Name, i
On Error Resume Next
'is the name already created?
Set nm = ThisWorkbook.Names(COUNTER_NAME)
On Error GoTo 0
If nm Is Nothing Then
'not there yest - create it...
Set nm = ThisWorkbook.Names.Add(COUNTER_NAME, 0)
End If
If Not reset Then
i = Evaluate(nm.RefersTo)
i = i + 1
nm.RefersTo = i
Else
nm.RefersTo = 0
i = 0 '<< or 1 if you want NextSequence(True) to
' return the first sequence value
End If
NextSequence = i
End Function
Usage:
Public Sub Macro(Optional reset As Boolean = False)
Dim i
i = NextSequence(reset)
If reset Then Exit Sub
With Worksheets("Hidden")
.Cells(i + 1, 1).Value = i
.Cells(2, 2).Value = i
End With
End Sub
A quick fix for this would be to store the value of the identifier/count inside a cell and hide/lock the cell. The value inside the cell won't change upon restart yet you still can manipulate it inside VBA.
Very quick feel of how it should look like (probably innacurate as I don't have every info I need.)
Public Sub Macro(Optional reset As Boolean = False)
Static i As Integer
i = ActiveWorkBook.Sheets("Ressource").Range("A1").Value
If reset Then
i = -1
i = i + 1
Exit Sub
End If
i = i + 1
Worksheets("Hidden").Cells(i + 1, 1).FormulaR1C1 = "=" & i
Worksheets("Hidden").Cells(2, 2).FormulaR1C1 = "=" & i
End Sub
You could also create a CustomDocumentProperty to save the sequence number. You can pass a boolean to the method to reset:
Lastly, a helper function will check if the property exists, in order to be added if not.
Public Sub SequenceNumber(Optional ByVal Reset As Boolean = False)
If Not PropertyExists("Identifier") Then
ThisWorkbook.CustomDocumentProperties.Add Name:="Identifier", _
LinkToContent:=False, _
Type:=msoPropertyTypeNumber, _
Value:=0
End If
Dim p As Object
Set p = ThisWorkbook.CustomDocumentProperties("Identifier")
If Reset Then p.Value = 0 Else p.Value = p.Value + 1
End Sub
'Property Exists?
Private Function PropertyExists(ByVal propertyName As String) As Boolean
Dim p As Object
For Each p In ThisWorkbook.CustomDocumentProperties
If p.Name = propertyName Then
PropertyExists = True
Exit Function
End If
Next p
End Function
To call it:
SequenceNumber
SequenceNumber Reset:=True
i'm writing a user defined function for excel in VBA.
User may pass a whole column/row into the function instead of one cell. How do you get cell that is in the same row (for column case) and in the same column (for row case), where the function is.
For example, when you are writing in Excel in cell, say, C3 the formula "=A:A*B:B" it calculates A3*B3 in fact. I want to have the same behaiviour in my UDF.
Let's assume function that returns passed argument for simplicity reasons.
This code does not work (returns #VALUE! for columns/rows/ranges):
Public Function MyTestFunction(ByVal arg1) As Variant
MyTestFunction = arg1
End Function
My option is as follows, but I am concerned about performance and the fact that user may want to pass a value to the formula instead of Range.
Public Function MyTestFunction2(ByVal arg1 As Range) As Variant
If arg1.Count = 1 Then
MyTestFunction2 = arg1.Value
Else
' Vertical range
If arg1.Columns.Count = 1 Then
MyTestFunction2 = arg1.Columns(1).Cells(Application.Caller.Row, 1).Value
Exit Function
End If
' Horizontal range
If arg1.Rows.Count = 1 Then
MyTestFunction2 = arg1.Rows(1).Cells(1, Application.Caller.Column).Value
Exit Function
End If
' Return #REF! error to user
MyTestFunction2 = CVErr(xlErrRef)
End If
End Function
How do you solve this problem?
Thanks to valuable comments code has been slightly updated and now can be used in other formulas to filter input values.
Public Function MyTestFunction2(ByVal arg1) As Variant
If Not TypeName(arg1) = "Range" Then
MyTestFunction2 = arg1
Exit Function
End If
If arg1.Count = 1 Then
MyTestFunction2 = arg1.Value
Else
' Vertical range
If arg1.Columns.Count = 1 Then
' check for range match current cell
If arg1.Cells(1, 1).Row > Application.Caller.Row Or _
arg1.Cells(1, 1).Row + arg1.Rows.Count - 1 < Application.Caller.Row Then
' Return #REF! error to user
MyTestFunction2 = CVErr(xlErrRef)
Exit Function
End If
' return value from cell matching cell with function
MyTestFunction2 = arg1.Worksheet.Columns(1).Cells(Application.Caller.Row, arg1.Column).Value
Exit Function
End If
' Horizontal range
If arg1.Rows.Count = 1 Then
' check for range match current cell
If arg1.Cells(1, 1).Column > Application.Caller.Column Or _
arg1.Cells(1, 1).Column + arg1.Columns.Count - 1 < Application.Caller.Column Then
' Return #REF! error to user
MyTestFunction2 = CVErr(xlErrRef)
Exit Function
End If
' return value from cell matching cell with function
MyTestFunction2 = arg1.Worksheet.Rows(1).Cells(arg1.Row, Application.Caller.Column).Value
Exit Function
End If
' Return #REF! error to user
MyTestFunction2 = CVErr(xlErrRef)
End If
End Function
In the first code snippet change MyTestFunction = arg1 to Set MyTestFunction = arg1. Also add a small mechanism that recognizes the TypeName() of the arg1 and make sure that the function is receiving a Range type object.
Public Function MyTestFunction(ByVal arg1) As Variant
Set MyTestFunction = arg1
End Function
example
Then, if you get to your spreadsheet and type in =MyTestFunction(A:A) on any row and you'll receive the equivalent value from the column you're passing to the function that sits on the same row.
And your second idea about getting a similar behaviour as =A:A*B:B you can achieve with
Public Function MyTestFunction2(ParamArray arr() As Variant)
MyTestFunction2 = arr(0)
End Function
example
I think you need to use Application.ThisCell property to do it. According to MSDN:
Application.ThisCell- Returns the cell in which the user-defined
function is being called from as a Range object.
Let me present how to use it on simple example.
Imagine we have data as presented below in column A:B and we want to achieve results which comes from =A*B for each row separately.
In such situation you need the function below and put it next in C column in this way: =MyTestFunction(A:A,B:B)
Function MyTestFunction(rngA As Range, rngB As Range)
Dim funRow As Long
funRow = Application.ThisCell.Row
MyTestFunction = rngA(funRow) * rngB(funRow)
End Function
Please keep in mind that Application.ThisCell will not work if you call your function from other VBA procedure.
I'm writing a script that will count a numbers of days between few separate dates. I have a data in cell like:
1-In Progress#02-ASSIGNED TO TEAM#22/01/2013 14:54:23,4-On
Hold#02-ASSIGNED TO TEAM#18/01/2013 16:02:03,1-In Progress#02-ASSIGNED
TO TEAM#18/01/2013 16:02:03
That's the info about my transaction status. I want to count the numbers of days that this transaction was in "4-On Hold". So in this example it will be between 18/01/2013 and 22/01/2013.
I wrote something like this(sorry for ma native language words in text)
Sub Aktywnywiersz()
Dim wiersz, i, licz As Integer
Dim tekstwsadowy As String
Dim koniectekstu As String
Dim pozostalytekst As String
Dim dataztekstu As Date
Dim status4jest As Boolean
Dim status4byl As Boolean
Dim datarozpoczecia4 As Date
Dim datazakonczenia4 As Date
Dim dniw4 As Long
wiersz = 2 'I start my scrypt from second row of excel
Do Until IsEmpty(Cells(wiersz, "A")) 'this should work until there is any text in a row
status4jest = False 'is status 4-On Hold is now in a Loop
status4byl = False 'is status 4-On Hold was in las loop
dniw4 = 0 ' numbers od days in 4-On Hold status
tekstwsadowy = Cells(wiersz, "H").Value2 'grabing text
tekstwsadowy = dodanieprzecinka(tekstwsadowy) 'in some examples I had to add a coma at the end of text
For i = 1 To Len(tekstwsadowy)
If Right(Left(tekstwsadowy, i), 1) = "," Then licz = licz + 1 'count the number of comas in text that separates the changes in status
Next
For j = 1 To licz
koniectekstu = funkcjaliczeniadni(tekstwsadowy) 'take last record after coma
Cells(wiersz, "k") = koniectekstu
dataztekstu = funkcjadataztekstu(koniectekstu) 'take the date from this record
Cells(wiersz, "m") = dataztekstu
status4jest = funkcjaokreslenia4(koniectekstu) 'check if there is 4-On Hold in record
Cells(wiersz, "n") = status4jest
If (status4byl = False And staus4jest = True) Then
datarozpoczecia4 = dataztekstu
status4byl = True
ElseIf (status4byl = True And staus4jest = False) Then
datazakonczenia4 = dataztekstu
status4byl = False 'if elseif funkcion to check information about 4-On Hold
dniw4 = funkcjaobliczeniadniw4(dniw4, datazakonczenia4, datarozpoczecia4) 'count days in 4-On Hold
Else
'Else not needed...
End If
tekstwsadowy = resztatekstu(tekstwsadowy, koniectekstu) 'remove last record from main text
Next
Cells(wiersz, "L") = dniw4 ' show number of days in 4-On Hold status
wiersz = wiersz + 1
Loop
End Sub
Function funkcjaliczeniadni(tekstwsadowy As String)
Dim a, dl As Integer
dl = Len(tekstwsadowy)
a = 0
On Error GoTo errhandler:
Do Until a > dl
a = Application.WorksheetFunction.Find(",", tekstwsadowy, a + 1)
Loop
funkcjaliczeniadni = tekstwsadowy
Exit Function
errhandler:
funkcjaliczeniadni = Right(tekstwsadowy, dl - a)
End Function
Function dodanieprzecinka(tekstwsadowy As String)
If Right(tekstwsadowy, 1) = "," Then
dodanieprzecinka = Left(tekstwsadowy, Len(tekstwsadowy) - 1)
Else
dodanieprzecinka = tekstwsadowy
End If
End Function
Function resztatekstu(tekstwsadowy, koniectekstu As String)
resztatekstu = Left(tekstwsadowy, Len(tekstwsadowy) - Len(koniectekstu))
End Function
Function funkcjadataztekstu(koniectekstu As String)
funkcjadataztekstu = Right(koniectekstu, 19)
funkcjadataztekstu = Left(funkcjadataztekstu, 10)
End Function
Function funkcjaobliczeniadniw4(dniw4 As Long, datazakonczenia4 As Date, datarozpoczecia4 As Date)
Dim liczbadni As Integer
liczbadni = DateDiff(d, datarozpoczecia4, datazakonczenia4)
funkcjaobliczaniadniw4 = dniw4 + liczbadni
End Function
Function funkcjaokreslenia4(koniectekstu As String)
Dim pierwszyznak As String
pierwszyznak = "4"
If pierszyznak Like Left(koniectekstu, 1) Then
funkcjaokreslenia4 = True
Else
funkcjaokreslenia4 = False
End If
End Function
And for now I get
Run-time error "13"
in
dataztekstu = funkcjadataztekstu(koniectekstu) 'take the date from this record
I would be very grateful for any help.
You are getting that error because of Type Mismatch. dataztekstu is declared as a date and most probably the expression which is being returned by the function funkcjadataztekstu is not a date. You will have to step through it to find what value you are getting in return.
Here is a simple example to replicate that problem
This will give you that error
Option Explicit
Sub Sample()
Dim dt As String
Dim D As Date
dt = "Blah Blah"
D = getdate(dt)
Debug.Print D
End Sub
Function getdate(dd As String)
getdate = dd
End Function
This won't
Option Explicit
Sub Sample()
Dim dt As String
Dim D As Date
dt = "12/12/2014"
D = getdate(dt)
Debug.Print D
End Sub
Function getdate(dd As String)
getdate = dd
End Function
If you change your function to this
Function funkcjadataztekstu(koniectekstu As String)
Dim temp As String
temp = Right(koniectekstu, 19)
temp = Left(temp, 10)
MsgBox temp '<~~ This will tell you if you are getting a valid date in return
funkcjadataztekstu = temp
End Function
Then you can see what that function is returning.
I tried running your code, but it is a little difficult to understand just what it is that you want to do. Part of it is the code in your language, but the code is also hard to read beacuse of the lack of indentation etc. :)
Also, I do not understand how the data in the worksheet looks. I did get it running by guessing, though, and when I did I got the same error you are describing on the second run of the For loop - that was because the koniectekstu string was empty. Not sure if this is your problem, so my solution is a very general.
In order to solve this type of problem:
Use Option Explicit at the top of your code module. This will make you have to declare all variables used in the module, and you will remove many of the problems you have before you run the code. Eg you are declaring a variable status4jest but using a different variable called staus4jest and Excel will not complain unless you use Option Explicit.
Declare return types for your functions.
Format your code so it will be easier to read. Use space before and after statements. Comment everything! You have done some, but make sure a beginner can understand. I will edit you code as an example of indentation.
Debug! Step through your code using F8 and make sure all variables contain what you think they do. You will most likely solve your problem by debugging the code this way.
Ask for help here on specific problems you run into or how to solve specific problems, do not send all the code and ask why it is not working. If you break down your problems into parts and ask separately, you will learn VBA yourself a lot faster.
A specific tip regarding your code: look up the Split function. It can take a string and make an array based on a delimiter - Example: Split(tekstwsadowy, ",") will give you an array of strings, with the text between the commas.
Did I mention Option Explicit? ;)
Anyway, I hope this helps, even if I did not solve the exact error you are getting.
Ok, I've got this formula which generates usernames based on a list of first and last names. Now, while this works, I want the cells to refer to my own VBA function instead. But, I still want to use the original formula because of much less code.
I've got this formula:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(LOWER(LEFT(table[[#This Row];[Firstname:]])&table[[#This Row];[Lastname:]]);"æ";"a");"ø";"o");"å";"a")
This basically generates the username. But, I want to run this through a separate function, to find out if the username is already taken. And if it is, it should generate a slightly different user name.
I was thinking something along these lines:
Public Function genUserName(ByVal strFirstName, strLastName As String)
Dim strUsername As String
Set objDomain = GetObject("WinNT://grunnarbeid2.local")
objDomain.Filter = Array("User")
'FormulaR1C1 = "=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(LOWER(LEFT(tableFaste[[#This Row];[Fornavn:]])&tableFaste[[#This Row];[Etternavn:]]);""æ"";""a"");""ø"";""o"");""å"";""a"")"
'strUsername = ActiveCell.FormulaR1C1
blnFound = False
For Each objUser In objDomain
If objUser.Name = strUsername Then
blnFound = True
Exit For
End If
Next
genUserName = strUsername
End Function
So, how do I combine these?
I would suggest limiting the functionality of genUserName to just checking uniqueness, and pass the result of your existing formual into it:
Public Function genUserName(ByVal strUsername As String)
Set objDomain = GetObject("WinNT://grunnarbeid2.local")
objDomain.Filter = Array("User")
blnFound = False
For Each objUser In objDomain
If objUser.Name = strUsername Then
blnFound = True
Exit For
End If
Next
genUserName = strUsername
End Function
then call it from a cell like
=genUserName(SUBSTITUTE( ... ))