Requerying subform only work sometimes - ms-access

I am trying to requery a subform which diplays customer details.
I am sure my sql works as the subform works fine when not influenced by the main form.
Private Sub btnSearch_Click()
Dim sql As String
sql = "SELECT tblCustomer.[Job ID], tblCustomer.[Customer Name], tblCustomer.[Street Name], tblCustomer.Area, tblAppointments.[Appointment Date] " _
& "FROM tblCustomer " _
& "LEFT JOIN tblAppointments ON tblCustomer.[Job ID] = tblAppointments.[Job Number].Value " _
& "WHERE [Customer Name] LIKE '*" & Me.txtKeywords & "*'" _
& "OR [Job ID] LIKE '*" & Me.txtKeywords & "*'" _
& "OR [Street Name] LIKE '*" & Me.txtKeywords & "*'" _
& "OR [Area] LIKE '*" & Me.txtKeywords & "*'" _
& "OR [Appointment Date] LIKE '*" & Me.txtKeywords & "*'" _
& "ORDER BY tblAppointments.[Appointment Date];"
Me.subCustomerList.Form.RecordSource = sql
Me.subCustomerList.Form.Requery
End Sub
The debugger shows an error at the following line:
Me.subCustomerList.Form.RecordSource = sql
I also get the error message
object or class does not support set of events

Consider parameterization with a stored query for several reasons in your case:
Helps avoid syntax issues like what you may have since Access will not allow you to save a query with syntax errors if using the GUI query designer;
Better maintainability than a concatenated SQL string which requires single/double quote enclosure and you abstract data from code;
The Access engine compiles stored queries to best execution plan so will be more efficient than a VBA called SQL string (i.e., use index on JOIN).
SQL (save as a query object with parameter to be referenced by name in VBA)
PARAMETERS txtKeywordsParam TEXT(255);
SELECT c.[Job ID], c.[Customer Name], c.[Street Name], c.Area, a.[Appointment Date]
FROM tblCustomer c
LEFT JOIN tblAppointments a ON c.[Job ID] = a.[Job Number]
WHERE c.[Customer Name] LIKE txtKeywordsParam
OR c.[Job ID] LIKE txtKeywordsParam
OR c.[Street Name] LIKE txtKeywordsParam
OR c.[Area] LIKE txtKeywordsParam
OR a.[Appointment Date] LIKE txtKeywordsParam
ORDER BY a.[Appointment Date];
VBA
Private Sub btnSearch_Click()
Dim qdef As QueryDef
Dim rst As Recordset
' OPEN QUERY AND BIND PARAM
Set qdef = CurrentDb.QueryDefs("mySavedParamQuery")
qdef!txtKeywordsParam = "*" & Me.txtKeyword & "*"
' ASSIGN QUERY RESULT TO RECORDSET
Set rst = qdef.OpenRecordset()
' APPLY RECORDSET TO FORM
Set Me.subCustomerList.Form.Recordset = rst
Set qdef = Nothing
End Sub

I created a new subform and copied the one that did not work and everything seems to be running well.

Related

MsAccess MsgBox to pull last record as a string

I am trying to create a button that will show the user the last lot, product code and qty that was saved to the database.
I am not sure how to write this in VBA, in other languages there are ways to view the last record by the method Bottom or Max.
I am trying to pull the data from column Product where the User column is equal to Environ("USERNAME") and the ID column has its max value.
Table to pull from is Data_Log.
Been looking around, but just no luck yet. Thanks!
You can try something like this:
Private Sub cmdShowLastData_Click()
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("select * from Data_Log where [User]='" & _
Environ("USERNAME") & "' and [ID]=" & DMax("ID", "Data_Log", "[User]='" & Environ("USERNAME") & "'"))
MsgBox "Last product: " & rst!Product & vbCrLf & _
"Last product code: " & rst!ProductCode & vbCrLf & _
"Last product qty: " & rst!Qty
rst.Close
Set rst = Nothing
End Sub
An alternative to Sergeys solution, using TOP 1:
strSql = "SELECT TOP 1 * FROM Data_Log WHERE [User]='" & Environ("USERNAME") & "' " & _
"ORDER BY ID DESC"
Set rst = CurrentDb.OpenRecordset(strSql)
The rest is the same.

query a query in VBA

Hi guys I dont know if this makes sense but how can I query another query in VBA?
I will show with example below
This is my first query
strSQL1 = "SELECT DISTINCT SourceBank" _
& ", Fullname, FirstNames" _
& ", Surname, Company" _
& ", EmailAddress" _
& " FROM question" _
& " WHERE FirstNames = '" & strFirstNames & "'" _
Set rs = dbs.OpenRecordset(strSQL)
Then I want to do something like this. Query the first query
strSQL2 = "S"SELECT * from " & strSQL1
Set rs1 = dbs.OpenRecordset(strSQL)
I just want to know if this is possible and if not then what is the best way around it?
All I want to do is to be able to query another query/string/recordset.
thanks
You can do it almost like you've wrote:
strSQL2="SELECT * FROM (" & strSQL1 & ")"
but be sure not to include ; in strSQL1
upd, try:
strSQL2 = "SELECT Question.EmailAddress, SUBQUERY.EmailAddress &" _
& "FROM Question LEFT JOIN (" & strSQL1 & ") AS SUBQUERY ON Question.EmailAddress = SUBQUERY.EmailAddress"
OR just save sql1 into QueryDef (Query in ms access) and use it like source table.

VBA Access - Multiple Tables count by date

We'd like to count from an Access database that has multiple tables - about 50.
We need to count from 1 column in each table that is 'QCPASS' This is a check box - if a product passed the box was checked if failed then not. We need to count both for EACH table, also allowing the user to specify a date range from a date column that exists in every table.
I've tried this with a query but I am told the query is unable to select, count and do the date range. Any VBA help would be great.
Exporting to Excel would be great, but any results would be fine. Here is the query I created that counts in a column from each table passes and failures. I can't iterate with a query either, so VBA seems the way to go:
SELECT "Table1" , Count('qcpass') AS column
FROM 5000028
GROUP BY [5000028].qcpass
union
SELECT "Table2",count('qcpass')
FROM 5000029
Group By [5000029].qcpass;
You can traverse the full TableDefs collection in your database, and create a query using VBA.
A word of warning: The TableDefs collection has the Access database system tables, so you need to skip this. A way I suggest you is to check for a specific table name prefix (it is noted in the code below).
public sub createMyBigUnionQuery()
dim db as DAO.database(), tbl as DAO.tableDef
dim strSQL as string, i as integer
set db = currentdb()
i = 1
for each tbl in db.TableDefs
if left(tbl.name, 1) = "5" then ' Check for a table name prefix
if i = 1 then
' The final spaces are important
strSQL = "select '" & tbl.Name & "' as table, count(qcpass) as column " & _
"from [" & tbl.Name & "] " & _
"group by qcpass "
else
' The final spaces are important
strSQL = strSQL & " union all " & _
"select '" & tbl.Name & "' as table, count(qcpass) as column " & _
"from [" & tbl.Name & "] " & _
"group by qcpass "
end if
i = i + 1
end if
next tbl
db.createQueryDef "qryYourFinalQuery", strSQL
db.close
exit sub
Notice that you can define any valid query you want. Take this as a hint, and tweak it to fit your specific needs.
Hope this helps you
Adressing #HansUp comment, if you need to filter your data by date, you have two options:
Include the where condition on every select created by the procedure
Include the date field in your query and group by it, and create a second query to filter the data you need from the created query.
I would personally go with option 1, and here is a sample code:
public sub createMyBigUnionQueryWithDates(d0 as date, d1 as date)
dim db as DAO.database(), tbl as DAO.tableDef
dim strSQL as string, i as integer
set db = currentdb()
i = 1
for each tbl in db.TableDefs
if left(tbl.name, 1) = "5" then ' Check for a table name prefix
if i = 1 then
' The final spaces are important
strSQL = "select '" & tbl.Name & "' as table, count(qcpass) as column " & _
"from [" & tbl.Name & "] " & _
"where rowDate between " & cDbl(d0) & " and " &cDbl(d1) & " " & _
"group by qcpass "
else
' The final spaces are important
strSQL = strSQL & " union all " & _
"select '" & tbl.Name & "' as table, count(qcpass) as column " & _
"from [" & tbl.Name & "] " & _
"where rowDate between " & cDbl(d0) & " and " &cDbl(d1) & " " & _
"group by qcpass "
end if
i = i + 1
end if
next tbl
db.createQueryDef "qryYourOtherFinalQuery", strSQL
db.close
exit sub
The reason I use cDbl(d0) is because Access dates are sensitive to regional settings, and I've had a lot of headaches dealing with it. Access (and many other Microsoft products) store dates as floating-point numbers (the integer part is the date, and the decimal part is the time).
Another word of warning: If your dates don't include time, then the between condition will work. But if they do include time, then I recommend you change the where condition to this:
"where rowDate >= " & cDbl(d0) & " and rowDate < " & cDbl(d1 + 1)"

Crosstab query with date criteria

I have created a crosstab query as below
TRANSFORM Nz(Sum([debit]*[GeneralExpenses]),0) AS mOmomeya
SELECT Expenses.sName, Expenses.ArName
FROM (GL INNER JOIN Expenses ON GL.ID = Expenses.glID) INNER JOIN Transactions ON GL.GL = Transactions.GL
GROUP BY Expenses.sName, Expenses.ArName
PIVOT Month([ddate]);
what I want to do is to add a criteria to the [dDate] field from a form text input to match the date that I entered, but I received error while doing this as below
any idea what's wrong?
Hmmm, there definitely seems to be something a little bit different about crosstab queries. The straight SELECT query...
SELECT expenses.*
FROM expenses
WHERE (((expenses.ddate) Between [Forms]![main]![DateFrom] And [Forms]![main]![DateTo]));
...works fine, but the crosstab query...
TRANSFORM Sum(expenses.expenses) AS SumOfexpenses
SELECT expenses.onduty
FROM expenses
WHERE (((expenses.ddate) Between [Forms]![main]![DateFrom] And [Forms]![main]![DateTo]))
GROUP BY expenses.onduty
PIVOT Month(ddate);
...fails with the error message you cited. One workaround would be to rebuild the SQL for the query before using it:
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.QueryDefs("yourCrosstab")
qdf.SQL = _
"TRANSFORM Nz(Sum([debit]*[GeneralExpenses]),0) AS mOmomeya " & _
"SELECT Expenses.sName, Expenses.ArName " & _
"FROM (GL INNER JOIN Expenses ON GL.ID = Expenses.glID) INNER JOIN Transactions ON GL.GL = Transactions.GL " & _
"WHERE (((ddate) " & _
"Between #" & Format(CDate([Forms]![main]![DateFrom]), "yyyy-mm-dd") & "# " & _
"And #" & Format(CDate([Forms]![main]![DateTo]), "yyyy-mm-dd") & "#)) " & _
"GROUP BY Expenses.sName, Expenses.ArName " & _
"PIVOT Month(ddate);"
Set qdf = Nothing
DoCmd.OpenQuery "yourCrosstab" '' or whatever you want to do with it
The problem is that crosstab querys require the form parameter for each form. Right click on gray space and select parameter. Put in the forms and data type.

Fastest way of looping in recordset

I have a VB6 application. I have 2 recordsets having the same number of records (almost 50k). Now I have to loop 50k*50k *(number of fields). Can any one tell me the fastest way to do so?
Thanks in advance.
As others have pointed out it is not a good idea to do this client side but here are a few pointers for speeding up recordset access.
Open the recordset as forward only (adOpenForwardOnly) and if you are not writing then read only also.
Refer to the fields by number so instead of doing rs.Fields(“MyField”) you would use rs.Fields(0)
If you are writing back to the database then consider wrapping things up in a transaction to speed things up.
When looping use “Do until rs.EOF” instead of counting records.
Thats all I can think of for now but they should help a bit
There really is no fastest way to do this in vb6.
You'd use 2 for loops.
You might want to give us more details as to why you are pulling down 50k records (twice) and comparing each field. This is usually an indication that something needs to be done on the database side but was brought in to the client side to be solved.
If your two databases are the same and the only difference is the data, you could do something like this (pseudo-code):
SELECT t1.A, t2.A, t2.B, t2.B, ...
FROM t1
INNER JOIN t2 on t1.id = t2.id
WHERE (t1.A <> t2.A) OR (t1.B <> t2.B) OR ...
t1 and t2 would be your two tables. This isn't the most efficient but it would allow you to do the comparisons very easily. Also, you could get more complicated with what you show in the SELECT statement. Currently it is just a listing of both columns side by side.
Having clarified that you've got two Access databases you need to compare, the easiest is to link the two together and then compare with a query.
Right-click the white empty space, Link tables.
Locate you second DB, select the table in it.
Now you can write a query to compare the two. The data being compared is always up to date as it's being pulled through the link.
I have written code to compare and synchronize two data tables many, many times, and I've posted about it here on SO. The key is to use SQL to limit the results to the records that don't match, but the chief insight is to write your on-the-fly SQL ONE COLUMN AT A TIME. With a WHERE clause on each of your SQL statements, this will be much more efficient than any other comparison method.
Within Access, I've written this code to update one table from another. It assumes the tables have the same fields and that there's a PK field that actually identifies the same record in both tables. The code has a dependency on my SQLRun() function to actually execute the SQL, but that line could be replaced with CurrentDB.Execute if you don't want that.
Public Function UpdateTableData(ByVal strSourceTable As String, _
ByVal strTargetTable As String, ByVal strJoinField As String, _
ByRef db As DAO.Database, Optional ByVal strExcludeFieldsList As String, _
Optional ByVal strUpdatedBy As String = "Auto Update", _
Optional strAdditionalCriteria As String) As Boolean
Dim strUpdate As String
Dim rsFields As DAO.Recordset
Dim fld As DAO.Field
Dim strFieldName As String
Dim strNZValue As String
Dim strSet As String
Dim strWhere As String
strUpdate = "UPDATE " & strTargetTable & " INNER JOIN " & strSourceTable _
& " ON " & strTargetTable & "." & strJoinField & " = " _
& strSourceTable & "." & strJoinField
' if the fields don't have the same names in both tables,
' create a query that aliases the fields to have the names of the
' target table
' if the source table is in a different database and you don't
' want to create a linked table, create a query and specify
' the external database as the source of the table
' alternatively, for strTargetTable, supply a SQL string with
' the external connect string
Set rsFields = db.OpenRecordset(strSourceTable)
For Each fld In rsFields.Fields
strFieldName = fld.Name
If strFieldName <> strJoinField Or (InStr(", " & strExcludeFieldsList _
& ",", strFieldName & ",") <> 0) Then
Select Case fld.Type
Case dbText, dbMemo
strNZValue = "''"
Case Else
strNZValue = "0"
End Select
strSet = " SET " & strTargetTable & "." & strFieldName & " = _
varZLSToNull(" & strSourceTable & "." & strFieldName & ")"
strSet = strSet & ", " & strTargetTable & ".Updated = #" & Date & "#"
strSet = strSet & ", " & strTargetTable & ".UpdatedBy = " _
& STR_QUOTE & strUpdatedBy & STR_QUOTE
strWhere = " WHERE Nz(" & strTargetTable & "." & strFieldName & ", " _
& strNZValue & ") <> Nz(" & strSourceTable & "." & strFieldName _
& ", " & strNZValue & ")"
If db.TableDefs(strTargetTable).Fields(fld.Name).Required Then
strWhere = strWhere & " AND " & strSourceTable & "." _
& strFieldName & " Is Not Null"
End If
If Len(strAdditionalCriteria) > 0 Then
strWhere = strWhere & " AND " & strAdditionalCriteria
End If
Debug.Print strUpdate & strSet & strWhere
Debug.Print SQLRun(strUpdate & strSet & strWhere, dbLocal) & " " _
& strFieldName & " updated."
End If
Next fld
Debug.Print dbLocal.OpenRecordset("SELECT COUNT(*) FROM " _
& strTargetTable & " WHERE Updated=#" & Date & "# AND UpdatedBy=" _
& STR_QUOTE & strUpdatedBy & STR_QUOTE)(0) _
& " total records updated in " & strTargetTable
rsFields.Close
Set rsFields = Nothing
UpdateTableData = True
End Function
try to use the algorithm of sql., the left and right join., then apply it in vb..,
i also have the same problem with you but i try that solution and it works.., on first, it takes almost 3 hours the complete the query but when i apply the sql algo, it just takes few minis