VBA SQL string saving short date as General date instead of short - sql

I'm trying to do something basic:
Take 2 dates [startD] and [endD] from a accdb file.
Move them forward one month each
save the new dates as short dates in the respective record.
I'm doing this all by VBA
The issue is that it is showing the correct SQL String (if i do msgbox sql) however when it saves, it is saving as a general date with time and is the wrong value!
*Note: I'm in Australia so I have a format section to make sure the date saves correctly.
I have tried using DateValue() and Formatting the date too.
Dim frq As Integer
Dim wks As Integer
Dim CurAcc As Integer
Dim CurAccEnd As Date
Dim Days As Integer
Dim curaccvalue As Currency
Dim cardtype As Integer
Dim cardcharged As Integer
cardtype = 0
cardcharged = 0
CurAcc = Me.ID
curraccvalue = DLookup("Acccurvalue", "Accounts", "[ID] = " & CurAcc)
Curraccend = DLookup("Accend", "Accounts", "[ID] = " & CurAcc)
frq = DLookup("freqid", "Accounts", "[ID] = " & CurAcc)
wks = DLookup("freqvalue", "tblfrequency", "FrequencyID = " & frq)
Days = wks * 7
strsql = "UPDATE Accounts SET AccStart = " & Date & " , AccEND = " &
Curraccend + Days & " , AccCurValue = 0.00 WHERE ID = " & CurAcc
MsgBox strsql
DoCmd.RunSQL strsql

When implicitly converting a date to a string, your regional settings are used, but in a SQL string, a date must be in the American format.
To avoid this, I suggest to do the update in just one query:
Dim strSql As String
strSql = "UPDATE Accounts " & _
"INNER JOIN tblfrequency ON Accounts.freqid = tblfrequency.FrequencyID SET " & _
"AccStart = Date(), " & _
"AccEND = DateAdd(""w"", tblfrequency.freqvalue, Accounts.Accend), " & _
"AccCurValue = 0.00 WHERE ID = " & Me.ID
MsgBox strSql
DoCmd.RunSQL strSql

Related

VBA ACCESS - SQL statement which Counting between 2 columns which are variables

I need a macro in VBA Access. I have a table with all dates of the years like columns (and also the dates are the names of the fields). I've made a form where the user selects two dates, and the macro would count all the data between these 2 columns.
For the example, I put two fixed dates. The problem is I need count between the 2 columns, and the columns can change depending the input of the user. The table is EVOLUTIVO_ASISTENCIA and the field can change depends the user selection. Ihe following code EVOLUTIVO_ASISTENCIA.[" & INICIO_MES_VAR1 & "] is the field "01-01-2023" of the EVOLUTIVO_ASISTENCIA table, but the syntax is wrong and does not function. Can anyone help me?
The code:
Private Sub BUSQUEDA()
Dim CONTEO As String
Dim VAR1 As String
Dim INICIO_MES_VAR1 As Date, TERMINOS_MES_VAR1 As Date
INICIO_MES_VAR1 = Format("01-01-2023", "dd-mm-yyyy")
TERMINOS_MES_VAR1 = Format("31-01-2023", "dd-mm-yyyy")
VAR1 = "VAR1"
CONTEO = "SELECT COUNT(*) FROM EVOLUTIVO_ASISTENCIA " & _
"WHERE EVOLUTIVO_ASISTENCIA.[NOMBRES]='" & VAR1 & "' " & _
** "BETWEEN EVOLUTIVO_ASISTENCIA.[" & INICIO_MES_VAR1 & "] AND EVOLUTIVO_ASISTENCIA.[" & TERMINOS_MES_VAR1 & "]"**
DoCmd.RunSQL CONTEO
End Sub
You don't run a select query, you open it as a recordset. So try:
Private Sub BUSQUEDA()
Dim Records As DAO.Recordset
Dim CONTEO As String
Dim VAR1 As String
Dim INICIO_MES_VAR1 As String
Dim TERMINOS_MES_VAR1 As String
Dim ASISTENCIA_CONTEO As Long
INICIO_MES_VAR1 = "01-01-2023"
TERMINOS_MES_VAR1 = "31-01-2023"
VAR1 = "VAR1"
CONTEO = "SELECT COUNT(*) FROM EVOLUTIVO_ASISTENCIA " & _
"WHERE EVOLUTIVO_ASISTENCIA.[NOMBRES]='" & VAR1 & "' " & _
"BETWEEN EVOLUTIVO_ASISTENCIA.[" & INICIO_MES_VAR1 & "] AND EVOLUTIVO_ASISTENCIA.[" & TERMINOS_MES_VAR1 & "]"
Set Records = CurrentDb.OpenRecordset(CONTEO)
' Read/list/print records.
' Retrieve the value of the first and only field of the first and only record.
ASISTENCIA_CONTEO = Records(0).Value
' Close when done.
Records.Close
End Sub

Date filter returns an invalid character error

I want to execute a query with a date filter in Access VBA.
My first issue was inconsistent datatypes: expected DATE got NUMBER.
I assume Access stores dates as numbers just like Excel.
I found I had to use "#" between the date for the query to recognize it as a DATE. Now I am getting an INVALID CHARACTER error which means the hash # is an invalid character.
I have to pull in the negotiated costs with our vendors that don't have more than 60 days of being expired.
There is also a tblVendors where the user selects the vendor ID (ORDID) they want to pull the info from. That's why I do a loop to pull in every ORDID in that table. I don't push in all the ORDID in one try because it brings a lot of data and doing it in batches runs faster.
Sub GetMaterialCost()
Dim db As Database
Dim rsData As ADODB.Recordset, rsVendor As DAO.Recordset, rsItemCost As DAO.Recordset
Dim strQuery As String
Dim vendorNO As Long, dtDate As Date
Set db = CurrentDb
dtDate = Format(Now() - 60, "m/d/yyyy")
Set rsVendor = db.OpenRecordset("SELECT ORDID, VEN_NAME, USER_ID FROM tblVendors WHERE ACTIVE = TRUE ORDER BY VEN_NAME, ORDID")
Set rsItemCost = db.OpenRecordset("tbl_ItemCost")
ConnectBILL
rsVendor.MoveFirst
Do Until rsVendor.EOF
strQuery = "SELECT MASID, LOCATION, ITEM, ITEM_QTY, ITEM_UOM, ITEM_COST, EXP_DT " _
& "FROM ITEMMASTER INNER JOIN ORDDETAIL ON (ITEMMASTER.ITEM = ORDDETAIL.ITEM) " _
& "WHERE (LOCATION IN (AS1,AS3,AS6) AND TRIM(MASID) = '" & Cstr(rsVendor.Fields("ORDID")) & "' AND EXP_DT >= #paramDate)"
With ComBill
.CommandText = strQuery
Set rsData = .Execute(, Array(dtDate))
end with
'clears previous instance of vendor data by vendor_no if it exists
db.Execute "DELETE * FROM tbl_ItemCost WHERE MASID LIKE '*" & rsVendor.Fields("ORDID") & "*'"
'starts inserting queried data
rsData.MoveFirst
Do Until rsData.EOF
With rsItemCost
.AddNew
.Fields("MASID") = rsData!MASID
.Fields("LOCATION") = rsData!LOCATION
.Fields("ITEM") = rsData!ITEM
.Fields("ITEM_UOM") = Trim(rsData!ITEM_UOM)
.Fields("ITEM_COST") = rsData!ITEM_COST
.Fields("EXP_DT") = rsData!EXP_DT
.Update
End With
rsData.MoveNext
Loop
rsVendor.MoveNext
Loop
End Sub
Correct these two lines:
dtDate = DateAdd("d", -60, Date)
& "WHERE LOCATION IN (AS1,AS3,AS6) AND TRIM(MASID) = '" & CStr(rsVendor.Fields("ORDID") & "' AND EXP_DT >= #" & Format(dtDate, "yyyy\/mm\/dd") & "#) "
Note, that for ADO, string expressions for date values must be formatted using the ISO sequence.
If the field EXP_DT is Text:
& "WHERE LOCATION IN (AS1,AS3,AS6) AND TRIM(MASID) = '" & CStr(rsVendor.Fields("ORDID") & "' AND EXP_DT >= '" & Format(dtDate, "m\/d\/yyyy") & "') "

How do you find if a record exists?

Dim mydb As DAO.Database
Dim myrst As DAO.Recordset
Dim Date1, Date2 As Date
Dim mysql As String
Dim qdf As QueryDef
Dim EmployeeID As String
EmployeeID = DLookup("lngEmpID", "tblEmployees", "Forms!frmEmployeeOrderForm.cboEmployeeName.Value = EmployeeName")
Me.EmpID = EmployeeID
PickupTime = DLookup("Pickup", "tblEmployees", "Forms!frmEmployeeOrderForm.cboEmployeeName.Value = EmployeeName")
Me.PickupDay = PickupTime
Set mydb = CurrentDb
Date1 = Me.dtmGiveAwayDate1
Date2 = Me.dtmGiveAwayDate2
mysql = ("Select tblOrders.lngEmpID, tblOrders.dtmGiveAwayDate1, tblOrders.dtmGiveAwayDate2 FROM tblOrders WHERE tblOrders.lngEmpID =" & EmployeeID & " AND tblOrders.dtmGiveAwayDate1 =" & Date1 & " AND tblOrders.dtmGiveAwayDate2 =" & Date2)
MsgBox mysql
Set myrst = mydb.OpenRecordset(mysql)
If myrst.EOF = False Then
MsgBox "You have already ordered for this PFG." & vbCrLf & "Please see Jody for help."
cmdCancel_Click
Exit Sub
End If
When I run the program I am trying to prevent employees from entering their name twice for the same dates. To test I tried to duplicate a record for the same employee and it will not trigger the myrst.eof = false and display the message box that says "You have already ordered for this PFG". Any help is much appreciated.
Thank you in advance.
Use the FindFirst method :
myrst.FindFirst "field = " & value
If myrst.NoMatch Then
//code when record doesn't exist
End If
Checking for equality with dates can be tricky. Since VBA dates can include time to the nanosecond, could it be that one side (SQL/code) has a real time, while the other has the default midnight value?
Set mydb = CurrentDb
Date1 = Format(Me.dtmGiveAwayDate1, "Short Date")
Date2 = Format(Me.dtmGiveAwayDate2, "Short Date")
mysql = ("Select tblOrders.lngEmpID, tblOrders.dtmGiveAwayDate1, tblOrders.dtmGiveAwayDate2 FROM tblOrders WHERE tblOrders.lngEmpID =" & EmployeeID & " AND tblOrders.dtmGiveAwayDate1 =" & "#" & Date1 & "#" & " AND tblOrders.dtmGiveAwayDate2 =" & "#" & Date2 & "#")
MsgBox mysql
Set myrst = mydb.OpenRecordset(mysql)
This was the code I used and it works now. Thank you.

date as name of field not recognized in ms access

I have fields which have as name a the date of delivery, as you can see here:
I have around 75 columns like that. I have a bug when I want to compute the value P1 because it does not find the field. BTW, I have very stranges values for my coefficients T1, T2 (which are dates) and thus A and B which are datediff. There is the code:
Sub vcm_fc()
Dim db As Database, T As Date, longest As Integer, nearest_date As Date, rsb As DAO.Recordset, strsqlb As String
Dim strsqla As String, rsa As Recordset, maturity As Date, T1 As Date, T2 As Date, P1 As Double, P2 As Double
Dim a As Integer, B As Integer, j As Integer, rsc As DAO.Recordset, strqlc As String, settlementbis As String
Dim settlement As String, maturitybis As Date, ym As Integer, ymbis As Integer
Set db = CurrentDb()
T = DateSerial(2020, 8, 15)
nearest_date = DFirst("PricingDate", "fc_historical")
longest = DateDiff("m", nearest_date, T)
db.Execute "CREATE TABLE time_series " _
& "(PricingDate CHAR);"
db.Execute " INSERT INTO time_series " _
& "SELECT PricingDate " _
& "FROM fc_historical " _
& "ORDER BY PricingDate;"
For i = 1 To longest
db.Execute " ALTER TABLE time_series " _
& "ADD COLUMN F_" & i & " Number;"
strsqla = "SELECT PricingDate, F_" & i & " FROM time_series ORDER BY PricingDate"
Set rsa = db.OpenRecordset(strsqla, dbOpenDynaset)
rsa.MoveFirst
rsa.Delete 'delete the first row which is blank when the time series table is created'
rsa.MoveFirst
While (Not rsa.EOF())
rsa.Edit
maturity = DateAdd("m", i, rsa.Fields("PricingDate").Value)
ym = Year(maturity) - 2000
settlement = "1/" & Month(maturity) & "/" & ym
strsqlb = "SELECT Pricingdate, " & settlement & " FROM fc_historical ORDER BY PricingDate;"
Set rsb = db.OpenRecordset(strsqlb, dbOpenDynaset)
rsb.MoveLast
T1 = rsb.Fields("PricingDate").Value
maturitybis = DateAdd("m", i, maturity)
ymbis = Year(maturitybis) - 2000
settlementbis = "1/" & Month(maturitybis) & "/" & ymbis
strsqlc = "SELECT Pricingdate, " & settlementbis & " FROM fc_historical ORDER BY PricingDate;"
Set rsc = db.OpenRecordset(strsqlc, dbOpenDynaset)
rsc.MoveLast
T2 = rsc.Fields("PricingDate").Value
a = DateDiff("d", T1, rsa.Fields("PricingDate").Value)
B = DateDiff("d", rsa.Fields("PricingDate").Value, T2)
P1 = rsb.Fields(settlement).Value
P2 = rsc.Fields(settlementbis).Value
rsa.Fields("F_" & i) = (P1 * B + P2 * a) / (a + B)
rsa.Update
rsa.MoveNext
Wend
Next i
End Sub
Have added as an answer so I can get the format for the code. This code will take your date field names and place them as record values - you may need to muck around with the fld.Name to make sure it isn't US date format (8th Jan, 9th Jan, etc for your table example) along with the price for that date.
Sub Put_Field_Names_As_Record_Values()
Dim DB As DAO.Database
Dim OldTable As DAO.TableDef
Dim fld As DAO.Field
Set DB = CurrentDb()
Set OldTable = DB.TableDefs("time_series")
DoCmd.SetWarnings False
For Each fld In OldTable.Fields
If IsDate(fld.Name) Then
Debug.Print fld.Name & " : " & SQLDate(fld.Name)
DoCmd.RunSQL "INSERT INTO MyNewTable (PricingDate, SettlementDate, Price) " & _
"SELECT PricingDate," & SQLDate(fld.Name) & ", [" & fld.Name & "] FROM time_series"
End If
Next fld
DoCmd.SetWarnings True
End Sub
Function SQLDate(varDate As Variant) As String
'Purpose: Return a delimited string in the date format used natively by JET SQL.
'Argument: A date/time value.
'Note: Returns just the date format if the argument has no time component,
' or a date/time format if it does.
'Author: Allen Browne. allen#allenbrowne.com, June 2006.
If IsDate(varDate) Then
If DateValue(varDate) = varDate Then
SQLDate = Format$(varDate, "\#mm\/dd\/yyyy\#")
Else
SQLDate = Format$(varDate, "\#mm\/dd\/yyyy hh\:nn\:ss\#")
End If
End If
End Function
You can then run queries on the table:
SELECT SUM(Price)
FROM MyNewTable
WHERE PricingDate<=#07/16/2014# AND SettlementDate=#01/08/2014#
Edit: Test on a copy of your database!!
Edit 2: Manually create the MyNewTable and set PricingDate and SettlementDate as key fields.
I've updated to convert the field name into the correct date - http://allenbrowne.com/ser-36.html
On my test it converted all dates to the first of each month correctly.
Use properly formatted date expressions:
settlementbis = "#" & CStr(ymbis) & "/" & CStr(Month(maturitybis)) & "/1#"
And do listen to Darren about normalisation.

Passing Parameter Value in Access Query using vba

Our requirement -
We have few suppliers and we want to generate a monthly report of purchases from each supplier during the month and export to excel. I think the solution is to create a parameter query where I can pass the value of the supplier ID, Month and Year. The list of supplier keeps changing and is stored in a separate table.
So, basically, I should be able to sequentially read the supplier ID from that table and pass as a parameter to my query to generate the report for that supplier.
The closest solutions that I found for my requirement was on (which are similar in nature) -
Exporting Recordset to Spreadsheet
http://answers.microsoft.com/en-us/office/forum/office_2010-customize/filtering-a-query-used-by-docmdtransferspreadsheet/06d8a16c-cece-4f03-89dc-89d240436693
Why I think there could be a better solution -
In the suggested solution, we are creating multiple queries and deleting these. Conceptually, I feel there should be a way to create a parameter query and use the do while loop to sequentially pass the value of the parameter (DeptName in above example) to the query and export the results to excel.
I should be able to achieve this if I can use vba to pass value to a parameter query. And that is what I have not yet been able to figure out.
Update on 24-Feb -
Following is the code that I have written -
Private Sub Monthly_Supplier_Sales_Report_Click()
Dim strDirectoryPath As String
Dim DateFolderName As String
DateFolderName = Format$((DateSerial(year(Date), month(Date), 1) - 1), "YYYY MM")
strDirectoryPath = "C:\dropbox\Accounting\Sales Reports\" & DateFolderName
If Dir(strDirectoryPath, vbDirectory) = "" Then MkDir strDirectoryPath
Dim Filename As String
Dim strSQL1 As String
Dim strSQL2 As String
Dim DesignerCode As String
Dim month1 As String
Dim year1 As Integer
Dim Query1 As DAO.QueryDef
Dim query2 As DAO.QueryDef
Dim rsDesigner As DAO.Recordset
Set rsDesigner = CurrentDb.OpenRecordset("Designer Details Master")
Do While Not rsDesigner.EOF
DesignerCode = rsDesigner![Designer Code]
month1 = "Jan" 'right now hardcoded, will call this programatically
year1 = 2014 'right now hardcoded, will call this programatically
strSQL1 = "SELECT * FROM [Sales Report Generation Data] WHERE [designer code] = '" & DesignerCode & "' AND [Shipping Month]= '" & month1 & "' AND [Shipping Year]=" & year1
strSQL2 = "SELECT * FROM [Sales Report Generation - Monthwise Inventory Snapshot] WHERE [designer code] = '" & DesignerCode & "' AND [Snapshot Month]= '" & month1 & "' AND [Snapshot Year]= " & year1
Set Query1 = CurrentDb.CreateQueryDef(Name:="TempSalesQuery", SQLText:=strSQL1)
Set query2 = CurrentDb.CreateQueryDef(Name:="TempInventoryQuery", SQLText:=strSQL2)
Filename = strDirectoryPath & "\" & DesignerCode & Format$(Now(), " yyyy mm") & ".xls"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "TempSalesQuery", Filename, False, "Sales Report"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "TempInventoryQuery", Filename, False, "Inventory"
CurrentDb.QueryDefs.Delete "TempSalesQuery"
CurrentDb.QueryDefs.Delete "TempInventoryQuery"
rsDesigner.MoveNext
Loop
End Sub
Instead, The logic I want to apply is -
Do While Not
assign Value to Parameter 1 = rsDesigner![Designer Code]
assign Value to Parameter 2 = Month1
assign Value to Parameter 3 = Year1
Run the two Parameter queries, for which about three parameters are the input value and export to excel in respective sheets.
Loop
Just that I have not yet been able to figure out - how to achieve this.
Here is one solution. Note that I created Functions that the two queries will use.
Just create your two queries and save them (see sample SQL below), add your code to pick dates and everything should be fine.
Option Compare Database
Option Explicit
Dim fvShipMonth As String
Dim fvShipYear As Integer
Dim fvDesignerCode As String
Public Function fShipMonth() As String
fShipMonth = fvShipMonth
End Function
Public Function fShipYear() As Integer
fShipYear = fvShipYear
End Function
Public Function fDesignerCode() As String
fDesignerCode = fvDesignerCode
End Function
Private Sub Monthly_Supplier_Sales_Report_Click()
Dim Filename As String
Dim strSQL1 As String
Dim strSQL2 As String
Dim DesignerCode As String
Dim month1 As String
Dim year1 As Integer
Dim rsDesigner As DAO.Recordset
'SAMPLE SQL
'SELECT * FROM [Sales Report Generation Data] " & _
'WHERE [designer code] = '" & fDesignerCode() & "' AND [Shipping Month]= '" & fShipMonth() & "' AND [Shipping Year]=" & fShipYear()
fvShipMonth = "Jan"
fvShipYear = 2014
Set rsDesigner = CurrentDb.OpenRecordset("Designer Details Master")
Do While Not rsDesigner.EOF
fvDesignerCode = rsDesigner![Designer Code]
Filename = strDirectoryPath & "\" & DesignerCode & Format$(Now(), " yyyy mm") & ".xls"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "<your Query 1>", Filename, False, "Sales Report"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "<your Query 2>", Filename, False, "Inventory"
rsDesigner.MoveNext
Loop
rsDesigner.Close
Set rsDesigner = Nothing
End Sub
Open your database
Create a NEW module
Paste the following code
Place your cursor inside Function TEST_MY_CODE()
Press F5
Paste the results from the immediate window in your response.
Option Compare Database
Option Explicit
Dim fvShipMonth As String
Dim fvShipYear As Integer
Dim fvDesignerCode As String
Public Function fShipMonth() As String
fShipMonth = fvShipMonth
End Function
Public Function fShipYear() As Integer
fShipYear = fvShipYear
End Function
Public Function fDesignerCode() As String
fDesignerCode = fvDesignerCode
End Function
Function TEST_MY_CODE()
My_Click_EVENT ' Test the code I provided
End Function
Private Sub My_Click_EVENT()
Dim month1 As String
Dim year1 As Integer
fvShipMonth = "Jan"
fvShipYear = 2014
Debug.Print "**** START TEST ****"
Debug.Print "fvShipMonth = " & fvShipMonth
Debug.Print "fvShipYear = " & fvShipYear
Debug.Print "fShipMonth() = " & fShipMonth()
Debug.Print "fShipYear() = " & fShipYear()
Debug.Print "**** END TEST ****"
End Sub