Option Compare Database
Public Function StandardReportExcel()
Dim objXL As Excel.Application
Dim XLWB As Excel.Workbook
Dim XLWS As Excel.Worksheet
Dim strSQL As String
Dim rsData As DAO.Recordset
Dim intMaxRecordCount As Integer
Dim intMaxColCount As Integer
Dim sngTimer As String
Dim sngTotalTime As Single
Dim blnTestMode As Boolean
Dim strNewReportPath As String ' for directory to save
Dim intWorksheetNum As Integer
Dim intRowNumber As Integer
Dim intColumnNumber As Integer
Dim intRowPos As Integer
Dim VBQuote As String ' move this to global later
Dim intHeaderColCount As Integer
Dim intMaxheaderColCount As Integer
Dim strSaveAsFileName As String ' the name with time stamp to save this report
Dim rnOmrade As Range
Dim vaData As Variant
Dim i As Integer
Dim StartTimer As Long
Dim StopTimer As Long
Dim TotalTime As Long
' In Access, set a reference to Microsoft Excel Applicaiton - This code can be put into a code module and called from a click event
On Error GoTo PROC_ERROR
VBQuote = Chr$(34) ' will add this to global later - for now just trying to get code into production in 4 minute window
On Error Resume Next
On Error GoTo PROC_ERROR
50 strNewReportPath = "m:\StandardReport" ' your path may vary
' ----------- Set objects in Excel
100 StartTimer = Timer
DoEvents
110 blnTestMode = True ' ------- change to false for production ------
On Error GoTo 0
120 If objXL Is Nothing Then
130 Set objXL = New Excel.Application
140 objXL.EnableEvents = False
150 Else
160 Excel.Application.Quit
170 Set objXL = New Excel.Application
180 objExcel.EnableEvents = False
End If
On Error GoTo PROC_ERROR
201 objXL.Visible = True ' Change to FASLE for final Production! this is for debugging
210 objXL.Workbooks.Add
220 'objXL.Worksheets.Add
230 intWorksheetNum = 1
235 'objXL.Visible = False
240 intRowPos = 1
250 objXL.Worksheets(intWorksheetNum).Cells(intRowPos, 1) = "Created: " & Now()
260 objXL.Worksheets(intWorksheetNum).Name = "StdRpt"
' --- Create Query in variable
630 ' Create an query in Access, then past your SQL below. This code is here to help understand the parsing and the vbquotes in the query
' This creates the record set dynamically during run time. You don't need to store a query in Access.
640 strSQL = "SELECT Wells.Well_Name, Wells_Status1.Status1 AS Well_status, States.State, Wells_County.County, " & _
"ORDER_Status_1.ORDER_Status AS State_Status, ORDER_State.Dt_ORDER_Sub AS State_Sub, ORDER_State.Dt_ORDER_Apv AS State_Dt_App, " & _
"IIf(IsNull([State_Sub]) And IsNull([State_Dt_App])," & VBQuote & VBQuote & " ,IIf(IsNull([State_Dt_App])," & Chr(34) & "Pending" & Chr(34) & ",[State_Dt_App]-[State_sub])) AS St_No_Days, " & _
"ORDER_State.Dt_ORDER_Exp AS State_Dt_Expire, " & _
"ORDER_Status.ORDER_Status AS Fed_Status, ORDER_Fed.Dt_ORDER_Sub AS Fed_Sub, ORDER_Fed.Dt_ORDER_Apv AS Fed_Dt_App, " & _
"IIf(IsNull([Fed_Sub]) And IsNull([Fed_Dt_App])," & VBQuote & VBQuote & " ,IIf(IsNull([Fed_Dt_App])," & Chr(34) & "Pending" & Chr(34) & ",[Fed_Dt_App]-[Fed_sub])) AS Fed_No_Days, " & _
"ORDER_Fed.Dt_ORDER_Exp AS Fed_Dt_Expire " & _
"FROM Wells_Status1 INNER JOIN ((((States INNER JOIN Wells_County ON States.ID_State = Wells_County.ID_State) " & _
"INNER JOIN Wells ON Wells_County.ID_County = Wells.ID_County) " & _
"LEFT JOIN (ORDER_Status RIGHT JOIN ORDER_Fed ON ORDER_Status.ID_ORDER_Status = ORDER_Fed.ID_ORDER_Status) ON Wells.ID_Wells = ORDER_Fed.ID_Wells) " & _
"LEFT JOIN (ORDER_State LEFT JOIN ORDER_Status AS ORDER_Status_1 ON ORDER_State.ID_ORDER_Status = ORDER_Status_1.ID_ORDER_Status) " & _
"ON Wells.ID_Wells = ORDER_State.ID_Wells) ON Wells_Status1.ID_WellStatus1 = Wells.ID_WellsStatus1;"
'Debug.Print strSQL
650 Set rsData = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot) ' Snapshots are faster
660 intRowPos = 5 ' Sets starting Row for data in Excel - reference fields to this
670 objXL.Worksheets(intWorksheetNum).Cells(intRowPos, 1).CopyFromRecordset rsData ' copies snapshot into Excel
680 intMaxRecordCount = rsData.RecordCount - 1 ' - use for max rows returned in formatting later
' ------- Create Header in new Excel based on Query
700 intMaxheaderColCount = rsData.Fields.count - 1
710 For intHeaderColCount = 0 To intMaxheaderColCount
730 If Left(rsData.Fields(intMaxheaderColCount).Name, 3) <> "xxx" Then ' Future use - adding xxx in cross tab queries for fields to exclude
740 objXL.Worksheets(intWorksheetNum).Cells(intRowPos - 1, intHeaderColCount + 1) = rsData.Fields(intHeaderColCount).Name ' Relative to intRowPos
750 End If
760 Next intHeaderColCount
780 objXL.Rows((intRowPos - 1) & ":" & (intRowPos - 1)).Select ' Selection for Bold header column (can make 2 if needed)
790 objXL.Selection.Font.Bold = True
' Just a bunch of bloated formatting for the cells for beginners. Normally, this gets compressed using the With statement.
800 With objXL.Selection.Font
.Name = "Arial"
.Size = 12
.ThemeColor = xlThemeColorLight1
End With
With objXL.Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ThemeColor = 10
.TintAndShade = -0.499984740745262
.Weight = xlThick
End With
With objXL.Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlThick
End With
With objXL.Selection.Borders(xlInsideVertical)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlThick
End With
objXL.Rows("4:4").RowHeight = 24
objXL.Rows("4:4").RowHeight = 32.25
objXL.Rows("4:4").RowHeight = 25.5
With objXL.Selection.Borders(xlEdgeLeft)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Weight = xlThick
End With
With objXL.Selection.Borders(xlEdgeBottom)
.LineStyle = xlContinuous
.ThemeColor = 10
.TintAndShade = -0.499984740745262
.Weight = xlThick
End With
With objXL.Selection.Borders(xlEdgeRight)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.Weight = xlThick
End With
With objXL.Selection.Borders(xlInsideVertical)
.LineStyle = xlContinuous
.ColorIndex = xlAutomatic
.Weight = xlThick
End With
900 objXL.Cells.EntireColumn.AutoFit ' After the data and headers are completed, autofit the entire sheet to fit
910 DoEvents
' ------------------------- Omitted a bunch of customer headers ----------------
DoEvents
On Error Resume Next ' ------------------------ End Custom Headers ---------------------------------
' ------------------------ Start Column Formatting ----------------------------
' objXL.Selection.NumberFormat = "m/d/yyyy"
'objXL.Visible = True
' Any column that SQL uses formula to return number & text combination needs to be custom formated
' Column H and M returned numbers as "text" so the SubTotal function won't work. This converts Text to Numeric
' but also leaves the text words "pending" in place. It also keeps the blanks from turning into zeros that affects my Average function.
Set rnOmrade = objXL.ActiveSheet.Range(objXL.Range("H5"), objXL.Range("H6536").End(xlUp))
vaData = rnOmrade.Value
For i = 1 To UBound(vaData) ' data base record set returns "Pending", blank or a number
If (vaData(i, 1) = "Pending") Then
vaData(i, 1) = "Pending"
ElseIf ((vaData(i, 1) * 1) = 0) Then
vaData(i, 1) = ""
Else
vaData(i, 1) = vaData(i, 1) * 1
End If
'vaData(i, 1) = IIf(IsNumeric(vaData(i, 1) * 1), vaData(i, 1) * 1, vaData(i, 1))
Next i
Err.Clear ' one unknown variant type can mess up the whole array
rnOmrade.Value = vaData
Set rnOmrade = Nothing
Set rnOmrade = objXL.ActiveSheet.Range(objXL.Range("M5"), objXL.Range("M6536").End(xlUp))
vaData = rnOmrade.Value
For i = 1 To UBound(vaData) ' data base record set returns "Pending", blank or a number
If (vaData(i, 1) = "Pending") Then
vaData(i, 1) = "Pending"
ElseIf ((vaData(i, 1) * 1) = 0) Then
vaData(i, 1) = ""
Else
vaData(i, 1) = vaData(i, 1) * 1
End If
'vaData(i, 1) = IIf(IsNumeric(vaData(i, 1) * 1), vaData(i, 1) * 1, vaData(i, 1))
Next i
Err.Clear ' one unknown variant type can mess up the whole array
rnOmrade.Value = vaData
DoEvents
On Error GoTo PROC_ERROR
' More fancy formatting and the use of the AutoFilter
1700 objXL.Selection.Borders(xlInsideHorizontal).LineStyle = xlNone
'objXL.Rows("4:4").Select
1720 objXL.Rows((intRowPos - 1) & ":" & (intRowPos - 1)).Select ' based on relative position for where data starts above
objXL.Selection.AutoFilter ' --------------- Autofilter --------------- Autofilter -----------
' Need to set blank cells here for subTotal function to work
' copy recordset adds hidden text due to formula - use array to convert to numeric
' Subtotals added on header over specific columns based on your Query.
' In this case - the numeric data is on columns H and M
' This adds the subtotal function on the top that totals only visible rows after the autofilter is used.
' STATE number of Days formula
1900 objXL.Range("G1").Select
1910 objXL.ActiveCell.FormulaR1C1 = "Max Days"
1920 objXL.Range("G2").Select
1930 objXL.ActiveCell.FormulaR1C1 = "Average Days"
1940 objXL.Range("H1").Select
1050 objXL.ActiveCell.FormulaR1C1 = "=SUBTOTAL(104,R[4]C:R[579]C)"
1960 objXL.Range("H2").Select
1970 objXL.ActiveCell.FormulaR1C1 = "=SUBTOTAL(101,R[3]C:R[5798]C)"
' Federal number of days formula
2000 objXL.Range("L1").Select
2010 objXL.ActiveCell.FormulaR1C1 = "Max Days"
2020 objXL.Range("L2").Select
2030 objXL.ActiveCell.FormulaR1C1 = "Average Days"
2040 objXL.Range("M1").Select
2050 objXL.ActiveCell.FormulaR1C1 = "=SUBTOTAL(104,R[4]C:R[579]C)"
2060 objXL.Range("M2").Select
2070 objXL.ActiveCell.FormulaR1C1 = "=SUBTOTAL(101,R[3]C:R[5798]C)"
2090 StopTimer = Timer
2100 TotalTime = StopTimer - StartTimer
' Time stamp for Excel to be created, data to be retrieved
' My old computer takes 3 seconds to pull the data, create a custom spread sheet report and save it to disk
2110 objXL.Range("A2").Select
2120 objXL.ActiveCell.FormulaR1C1 = "Code Completed in " & CStr(Format(TotalTime, "0.00")) & " seconds"
2200 'objXL.Application.GoTo Reference:="NamedRange" ' create some named range to highlight before saving ' future
2210 objXL.Application.Calculation = xlAutomatic
2220 objXL.ActiveWorkbook.PrecisionAsDisplayed = False
' Future for security addition
2230 If CurrentUser <> "Admin" And CurrentUser <> "SomeUSERNAME" And blnTestMode = False Then
2240 objXL.ActiveWorkbook.SaveAs FileName:=strNewReportPath
2250 End If
2280 'objXL.ActiveWorkbook.SaveAs
2290 strSaveAsFileName = strNewReportPath & "\" & Year(Now()) & "-" & Month(Now()) & "-" & Day(Now()) & "-" & Hour(Now()) & "-" & Minute(Now()) & "-" & " Standard Report.xlsx"
2300 objXL.ActiveWorkbook.SaveAs FileName:=strSaveAsFileName
2320 objXL.Visible = True
2325 objXL.Application.Quit
' I don't let users look at it but a second. They can go find it saved on a drive and open it.
2330 MsgBox "Please open My Documents folder and find your Excel Standard Report named: " & strSaveAsFileName, vbOKOnly, "Testing new style Excel Report"
3010 Debug.Print sngTotalTime, "Code Completed in " & CStr(Format(sngTotalTime, "0.00")) & " sec."
PROC_EXIT:
10010 On Error Resume Next
10020 'objXL.ActiveWindow.Close False
10050 Set objXL = Nothing
11290 On Error Resume Next
11300 Exit Function
PROC_ERROR:
11310 Select Case Err.Number
'Case ###
Case Else
11320 'fLogError Err.Number, Erl, Err.Description, "basExcelBasisSummary", "MakeBaseload", True
' later - use central error funciton I designed
11330 'objXL.Quit
11340 'objXL.Close
11350 Resume PROC_EXIT
11370 End Select
End Function