I am trying to count the number of rows in sql query result using access 2007 vba.
What I have is a text box named AGN when a user put value on it check for this value then it bring back MsgBox if the the value is already inserted. What I try to do is :
Dim rs As DAO.Recordset
Dim db As Database
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT agencies.[agency no] FROM agencies WHERE agencies.[agency no]= " &Me.AGN.Text
Set rs = db.OpenRecordset(strSQL)
If rs.Fields.Count > 1 Then
MsgBox "this value is already here "
End If
Set rs = Nothing
When I insert any value on the textbox I got run time error 3061 (too few parameters)
The "too few parameters" error message generally means there is something in your SQL statement which Access doesn't recognize as a field, table, function or SQL keyword. In this case, it could happen if [agency no] is text rather than numeric data type. If that is the case, enclose the value of AGN with quotes when you build the SQL statement. (Or you could use a parameter query to avoid the need to quote the text value.)
strSQL = "SELECT a.[agency no] FROM agencies AS a" & vbCrLf & _
"WHERE a.[agency no]= '" & Me.AGN.Value & "'"
Debug.Print strSQL
In case of trouble, go to the Immediate window and copy the output from Debug.Print. Then you can create a new query in the Access query designer, switch to SQL View and paste in the statement text for testing.
Once your SELECT is working, you can check whether or not the recordset is empty. When it is empty both its BOF and EOF properties are true. So to detect when it is not empty, check for Not (BOF And EOF) ...
With rs
If Not (.BOF And .EOF) Then
MsgBox "this value is already here "
End If
End With
However you don't actually need to open a recordset to determine whether a matching row exists. You can check the value returned by a DCount expression.
Dim lngRows As Long
lngRows = DCount("*", "agencies", "[agency no]='" & Me.AGN.Value & "'")
If lngRows > 0 Then
MsgBox "this value is already here "
End If
Notes:
I used AGN.Value instead of AGN.Text because the .Text property is only accessible when the control has focus. But I don't know where you're using that checking code, so unsure which is the proper choice for you.
Notice the similarities between the SELECT query and the DCount options. It's often easy to translate between the two.
Related
How do I get an operator to work in a query criteria based on a form field. Ideally I would like it to be something like:
IIf([Afloat]="No",<[Forms]![DASF]![Text222],"")
When I remove the operator it finds anything exactly to the criteria in that field but the moment I try to put an operator like greater than or less than it does not work. I am trying to find all records less than the value in that form field.
Any advice on how I can fix this? Or is it not possible in MS Access?
QBF (Query By Form) can't accept operators in the formula. Your only option is to write the query on the fly. You can use the CreateQueryDef method to define the SQL in a specific query, and attach your form or report to the specific query name.
Something like:
Dim db as Database
Dim rec as Recordset
Dim qdf As QueryDef
Dim strSQL as String
Set db = CurrentDB
On Error Resume Next
'First, delete the query if it exists
db.QueryDefs.Delete "MyQueryName"
'Then, set up the query string
strSQL = "Select * From MyTable Where MyField < " & [Forms]![DASF]![Text222] & " and [Afloat] = 'No' "
strSQL = strSQL & "UNION "
strSQL = strSQL & "Select * From MyTable Where MyField = '' and [Afloat] <> 'No' "
'Now, recreate the query
Set qdf = db.CreateQueryDef("MyQueryName", strSQL)
DoCmd.OpenQuery qdf.Name
You could try changing the first criteria to:
>IIf([Afloat]="No",[Forms]![DASF]![Text222])
And then add a second criteria below it in the Or line:
=IIf([Afloat]<>"No","")
I ended up solving my problem by separating it into two separate queries. Below are my steps:
Instead of having a logical expression to decide I separated it into
FLOAT and NONFLOAT queries.
Then I created a command button to open
each query depending on the criteria in a combo box (yes or no).
Here is the code:
Private Sub Command2_Click()
DoCmd.SetWarnings False
If Me.Combo272 = "Yes" Then
DoCmd.OpenQuery "DASF_AGED_AS1_FLOAT", acViewNormal, acEdit
Else
DoCmd.OpenQuery "DASF_AGED_AS1_NONFLOAT", acViewNormal, acEdit
End If
End Sub
This created another problem, I was still unable to reference the txt boxes necessary for my query criteria. To solve this, I made all the text boxes unbound by using the below VBA to auto populate the text boxes based on another combo box. Here is the VBA I used:
Me.Text220 = DLookup("REGION", "TDD_TABLE", "[ID]= " & Me.Combo236)
I am trying to run the following SQL statement in ACCESS 2013 VBA but am getting errors due to wrong formatting (in this case I get "Semicolon (;) missing from end of statement"). Could anybody tell me what I am doing wrong in the code below please?
Dim dbs As dao.Database
Set dbs = CurrentDb()
dbs.Execute "INSERT INTO TEMP2 ([Study_Date], [Created_By], [Part_Number],
[Upper_Tolerance], [Lower_Tolerance], [ID21_Number]) VALUES ([Study_Date],
[Created_By], [Part_Number], [Upper_Tolerance], [Lower_Tolerance], [ID21_Number])
FROM RAC_DATA_ENTRY
WHERE [RAC_CAP_VALS] = '" & Me.[RAC_CAP_VALS] & "'"
Don't use VALUES when you're pulling data from one table to INSERT into another. Use SELECT instead.
This example uses just two of your fields. Add in the others you need.
Dim strInsert As String
strInsert = "INSERT INTO TEMP2 ([Study_Date], [Created_By])" & _
" SELECT [Study_Date], [Created_By] FROM RAC_DATA_ENTRY" & _
" WHERE [RAC_CAP_VALS] = '" & Me.[RAC_CAP_VALS].Value & "';"
Debug.Print strInsert '<- view this in Immediate window; Ctrl+g will take you there
dbs.Execute strInsert, dbFailOnError
Notes:
A semicolon at the end of the statement is optional. Access will consider the statement valid with or without it.
Value is not actually required following Me.[RAC_CAP_VALS], since it's the default property. I prefer to make it explicit.
dbFailOnError gives you better information about failed inserts. Without it, a problem such as a primary key violation would fail silently.
Debug.Print strInsert allows you to inspect the statement you built and are asking the db engine to execute. If there is a problem, you can copy the statement text from the Immediate window and paste it into SQL View of a new Access query for testing.
I have a form in which one of the ComboBoxes lists all the documents of a given project. The user should select one and after pressing a button, and if present in Table Dessinsit opens a second form showing that record. If it is not present in that table, I want to add it in.
One of my collegues told me all I had to do was to execute an SQL query with VBA. What I have so far is this:
Dim rsDessin As DAO.Recordset
Dim strContrat As String
Dim strProjet As String
Dim strDessin As String
Dim sqlquery As String
'I think these next 3 lines are unimportant. I set a first query to get information I need from another table
strDessin = Me.Combo_Dessin
strProjet = Me.Combo_Projet
sqlquery = "SELECT [Projet HNA] FROM [Projets] WHERE [Projet AHNS] = '" & strProjet & "'"
Set rsDessin = CurrentDb.OpenRecordset(sqlquery)
If Not rsDessin.RecordCount > 0 Then 'If not present I want to add it
strContrat = rsDessin![Projet HNA]
sqlquery = "INSERT INTO Feuilles ([AHNS], [Contrat], [No Projet]) VALUES (strDessin, strContrat, strDessin)"
'Not sure what to do with this query or how to make sure it worked.
End If
'Checking my variables
Debug.Print strProjet
Debug.Print strContrat
Debug.Print strDessin
'By here I'd like to have inserted my new record.
rsDessin.Close
Set rsDessin = Nothing
I also read online that i could achieve a similar result with something like this:
Set R = CurrentDb.OpenRecordset("SELECT * FROM [Dessins]")
R.AddNew
R![Contrat] = strContrat
R![Projet] = strProjet
R![AHNS] = strDessin
R.Update
R.Close
Set R = Nothing
DoCmd.Close
Is one way better than the other? In the case where my INSERT INTO query is better, what should I do to execute it?
You're asking which is preferable when inserting a record: to use an SQL statement issued to the Database object, or to use the methods of the Recordset object.
For a single record, it doesn't matter. However, you could issue the INSERT statement like this:
CurrentDb.Execute "INSERT INTO Feuilles ([AHNS], [Contrat], [No Projet]) VALUES (" & strDessin & ", " & strContrat & ", " & strDessin & ")", dbFailOnError
(You should use the dbFailOnError option to catch certain errors, as HansUp points out in this answer.)
For inserting multiple records from another table or query, it is generally faster and more efficient to issue an SQL statement like this:
Dim sql = _
"INSERT INTO DestinationTable (Field1, Field2, Field3) " & _
"SELECT Field1, Field2, Field3 " & _
"FROM SourceTable"
CurrentDb.Execute sql
than the equivalent using the Recordset object:
Dim rsSource As DAO.Recordset, rsDestination As DAO.Recordset
Set rsSource = CurrentDb.OpenRecordset("SourceTable")
Set rsDestination = CurrentDb.OpenRecordset("DestinationTable")
Do Until rs.EOF
rsDestination.AddNew
rsDestination!Field1 = rsSource!Field1
rsDestination!Field2 = rsSource!Field2
rsDestination!Field3 = rsSource!Field3
rsDestination.Update
rs.MoveNext
Loop
That said, using an SQL statement has its limitations:
You are limited to SQL syntax and functions.
This is partially mitigated in Access, because SQL statements can use many VBA built-in functions or functions that you define.
SQL statements are designed to work on blocks of rows. Per-row logic is harder to express using only the Iif, Choose, or Switch functions; and logic that depends on the current state (e.g. insert every other record) is harder or impossible using pure SQL. This can be easily done using the Recordset methods approach.
This too can be enabled using a combination of VBA and SQL, if you have functions that persist state in module-level variables. One caveat: you'll need to reset the state each time before issuing the SQL statement. See here for an example.
One part* of your question asked about INSERT vs. Recordset.AddNew to add one row. I suggest this recordset approach:
Dim db As DAO.Database
Dim R As DAO.Recordset
Set db = CurrentDb
Set R = db.OpenRecordset("Dessins", dbOpenTable, dbAppendOnly)
With R
.AddNew
!Contrat = rsDessin![Projet HNA].Value
!Projet = Me.Combo_Projet.Value
!AHNS = Me.Combo_Dessin.Value
.Update
.Close
End With
* You also asked how to execute an INSERT. Use the DAO.Database.Execute method which Zev recommended and include the dbFailOnError option. That will add clarity about certain insert failures. For example, a key violation error could otherwise make your INSERT fail silently. But including dbFailOnError ensures you get notified about the problem immediately. So always include that option ... except in cases where you actually want to allow an INSERT to fail silently. (For me, that's never.)
I have a query in an Access Db that counts the number of observations that meet a certain criteria as defined by two comboboxes. The query works fine, and I can get the result of the query to display and update live with the comboboxes using subforms, but the subforms are an extremely ugly way to represent a single number.
I would like to use a textbox to display that single number from the query instead of a subreport. I've tried inputting the SQL of the query into the Control Source and the Default Value, but no success.
After reading through the forum it appears I can write a function and then set my control source equal to that function.
Here is my VBA:
Public Function AdultCount()
Dim rs As Recordset
Set rs=CurrentDb.OpenRecordset("Select Count([name]) as [# Vars] from Masterdb where ((masterdb.year=[forms]![Masterform]![NavigationSubform].[form]![year]) and (masterdb.recipient=[forms]![Masterform]![NavigationSubform].[form]![recipient]) and (masterdb.group="adult"))")
AdultVar=rs!Result
rs.Close
Set rs=Nothing
End Function
I get "compile error: Expected:list separator or )"
and it highlights "adult" at the end of my SQL query.
I don't know why this isn't working. Does anyone know why I'm getting this error, and tell me if I'm even doing the right thing to get what I want?
edit:
I now have
Dim strSQL AS String
strSQL = "Select Count([name]) as [# Vars] from Masterdb where [year] = " & Me.NavigationSubform.year.value & " and [recipient] = " & Me.NavigationSubform.recipient.value & " and [group]='adult'"
Set rs=CurrentDb.OpenRecordset(strSQL)
AdultVar=rs![# Vars].Value
rs.Close
Set rs=Nothing
End Function
But the textbox reads "#Name?"
Any ideas?
The double quotes for "adult" are throwing the error because you're closing and reopening a string without telling VB what to do with adult"))"). SQL needs single quotes anyway, so change it to 'adult' and the error will go away.
A second option is to build your string first, like so:
Dim strSQL AS String
strSQL = "Select Count([name]) as [# Vars] from Masterdb where [year] = " & Me.NavigationSubform.year.value & " and [recipient] = " & Me.NavigationSubform.recipient.value & " and [group]='adult'"
Set rs=CurrentDb.OpenRecordset(strSQL)
If you're not familiar with using the Me keyword, do a bit of reading up as it will shorten your code and save you time.
I have a table 'Contacts' which has a multivalued field 'Department'. I have another table 'Outreach' and it has a field 'partner org'. I have a query which combines 'Contacts.Department' and 'outreach.[partner org]' into one field joining the two tables using an outer join on fullname field which is common in both tables.
The SQL statement I have to combine the two fields is
Contacts.Department & ";" & Outreach.[Partner Org] AS [Dept/Partner Org]
If I run this query, I get the error saying
The multivalued field 'Contacts.Department' is not valid in the expression 'Contacts.Department & " " & Outreach.[Partner Org] AS [Dept/Partner Org]'
If I add the '.Value' to the multivalued field, I get multiple rows.
Contacts.Department.Value & " " & Outreach.[Partner Org] AS [Dept/Partner Org]
I want the output to have the multivalued valued field contents followed by a ';' and the partner org name all in the same cell.
Please can someone tell me to how to get this.
Thank You.
I've come up against a similar problem with these useful (from the end-users perspective) but irritating (from the perspective of those analysing) fields.
I came up with a workaround, using a form, that I think solves your problem. I added a pseudo-departments text field to the table, applied slightly modified code from the fourth post to the relevant field(s) "AfterUpdate" events as & when they change (I pass the current record & the SQL string only summarises that record).
Dim db As Database, _
rst As Recordset, _
strSQL As String
Me.Refresh
Set db = CurrentDb
strSQL = "Select PseudoDepartment from YOURTABLE where UNIQUEIDNO = " & Me.UNIQUEIDNO & ";"
Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
With rst
If .RecordCount > 0 Then
.MoveFirst
.Edit
!PseudoDepartment = MakeList(Me.UNIQUEIDNO)
.Update
End If
End With
To initialise the pseudo-departments field, one could loop through all records one by one to generate the contents. One can then query the data normally and get the results in the form you indicated.
HTH.