Objects Not Working In Sub - function

In our code, we have a few Excel objects and a few subs and functions.
We edited a few things and now, for some reason, our objects aren't working inside the sub, the give a "Object Required" error.
We don't know what to do anymore, so any help would be greatly appreciated!
Note: We added the entire code in case there would be questions about declarations and that...
Sub:
Sub birthday (formatDate, i, intRow)
'Take date from database, separate it to days & months
Dim month, day, name
eventDate = Split(formatDate,"/")
month = eventDate(0)
day = eventDate(1)
'Get name of event out of database (one column to the right, from date of event)
name = "netch"
'Get value of row which is used to write events in the specific month
Dim k, row, c
k = 1
wscript.echo objXLCal.Cells(k, 2).Value
Do Until objXLCal.Cells(k, 2).Value = monthRet(month)
k = k + 1
Loop
'k will be used to find the day column, while row is where the events of that months are written
row = k + 3
c = 1
'Get value of column
Do Until objXLCal.Cells(k,c).Value = eval(day)
c = c + 1
Loop
'Insert name of event into place
If Asc(name) = 63 Then
objXLCal.Cells(row,c).Value = StrReverse(name)
Else
objXLCal.Cells(row,c).Value = name
End If
End Sub
Rest of code:
main("C:\Users\liatte\Desktop\hotFolder\Input")
Function main(argFilePath)
Dim templatePath
'-----------------------------------------------------------------------------
'Path to calendar template
templatePath = "C:\Users\liatte\Desktop\Aviv Omer Neta\Birthdays\Calendar1.xlsx"
'-----------------------------------------------------------------------------
'creates the msxml object
'Set xmlDoc = CreateObject("Msxml2.DOMDocument.6.0")
'Dim retVal
'load the xml data of the script
'retVal=xmlDoc.load(argFilePath)
Dim fso, folder, sFolder, inputFolder, xmlDataPath, curNode
'get input folder
'Set curNode=xmlDoc.selectSingleNode("//ScriptXmlData/inputFilePath")
'inputFolder=CSTR(curNode.text)
'location of input folder
'sFolder=inputFolder
sFolder=argFilePath
'creating file getting object
Set fso = CreateObject("Scripting.FileSystemObject")
Set folder = fso.GetFolder(sFolder)
'loop that runs on files in input - RUNS JUST ONCE
'For each folderIdx In folder.files
'Creating object for user excel
Set objXLBirth = CreateObject("Excel.Application")
Set objWorkbookBirth = objXLBirth.Workbooks.Open("C:\Users\liatte\Desktop\hotFolder\Input\Birthdays.xlsx")
'Creating object for calendar template excel
Set objXLCal = CreateObject("Excel.Application")
objXLCal.DisplayAlerts = false
Dim picStr, srcMonth, k, i, intRow, formatDate, txtStr
'Beginning reading from line 2, skipping header
intRow = 2
'loop for each person in user excel
Do Until objXLBirth.Cells(intRow,1).Value = ""
i=2
'Opening the template as new in each round of loop
Set objWorkbookCal = objXLCal.Workbooks.Open(templatePath)
'Cover pic
If Not objXLBirth.Cells(intRow, i).Value = "" Then
objXLCal.Cells(2, 49).Value = objXLBirth.Cells(intRow, i).Value
End If
'Month pic inserter
For i=3 To 14
If Not objXLBirth.Cells(intRow,i).Value = "" Then
picStr = objXLBirth.Cells(1,i).Value
srcMonth = monthRet(Mid(picStr,4))
k=1
Do Until objXLCal.Cells(k, 2).Value = srcMonth
k=k+1
Loop
objXLCal.Cells(k, 47).Value = objXLBirth.Cells(intRow,i).Value
End If
Next
i=15
'Cover text inserter
If Not objXLBirth.Cells(intRow, i).Value = "" Then
objXLCal.Cells(2, 50).Value = objXLBirth.Cells(intRow, i).Value
End If
'Month text inserter
For i = 16 To 27
If Not objXLBirth.Cells(intRow,i).Value = "" Then
txtStr = objXLBirth.Cells(1,i).Value
srcMonth = monthRet(Mid(txtStr,5))
k=1
Do Until objXLCal.Cells(k, 2).Value = srcMonth
k=k+1
Loop
If Asc(objXLBirth.Cells(intRow, i).Value)=63 Then
objXLCal.Cells(k, 48).Value = StrReverse(objXLBirth.Cells(intRow, i).Value)
Else
objXLCal.Cells(k, 48).Value = objXLBirth.Cells(intRow, i).Value
End If
End If
Next
i=28
'Birthday inserter
Do Until objXLBirth.Cells(intRow,i).Value = ""
formatdate=FormatDateTime(objXLBirth.Cells(intRow,i),2)
Call birthday (formatdate,i,intRow)
i=i+2
Loop
'saving changed calendar
objXLCal.ActiveWorkBook.SaveAs "C:\Users\liatte\Desktop\Aviv Omer Neta\Birthdays\Calendar_" & objXLBirth.Cells(intRow, 1).Value & ".txt", 42
intRow = intRow+1
Loop
'moving file to Success
'fso.MoveFile inputFolder, "C:\Users\liatte\Desktop\Success\"
'Next
objXLBirth.Quit
objXLCal.Quit
End Function
Another function:
Function monthRet(month)
Select Case month
Case "1"
monthRet="January"
Case "2"
monthRet="February"
Case "3"
monthRet="March"
Case "4"
monthRet="April"
Case "5"
monthRet="May"
Case "6"
monthRet="June"
Case "7"
monthRet="July"
Case "8"
monthRet="August"
Case "9"
monthRet="September"
Case "10"
monthRet="October"
Case "11"
monthRet="November"
Case "12"
monthRet="December"
End Select
End Function
Thank you very much!

Given a code layout like:
Sub birthday (formatDate, i, intRow)
...
wscript.echo objXLCal.Cells(k, 2).Value
...
End Sub
Function main(argFilePath)
...
Set objXLCal = CreateObject("Excel.Application")
...
End Function
main "C:\Users\liatte\Desktop\hotFolder\Input"
an "Object required" error for the WScript.Echo line is to be expected (the local variable objXLCal initialized in main isn't the same as the (therefore) uninitialized local variable objXLCal in birthday).
The correct solution would be to start with "Option Explicit" and follow the principles of decent procedural programming in VBScript, but the disgusting hack of Diming variables like objXLCal at the top/global level won't lower the quality of the published code.

Related

Excel VBA: parsing JSON

Hope somebody might able to help me.
I am a real rookie in this field, had a friend of mine write up the following code some time ago.
I have VB in Excel that gets data from a yahoo API, URL: "https://query2.finance.yahoo.com/v8/finance/chart/" & ticker & "?interval=1m&range=1d"
The data gets inserted in excel and is auto-refreshed every minute.
Everything works smoothly with no issues.
Now to the challange, since the data gets auto purged after a day in the excel, I would need to extend the amount of data (rows) from the current 1 day to 7 days.
So I tried simply to change the URL from the above mentioned to the following:
"https://query2.finance.yahoo.com/v8/finance/chart/" & ticker & "?interval=1m&range=7d"
However the parsing in the code gives me errors which I am to bad at solving..
First warning comes in the code:
"Case Else: If token(p + 1) <> ":" Then dic.Add key, token(p)"
And the whole code is as below (feel free to try it in excel if you would like), thanks in advance.
Option Explicit
Private p&, token, dic
Function ParseJSON(json$, Optional key$ = "obj") As Object
p = 1
token = Tokenize(json)
Set dic = CreateObject("Scripting.Dictionary")
If token(p) = "{" Then ParseObj key Else ParseArr key
Set ParseJSON = dic
End Function
Function ParseObj(key$)
Do: p = p + 1
Select Case token(p)
Case "]"
Case "[": ParseArr key
Case "{": ParseObj key
Case "{"
If token(p + 1) = "}" Then
p = p + 1
dic.Add key, "null"
Else
ParseObj key
End If
Case "}": key = ReducePath(key): Exit Do
Case ":": key = key & "." & token(p - 1)
Case ",": key = ReducePath(key)
Case Else: If token(p + 1) <> ":" Then dic.Add key, token(p)
End Select
Loop
End Function
Function ParseArr(key$)
Dim e&
Do: p = p + 1
Select Case token(p)
Case "}"
Case "{": ParseObj key & ArrayID(e)
Case "[": ParseArr key
Case "]": Exit Do
Case ":": key = key & ArrayID(e)
Case ",": e = e + 1
Case Else: dic.Add key & ArrayID(e), token(p)
End Select
Loop
End Function
Function Tokenize(s$)
Const Pattern = """(([^""\\]|\\.)*)""|[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?|\w+|
[^\s""']+?"
Tokenize = RExtract(s, Pattern, True)
End Function
Function RExtract(s$, Pattern, Optional bGroup1Bias As Boolean, Optional bGlobal As Boolean = True)
Dim c&, m, n, v
With CreateObject("vbscript.regexp")
.Global = bGlobal
.MultiLine = False
.IgnoreCase = True
.Pattern = Pattern
If .TEST(s) Then
Set m = .Execute(s)
ReDim v(1 To m.Count)
For Each n In m
c = c + 1
v(c) = n.Value
If bGroup1Bias Then If Len(n.submatches(0)) Or n.Value = """""" Then v(c) = n.submatches(0)
Next
End If
End With
RExtract = v
End Function
Function ArrayID$(e)
ArrayID = "(" & e & ")"
End Function
Function ReducePath$(key$)
If InStr(key, ".") Then ReducePath = Left(key, InStrRev(key, ".") - 1) Else ReducePath = key
End Function
Function ListPaths(dic)
Dim s$, v
For Each v In dic
s = s & v & " --> " & dic(v) & vbLf
Next
Debug.Print s
End Function
Function GetFilteredValues(dic, match)
Dim c&, i&, v, w
v = dic.keys
ReDim w(1 To dic.Count)
For i = 0 To UBound(v)
If v(i) Like match Then
c = c + 1
w(c) = dic(v(i))
End If
Next
ReDim Preserve w(1 To c)
GetFilteredValues = w
End Function
Function GetFilteredTable(dic, cols)
Dim c&, i&, j&, v, w, z
v = dic.keys
z = GetFilteredValues(dic, cols(0))
ReDim w(1 To UBound(z), 1 To UBound(cols) + 1)
For j = 1 To UBound(cols) + 1
z = GetFilteredValues(dic, cols(j - 1))
For i = 1 To UBound(z)
w(i, j) = z(i)
Next
Next
GetFilteredTable = w
End Function
Function OpenTextFile$(f)
With CreateObject("ADODB.Stream")
.Charset = "utf-8"
.Open
.LoadFromFile f
OpenTextFile = .ReadText
End With
End Function
Function toUnix(dt) As Long
toUnix = DateDiff("s", "1/1/1970 00:00:00", dt)
End Function
Function fromUnix(ts) As Date
fromUnix = DateAdd("s", ts, "1/1/1970 00:00:00")
End Function
Private Sub GetData()
' Queue next invocation
Application.OnTime Now + TimeValue("00:01:00"), "GetData"
Dim DataSheet As Worksheet
Set DataSheet = Sheets("Data")
Dim ParameterSheet As Worksheet
Set ParameterSheet = Sheets("Parameters")
Dim scrape As String
scrape = ParameterSheet.Range("B2").Value
If scrape <> "TRUE" Then
Exit Sub
End If
Dim ticker As String
ticker = ParameterSheet.Range("A2").Value
Dim url As String
url = "https://query2.finance.yahoo.com/v8/finance/chart/" & ticker & "?interval=1m&range=1d"
Dim hReq As Object
Set hReq = CreateObject("MSXML2.XMLHTTP")
With hReq
.Open "GET", url, False
.Send
End With
Dim json As Object
Set json = ParseJSON(hReq.ResponseText)
Dim closes As Variant
closes = GetFilteredValues(json, "*.close*")
Dim opens As Variant
opens = GetFilteredValues(json, "*.open*")
Dim volumes As Variant
volumes = GetFilteredValues(json, "*.volume*")
Dim highs As Variant
highs = GetFilteredValues(json, "*.high*")
Dim lows As Variant
lows = GetFilteredValues(json, "*.low*")
Dim timestamps As Variant
timestamps = GetFilteredValues(json, "*.timestamp*")
Dim i As Integer
i = UBound(timestamps) + 1
Dim row As Integer
row = 2
' Load new data in
Dim timestamp As Variant
For Each timestamp In timestamps
i = i - 1
timestamp = Int(timestamps(i) / 60) * 60
If "null" = closes(i) Then
GoTo Continue
End If
If DataSheet.Range("H" & row).Value = "" Then
' Empty dataset
ElseIf toUnix(DataSheet.Range("H" & row).Value) < timestamp Then
' There is new data, prepend
DataSheet.Rows(row).Insert
ElseIf toUnix(DataSheet.Range("H" & row).Value) = timestamp Then
' Replace old data,
Else: GoTo Continue
End If
DataSheet.Range("B" & row).Value = ticker
DataSheet.Range("C" & row).Value = opens(i)
DataSheet.Range("D" & row).Value = highs(i)
DataSheet.Range("E" & row).Value = lows(i)
DataSheet.Range("F" & row).Value = closes(i)
DataSheet.Range("G" & row).Value = volumes(i)
DataSheet.Range("H" & row).Value = fromUnix(timestamp)
row = row + 1
Continue:
Next timestamp
' Remove data that is more then 10 days old
row = 1
Do While True
row = row + 1
Dim datee As Variant
datee = DataSheet.Range("H" & row).Value
If datee = "" Then
Exit Do
End If
If toUnix(datee) + 864000 < toUnix(Now()) Then
DataSheet.Rows(row).EntireRow.Delete
row = row - 1 ' This prevents skipping the next line
End If
Loop
End Sub
Private Sub Auto_Open()
GetData
End Sub
Problem is the parsing code cannot deal with the multiple trading periods which in the JSON are arrays within arrays [[{}],[{}],[{}]] when the range is greater than 1 day. The array index counter e is reset at each opening bracket so you get identical keys for each trading period. Dictionary keys must be unique hence the error. The best solution would be to rewrite using a modern parser but as a quick-fix hack the ParseArr function as follows ;
Function ParseArr(key$)
'Dim e& move to top of script
' add this line
If InStr(1, key, "tradingPeriods") = 0 Then e = 0
Do: p = p + 1
' no change to this code
Loop
End Function

keep the solution in VBA

i am trying to get the frequency of terms within a collection of variable length strings.The context is descriptions in an Access database. Would prefer to keep the solution in VBA. Delimiter is " " (space) character
Dim db As DAO.Database
Set db = CurrentDb()
Call wordfreq
End Sub
Function wordfreq()
Dim myCol As Collection
Dim myArray() As String
Dim strArray As Variant
Dim strDescr, strTerm, strMsg As String
Dim i, j As Integer
Set myCol = New Collection
strDescr = "here it should accept the table and display the result in seperate table"
' db.Execute "select columns from table"
myArray = Split(strDescr, " ")
For Each strArray In myArray
On Error Resume Next
myCol.Add strArray, CStr(strArray)
Next strArray
For i = 1 To myCol.Count
strTerm = myCol(i)
j = 0
For Each strArray In myArray
If strArray = strTerm Then j = j + 1
Next strArray
'placeholder
strMsg = strMsg & strTerm & " --->" & j & Chr(10) & Chr(13)
Next i
'placeholder
'save results into a table
MsgBox strMsg
End Function
See an example below using a Scripting.Dictionary object.
Function wordfreq()
Dim objDict As Object
Dim myArray() As String
Dim strInput As String
Dim idx As Long
Set objDict = CreateObject("Scripting.Dictionary")
strInput = "here it should accept the table and display the result in seperate table"
myArray = Split(strInput, " ")
For idx = LBound(myArray) To UBound(myArray)
If Not objDict.Exists(myArray(idx)) Then
'Add to dictionary with a count of 1
objDict(myArray(idx)) = 1
Else
'Increment counter
objDict(myArray(idx)) = objDict(myArray(idx)) + 1
End If
Next
'Test it
Dim n As Variant
For Each n In objDict.Keys
Debug.Print "Word: " & n, " Count: " & objDict(n)
Next
End Function
Output:
'Word: here Count: 1
'Word: it Count: 1
'Word: should Count: 1
'Word: accept Count: 1
'Word: the Count: 2
'Word: table Count: 2
'Word: and Count: 1
'Word: display Count: 1
'Word: result Count: 1
'Word: in Count: 1
'Word: seperate Count: 1
Edit
The process:
Loop through the Input recordset.
Split the Description into words.
Check if the word exist in Dictionary and add or
increment.
Add the Keys (words) and Values (count) of the aforementioned
Dictionary to the Output table.
To achieve this two helper functions have been set up:
One loops through the description recordset and returns a
Dictionary object filled with unique words as Keys and their
count as Values.
The other takes the above Dictionaryobject and adds it to the Output table.
You need to change [TABLE] to the name of your Input and Output tables.
Option Explicit
Sub WordsFrequency()
On Error GoTo ErrTrap
Dim rs As DAO.Recordset
Set rs = CurrentDb().OpenRecordset("SELECT Description FROM [TABLE] WHERE Description Is Not Null;", dbOpenSnapshot)
If rs.EOF Then GoTo Leave
With rs
.MoveLast
.MoveFirst
End With
If AddDictionaryToTable(ToDictionary(rs)) Then
MsgBox "Completed successfully.", vbInformation
End If
Leave:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
On Error GoTo 0
Exit Sub
ErrTrap:
MsgBox Err.Description, vbCritical
Resume Leave
End Sub
' Returns Scripting.Dictionary object
Private Function ToDictionary(rs As DAO.Recordset) As Object
Dim d As Object 'Dictionary
Dim v As Variant 'Words
Dim w As String 'Word
Dim i As Long, ii As Long 'Loops
Set d = CreateObject("Scripting.Dictionary")
For i = 1 To rs.RecordCount
v = Split(rs![Description], " ")
For ii = LBound(v) To UBound(v)
w = Trim(v(ii))
If Not d.Exists(w) Then d(w) = 1 Else d(w) = d(w) + 1
Next
rs.MoveNext
Next
Set ToDictionary = d
End Function
' Adds Dictionary object to table
Private Function AddDictionaryToTable(objDict As Object) As Boolean
On Error GoTo ErrTrap
Dim rs As DAO.Recordset
Dim n As Variant
Set rs = CurrentDb().OpenRecordset("[TABLE]")
With rs
For Each n In objDict.Keys
.AddNew
.Fields("Words").Value = n
.Fields("Counts").Value = objDict(n)
.Update
Next
End With
'all good
AddDictionaryToTable = True
Leave:
If Not rs Is Nothing Then rs.Close
Set rs = Nothing
On Error GoTo 0
Exit Function
ErrTrap:
MsgBox Err.Description, vbCritical
Resume Leave
End Function

Runtime Error 3061 too few parameters expected 1 DAO declarations

I have been looking for some code that creates a calendar year and will take data from a table and place it in the corresponding date on the calendar. I found some code online (from an older version of access) that pretty much fit the bill, with some modifications it does exactly what I need it to do. Originally, the code pulled data from one table and it was set up to run on the current year. I use two queries, qr_SafetyCal and qr_SafetyCal2, to refine data from the one table. The first query prioritizes the data and eliminates multiple events on any given day. The second query uses the results from the first and specifies the year in the query criteria.
The code works flawlessly as long as I set the year criteria in the qr_SafetyCal2 and specify the first day, ex. 1/1/2017 (datStart) in the underlying code of the calendar year I want displayed.
After getting the code squared away I created a pop up form the user to select the year for the report but when I run the report I get the following error, Runtime Error 3061 too few parameters expected 1.
From what I have been able to research, I believe I changed the dynamic of the code when I referenced the form in the query criteria that the DAO Recordset Used.
As I understand it, the criteria in the query is not passed to the rs and therefore needs to be declared in the code. What I can't figure out is how to declare the variables in the code through reference to the form. I hope that makes some sense to somebody, long explanation but hard to describe something you don't understand.
Below is all the code and you will see some things I've rem'd out that I have tried but did not work. Any help would be greatly appreciated. I apologize ahead of time if the code is not formatted correctly.
Option Compare Database
Option Explicit
Private m_strCTLLabel As String
Private m_strCTLLabelHeader As String
Private colCalendarDates As Collection
Function getCalendarData() As Boolean
Dim rs As DAO.Recordset
Dim strDate As String
Dim strCode As String
Dim i As Integer
'Dim qdf As DAO.QueryDef
'Set qdf = CurrentDb.QueryDef("qr_SafetyCal2")
'qdf.Parameters("[Forms]![fr_SafetyCal]![cboYear]") = [Forms]![fr_SafetyCal]![cboYear]
'Set rs = qdf.OpenRecordset("qr_SafetyCal2", dbOpenDynaset)
Set rs = CurrentDb.OpenRecordset("qr_SafetyCal2", dbOpenDynaset)
Set colCalendarDates = New Collection
With rs
If (Not .BOF) Or (Not .EOF) Then
.MoveLast
.MoveFirst
End If
If .RecordCount > 0 Then
For i = 1 To .RecordCount
strDate = .Fields("Date")
strCode = .Fields("ShortName")
colCalendarDates.Add strCode, strDate
.MoveNext
Next i
End If
.Close
End With
'Return of dates and data collection form qr_SafetyCal2
Set rs = Nothing
End Function
Public Sub loadReportYearCalendar(theReport As Report)
Dim i As Integer
Dim datStart As Date
Dim rptControl As Report
m_strCTLLabel = "labelCELL"
m_strCTLLabelHeader = "labelDAY"
'Load calendar data for the specified year into the collection
Call getCalendarData
With theReport
'Get the first month of the specified year
datStart = "1/1/2017" '"1/1/" & Year(Date), "1/1/" & Forms!
[fr_SafetyCal]![cboYear], Forms![fr_SafetyCal]![txtCalYear]
'Add the specified year to the report's label
.Controls("labelCalendarHeaderLine2").Caption = Year(datStart) & "
iCalendar"
For i = 1 To 12
'Set pointer to subreport control hosting the mini-calendar
Set rptControl = .Controls("childCalendarMonth" & i).Report
'Run procedure to populate control with it's respective year
Call loadReportCalendar(rptControl, datStart)
'Reset and obtain first day of the following month
datStart = DateAdd("m", 1, datStart)
Next i
End With
'Clean up
Set colCalendarDates = Nothing
Set rptControl = Nothing
End Sub
Public Sub loadReportCalendar(theReport As Report, Optional StartDate As
Date, Optional theHeaderColor As Variant)
Dim i As Integer
Dim intCalDay As Integer
Dim datStartDate As Date
Dim intWeekDay As Integer
datStartDate = StartDate
intWeekDay = Weekday(datStartDate)
With theReport
.Controls("labelMONTH").Caption = Format(StartDate, "mmmm")
'Change the day label's backcolor if necessary
If Not (IsMissing(theHeaderColor)) Then
For i = 1 To 7
.Controls("labelDayHeader" & i).BackColor = theHeaderColor
Next
End If
For i = 1 To 42
With .Controls(m_strCTLLabel & i)
If (i >= intWeekDay) And (Month(StartDate) =
Month(datStartDate)) Then
If (datStartDate = Date) Then
.BackColor = 14277081
End If
On Error Resume Next
Dim strCaption As String
Dim strKey As String
strKey = datStartDate
strCaption = ""
strCaption = colCalendarDates.Item(strKey)
colCalendarDates.Remove strKey
'Set back color to grean on days in the past that have
no corresponding event
If (datStartDate < Date) And (strCaption = vbNullString) Then
.Caption = Day(datStartDate)
.Bold = False
.BackColor = vbGreen
.ForeColor = vbWhite
.Heavy = True
'Do not set a back color for days in the future
ElseIf (datStartDate > Date) And (strCaption = vbNullString) Then
.Caption = Day(datStartDate)
.Bold = False
'Set the corresponding labels and formats for each specified event
Else
.Caption = strCaption
.Bold = True
Select Case strCaption
Case "FA"
.BackColor = vbYellow
.ForeColor = 0
.LeftMargin = 0
.TextAlign = 2
Case "FAM"
.BackColor = vbYellow
.ForeColor = 0
.LeftMargin = 0
.TextAlign = 2
.Heavy = True
Case "LTA"
.BackColor = vbRed
.ForeColor = vbWhite
.LeftMargin = 0
.TextAlign = 2
Case "MED"
.BackColor = vbRed
.ForeColor = vbWhite
.LeftMargin = 0
.TextAlign = 2
End Select
End If
datStartDate = DateAdd("d", 1, datStartDate)
Else
.Caption = ""
End If
End With
Next i
End With
End Sub
Here is SQL for the two queries, the first is qr_SafetyCal and the second is qr_SafetyCal2:
SELECT tb_CaseLog.Date, Max(tb_Treatment.Priority) AS MaxOfPriority,
Count(tb_Treatment.TreatmentID) AS CountOfTreatmentID
FROM tb_Treatment INNER JOIN tb_CaseLog ON tb_Treatment.TreatmentID =
tb_CaseLog.Treatment
GROUP BY tb_CaseLog.Date;
SELECT qr_SafetyCal.Date, tb_Treatment.ShortName,
qr_SafetyCal.CountOfTreatmentID AS [Count], Year([Date]) AS CalYear
FROM qr_SafetyCal INNER JOIN tb_Treatment ON qr_SafetyCal.MaxOfPriority =
tb_Treatment.Priority;
No need to reference QueryDef.
Open the recordset object with filtered dataset by referencing the combobox like:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE CalYear=" & [Forms]![fr_SafetyCal]![cboYear], dbOpenDynaset)
or if the code is behind the form:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE CalYear=" & Me.[cboYear], dbOpenDynaset)
Both examples assume the field is a number type.
If there is no field in query with the year value, it can be extracted from date value field in the VBA construct:
Set rs = CurrentDb.OpenRecordset("SELECT * FROM qr_SafetyCal2 WHERE Year([YourFieldnameHere])=" & [Forms]![fr_SafetyCal]![cboYear], dbOpenDynaset)
Code for setting datStart variable:
'Get the first month of the specified year
datStart = "1/1/" & Forms![fr_SafetyCal].[cboYear]

VBscript - Transpose CSV File

Does anyone have a short script in VBscript for transposing a Matrix (given as CSV (comma separated values) file)?
A, 1, 2, 3
B, 7, 5, 6
->
A, B
1, 7
2, 5
3, 6
Many Thanks in advance
Tom
So by creating dynamic arrays and auto-increment their growth in parallel with discovering new columns of the original matrix, you can auto build the new data structure quite quickly.
Const OutputCSV = "C:\op.csv"
Dim dt_start, WriteOutput : dt_start = Now
Dim fso : Set fso = CreateObject("Scripting.FileSystemObject")
Dim file : Set file = fso.OpenTextFile("C:\test.csv", 1, True)
Set WriteOutput = fso.OpenTextFile(OutputCSV, 8, True)
Dim fc : fc = file.ReadAll : file.close : Dim fcArray : fcArray = Split(fc, vbCrLf)
WScript.echo "Before Transpose"
WScript.echo "----------------"
WScript.echo fc
WScript.echo "----------------"
Dim opArray() : ReDim opArray(0)
For Each row In fcArray
Dim tmp: tmp = Split(row, ",")
For ent=0 To UBound(tmp)
If ent > UBound(opArray) Then
ReDim Preserve opArray(UBound(opArray)+1)
opArray(ent) = Trim(tmp(ent))
Else
If Len(opArray(ent)) > 0 Then
opArray(ent) = opArray(ent) & "," & Trim(tmp(ent))
Else
opArray(ent) = Trim(tmp(ent))
End If
End If
Next
Next
Dim dt_end : dt_end = Now
WScript.echo "After Transpose"
WScript.echo "----------------"
WScript.echo Join(opArray, vbCrLf)
WScript.echo "----------------"
WScript.echo "Script Execution Time (sec): " & DateDiff("s", dt_start, dt_end)
WriteOutput.Write Join(opArray, vbCrLf) : WriteOutput.Close
If it's just two lines with an equal number of values, you can read both into arrays using the Split function:
a1 = Split(FileIn.ReadLine, ",")
a2 = Split(FileIn.ReadLine, ",")
Then, iterate the arrays and write each element:
For i = 0 To UBound(a1)
FileOut.WriteLine a1(i) & ", " & a2(i)
Next
I'm assuming you know how to open files for reading and writing?
Edit: It sounds like you may have an unknown number of rows to read. In that case, you can use an array of arrays:
Dim a(255) ' Hold up to 255 rows. Adjust as needed. Or use ReDim Preserve to grow dynamically.
Do Until FileIn.AtEndOfStream
a(i) = Split(FileIn.ReadLine, ",")
i = i + 1
Loop
Then, to write:
For j = 0 To UBound(a(0))
' Concatenate the elements into a single string...
s = ""
For k = 0 To i - 1
s = s & a(k)(j) & ","
Next
' Write the string without the final comma...
FileOut.WriteLine Left(s, Len(s) - 1)
Next

In VBA, how does one make a table from a recordset

I have a recordset that I want to export into Excel 2000 format (acSpreadsheetTypeExcel9). I believe I need to drop it into a table first then execute a DoCmd.TransferSpreadsheet (keeps it easy and it works). The user sets just a few parameters in the form, thus the Me. syntax you will see.
Here's the working code so far:
Select Case Me.Controls("frame_ChooseReport").Value
Case 1
sExecuteQuery = "qry_PDSR w/ Destruct Dates"
bHasProgramCode = True
sFileName = "Project_Doc_Submittal_Request_better"
Case 2
sExecuteQuery = "qry_PDSR w/Destruct Dates BE"
bHasProgramCode = False 'This is the only query here that doesn't have a Program Code parameter
sFileName = "Project_Doc_Submittal_Request_better_BE"
Case 3
sExecuteQuery = "qry_Project Documentation Submittal Request w/ Destruct Dates"
bHasProgramCode = True
sFileName = "Project_Doc_Submittal_Request_ENH"
Case 4
sExecuteQuery = "qry_Project_Doc_Submittal_Request_w_Destruct_Dates_HES_Installer"
bHasProgramCode = True
sFileName = "Project_Doc_Submittal_Request_Installer"
Case Else
Stop 'Error! This should never be reached!
End Select
'Execute query & save output to Excel
Set qdf = CurrentDb.QueryDefs(sExecuteQuery) 'Open the query
'Assign values to the query using the parameters option
If bHasProgramCode = True Then
qdf.Parameters(0) = Me.lbl_ProgramCodes.Section
qdf.Parameters(1) = Me.txt_StartDate
qdf.Parameters(2) = Me.txt_EndDate
Else
qdf.Parameters(0) = Me.txt_StartDate
qdf.Parameters(1) = Me.txt_EndDate
End If
sFullPath = Me.lbl_SaveTo.Caption & "\" & sFileName
Set rst = qdf.OpenRecordset 'Convert the querydef to a recordset and run it
If rst.BOF = True And rst.EOF = True Then
MsgBox "No records were found.", vbExclamation, "Empty recordset"
Exit Sub
End If
'Dump recordset into a table, export it to Excel, then delete it.
'Here is where the recordset needs to become a table.
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "qry_PDSR w/ Destruct Dates", sFullPath, True 'Export table to an Excel format
'Clean up!
DoCmd.DeleteObject acTable, gTEMP_TBL 'Done with the temporary table so delete it
rst.Close
qdf.Close
Set rst = Nothing
Set qdf = Nothing
Help/suggestions? Thank you.
Access 2010 in Windows 7
---------- FOLLOW UP ----------
Here's the query I added that will use the references of the opened form per Remou's suggestion:
SELECT dbo_PROJECT.PROJECTID, dbo_PROJECT.TITLE, dbo_PROJECT.PROGRAMCODE, dbo_PROJECT.PROJECTTYPE, dbo_PROJECT.REFERENCE, dbo_PROJECT.STATUS, dbo_PROJECT.PMC, dbo_TRANSACTION_SUM.STATUS, dbo_TRANSACTION_SUM.IMPORTEDDT, dbo_TRANSACTION_SUM.CHECKDT, dbo_PROJECT.NOTES, dbo_TRANSACTION_SUM.TRANSACTIONID, dbo_TRANSACTION_SUM.GL_ACCT, dbo_PROJECT_SUM.PAID_INCENT_TOTAL, dbo_TRANSACTION_SUM.AMOUNT
FROM ((dbo_INCENTIVE RIGHT JOIN dbo_PROJECT ON dbo_INCENTIVE.PROJECTID = dbo_PROJECT.PROJECTID) LEFT JOIN dbo_TRANSACTION_SUM ON dbo_INCENTIVE.INCENTIVEID = dbo_TRANSACTION_SUM.INCENTIVEID) LEFT JOIN dbo_PROJECT_SUM ON dbo_PROJECT.PROJECTID = dbo_PROJECT_SUM.PROJECTID
WHERE (((dbo_PROJECT.PROGRAMCODE) In ([Forms]![Submittal_Request_Report]![txt_ListProgramCodeSelections])) AND ((dbo_TRANSACTION_SUM.CHECKDT) Between [Forms]![Submittal_Request_Report]![txt_StartDate] And [Forms]![Submittal_Request_Report]![txt_EndDate]));
Here's the routine that is in the On_Exit event of the listbox:
Private Sub list_ProgramCodes_Exit(Cancel As Integer)
'Get selection from Program Code listbox and store it in a hidden textbox for the query.
Dim x As Long, sValue As String, ctlSource As Control
sValue = ""
Set ctlSource = Me!list_ProgramCodes
For x = 0 To ctlSource.ListCount - 1
If ctlSource.Selected(x) Then
sValue = sValue & ctlSource.Column(0, x) & ","
End If
Next
Me.txt_ListProgramCodeSelections.Value = Left(sValue, Len(sValue) - 1) 'Drop the last comma
Set ctlSource = Nothing
End Sub
Works great! The SQL line In ([Forms]![Submittal_Request_Report]![txt_ListProgramCodeSelections]) pulls the list of items in the hidden textbox (using a label didn't work) that was populated with the selection from the listbox on the form.
This is now the code for exporting the query:
Private Sub btn_RunReport_Click()
Dim sExecuteQuery As String, sFullPath As String, sFileName As String
On Error GoTo Err_btn_RunReport_Click
If Left(Me.lbl_SaveTo.Caption, 4) = "save" Then
MsgBox "Please select a folder to save the results to.", vbInformation, "No folder selected"
Exit Sub
End If
Select Case Me.Controls("frame_ChooseReport").Value
Case 1
sExecuteQuery = "qry_PDSR_Destruct_Dates_form"
sFileName = "Project_Doc_Submittal_Request.xls"
Case 2
sExecuteQuery = "qry_Project_Doc_Submittal Request w/ Destruct Dates_form"
sFileName = "Project_Doc_Submittal_Request_ENH.xls"
Case 3
sExecuteQuery = "qry_PDSR_w_Destruct_Dates_HES_Installer_form"
sFileName = "Project_Doc_Submittal_Request_Installer.xls"
Case Else
Stop 'Error! This should never be reached!
End Select
sFullPath = Me.lbl_SaveTo.Caption & "\" & sFileName
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, sExecuteQuery, sFullPath, True 'Export table to an Excel format
Exit_btn_RunReport_Click:
Exit Sub
Err_btn_RunReport_Click:
MsgBox Err.Description
Resume Exit_btn_RunReport_Click
End Sub
Thanks Remou!
I suggest you just set the sql of a query to a suitable string and then export the query:
sSQL="SELECT * FROM Table WHERE Field=" & me.MyText
If IsNull(DLookup("name", "msysobjects", "name='query1'")) Then
CurrentDb.CreateQueryDef "Query1", sSQL
Else
CurrentDB.QueryDefs("Query1").SQL = sSQL
End If
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "Query1", sFullPath
You can create a query that references an open form:
SELECT Test.ID, Test.Data
FROM Test
WHERE Test.AField=[forms]![test]![pickone]