SQL Query in Access not applying WHERE clause - sql

I am an amateur vba programmer currently struggling with the following:
I wrote a simple SQL Query for my VBA program to extract data from an existing Query (GroupedData) in Access:
Dim strSQL as string
Dim db as dao.database
dim rs as dao.recordset
strSQL = "SELECT GroupedData.EmployeeID, GroupedData.End, GroupedData.LOB, GroupedData.Position, GroupedData.WorkStatus " & _
"FROM GroupedData WHERE (((GroupedData.End) Is Null) AND ((GroupedData.Position)=0) AND ((GroupedData.WorkStatus)=0));"
Set db = OpenDatabase(MY_DB, dbOpenDynaset)
Set rs = db.openrecordset(strSQL, dbOpenSnapshot)
Do While Not rs.EOF
ListBox1.AddItem rs!EmployeeID
rs.MoveNext
Loop
So my problem is that SQL is running smoothly but is not applying any filters (that is where clause - it produces records where workstatus and position contain values above 0)
I have done such queries in the past without having any issues. This time however I am stuck
Any help would be much appreciated!
Thank you

Ok i have fixed the issue. Here is what happened:
I have made a separate function that was retrieving Employee Name based on EmployeeID. But in that function i had recordset and database declared the same way, that is: rs and db. What happened when i ran the query was it was taking the first record filtered but then the rest of them were unfiltered because they were based on the recordset within the function (which is of course all of the employees) Such a silly mistake :) Thanks anyways

Related

MS Access crashes binding RS to a form from SQL Server stored procedure

I am just starting to move our Access DB to SQL Server and am having trouble.
I have a stored procedure that successfully returns rows to an ado recordset.
When I try to bind the rs containing the results of the stored procedure to the Access form, Access crashes without displaying any error messages. I'm on O365 32b and SQL Server 2019.
Here's the code:
Dim sSQL As String, rs As ADODB.Recordset
1 sSQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
2 ADOConn.ConnectionString = conADO
4 ADOConn.Open
6 Set rs = New ADODB.Recordset
7 rs.CursorLocation = adUseClient
8 rs.Open sSQL, ADOConn
10 Set Me.Recordset = rs ' Access crashes here
. . .
Any help would be greatly appreciated!
tia.
SR
Ok, are you previous using ADO, or are you just introducing this?
In most cases, you are better off to just use a view. (replace the access query with a linked view), and then continue useing client side where clauses or filters (access will ONLY pull down the rows you request). So linked views are often a better choice and much less work (in fact, even existing filter for a open report etc. will work and only critera matching the were clause records are pulled.
And in most cases, i don't introduce ADO.
So for a PT query, I often do this:
dim rs as DAO.RecordSet
with CurrentDb.queryDefs("qryPt")
.SQL = "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
set rs = .OpenRecordSet
end with
So, above assumes you have a pt query called qryPt. This also means that you never deal with or worry about connection strings in code. The pt query has the connection. (and your re-link code now can re-link tables and pt queries).
I ONLY suggest the above as a FYI in case that you introducing ADO for calling store procedures, and the rest of the application was previous DAO. If the application was previous DAO, then leave it alone, and use above approach for your PT queries - even code that needs to call store procedures.
Access tends to try and parse the query text to get filters/sorts/etc to work, and if it isn't a plain syntax error but isn't Access SQL either, strange things tend to happen, mostly crashes.
Try adding a comment up front to make sure Access knows not to parse:
sSQL = "-- Access no parse pls" & vbCrLf & "Exec usp_TaskStatusWidget " & Me.Tag & ",0"
The content of the comment is not relevant, of course, its purpose is to immediately cause a syntax error when Access tries to parse it as Access SQL (which doesn't have comments)

In Excel VBA run SQL "SELECT ... INTO ... IN ...." Statement

I can't seem to find any good reference or example of how to get this to work. I have a database which is stored on an AS/400 (my local MS Access database [stored on a network drive] has linked tables to the 400, using ODBC/DSN). My utility works just fine passing SQL statements to through Access to retrieve data from the 400 using the linked tables. The problem is that with some of the larger reports and the fact that the 400 is several states away, it can take several hours to run the reports. The settled on solution to this is to create a local "copy" of the tables needed with just the data set that is relevant to the reports, which is a considerably smaller data set. Obviously this has the down side of not being "live" data but I can live with that. Ultimately what I want to do is gather the relevant data from the linked table and save it to separate database that is local to the client so that it could be used if offsite/offline and to increase the speed of the report.
network location stored database = DB1 (Tabled linked to AS/400)
local client stored database = DB2 (relevant data set created by below SQL, non-linked tables named the same as the linked tables)
Below is the SQL statement that I'm trying to get to work using VBA & DAO
SELECT
DB1_TABLEA.FIELD1,
DB1_TABLEA.FIELD2,
DB1_TABLEA.FIELD3,
DB1_TABLEA.FIELD4,
DB1_TABLEA.FIELD5,
DB1_TABLEA.FIELD6,
DB1_TABLEA.FIELD7,
DB1_TABLEA.FIELD8
INTO
DB1_TABLEA IN 'Local_DB_Copy.accdb' <== Creating non-linked copy
FROM
DB1_TABLEA
WHERE
(
((DB1_TABLEA.FIELD4) Like 99999)
AND
((DB1_TABLEA.FIELD6)="02" Or (DB1_TABLEA.FIELD6)="22")
)
;
I already have my program working fine and returning/processing data from the AS/400 DB. I just need to be able to get the above to work so that people have the option to run a local copy that will process much faster.
Below is the code that I tried, but of course it fails or I wouldn't be here.
Sub gCreateLocalDBTables()
Dim DBPath As String
Dim LocalDBPath As String
Dim sSQL As String
Dim DB As DAO.Database
Dim DB2 As DAO.Database
Dim RS As DAO.Recordset
LocalDBPath = "AS400_Local.accdb"
sSQL = "SELECT DB1_TABLEA.FIELD1, DB1_TABLEA.FIELD2, DB1_TABLEA.FIELD3, DB1_TABLEA.FIELD4, DB1_TABLEA.FIELD5, DB1_TABLEA.FIELD6, DB1_TABLEA.FIELD7, DB1_TABLEA.FIELD8 INTO DB2_TABLEA IN '" & LocalDBPath & "' FROM DB1_TABLEA WHERE (((DB1_TABLEA.FIELD4) Like 99999) AND ((DB1_TABLEA.FIELD6)='02' Or (DB1_TABLEA.FIELD6)='22'));"
Set DB = OpenDatabase(LocalDBPath, False, False)
DB.TableDefs.Delete ("DB2_TABLEA")
DB.Close
DBPath = Interaction.GetSetting("Cust_Tools", "Settings\Report_Planning", "400DB_Location")
Set DB2 = OpenDatabase(DBPath, False, False)
Set RS = DB2.OpenRecordset(sSQL)
RS.Close
DB2.Close
Set RS = Nothing
Set DB = Nothing
Set DB2 = Nothing
End Sub
I know the SQL works as I have tested it from inside MS Access. I just can't find info on how to get it to work being passed from Excel VBA
You cannot assign an action query like a make-table query (i.e., SELECT with INTO call) to a recordset. Consider executing your DROP and SELECT ... INTO action queries prior to opening recordset on the local table. Also, it is unclear why you are opening a second database or what the path points to. Below opens a recordset on the mainframe data:
Set DB = OpenDatabase(LocalDBPath, False, False)
DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute sSQL, dbFailOnError
Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")
Furthermore, the IN clause in your make-table query is unnecessary as you are currently connected to the very database you are running the action on. Simply remove it ('" & LocalDBPath & "'). Also, LIKE expressions without wildcards and on numbers should be replaced with =
SELECT
DB1_TABLEA.FIELD1,
DB1_TABLEA.FIELD2,
DB1_TABLEA.FIELD3,
DB1_TABLEA.FIELD4,
DB1_TABLEA.FIELD5,
DB1_TABLEA.FIELD6,
DB1_TABLEA.FIELD7,
DB1_TABLEA.FIELD8
INTO
DB2_TABLEA
FROM
DB1_TABLEA
WHERE
(
((DB1_TABLEA.FIELD4) = 99999)
AND
((DB1_TABLEA.FIELD6)='02' OR (DB1_TABLEA.FIELD6)='22')
)
;
In fact, consider saving the query inside the MS Access database (Ribbon -> Create -> Query Design -> SQL View) and call it as a named object and avoid any long SQL in VBA.
DB.Execute "DROP TABLE DB2_TABLEA", dbFailOnError
DB.Execute "mySavedQuery", dbFailOnError
Set RS = DB.OpenRecordset("SELECT * FROM DB2_TABLEA")

MS Access VBA code

I am new to MS Access and would like to type EmployeeID in the text box 1 (text_in) and after the button is pressed the result query (one unique value e.g. employee first name taken from the table) is printed out in the text box2 (text_out).
So far have the following code:
Private Sub btn_get_data_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
'declaration of database on recordset objects
Dim strSQL As String
Dim a As String
a = text_in.Value
Set db = CurrentDb
Set rs = db.OpenRecordset("Employee")
strSQL = "SELECT Employee.FirstName FROM Employee WHERE Employee.EmployeeId=" & a
Set db = Nothing
Set rs = Nothing
End Sub
I have tried searching for a solution in many places but I cannot understand the structure that is used in MS access VBA to implement query from regular SQL language.
Guys, thank you very much! It took me one more hour to sucessfully implement both solutions into my database file. As I wrote I am completely new to Ms-access I am learning using some tutorials but my level is still low. Thank you very much once again.
Private Sub btn_get_data_Click()
on error goto errorCatch
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb
strSQL = "SELECT Employee.FirstName FROM Employee WHERE Employee.EmployeeId=" & Me.text_in.Value & ";"
Set rs = db.OpenRecordset(strSql, DbOpenDynaset)
If rs.RecordCount > 0 Then
debug.print; rs!FirstName
Me.text_out.Value = rs!FirstName
End if
Cleanup:
Set db = Nothing
Set rs = Nothing
Exit Sub
errorCatch:
debug.print; err.Number
debug.print; Err.Description
GoTo Cleanup
End Sub
I cant tell what youre after is this. You need to be better at utilizing recordsets and how to use a string value as your sql statement.
You also didnt need to create a variable to store the textbox value in- you can use it directly in your sql statement.
Also it is very important to have good error handling as hanging recordset objects can be quite a pain in the ass.
EDIT - Ill expand on other ways to use string sql statements within VBA
DoCmd.RunSQl strSql
Or
DoCmd.Execute strSql
Both of these are great for UPDATE's or INSERT's.
Then, like Gustav pointed out, you have various D functions that are basically compact queries with some limitations. However, they often save you the trouble of having to do all the typing that is involved with opening,utlizing and closing records sets. Even though the D functions seem limited, I have often nested a few to get join results out of. Just a matter of imagination.
Look at this nifty site for function details -
https://www.techonthenet.com/access/functions/index.php
You don't need a query to do this. Just set the ControlSource of text2:
=DLookup("FirstName","Employee","EmployeeId=" & [text_in] & "")

VBA - MariaDB - Query cannot be updated because it contains no searchable columns to use as a key

I am using MariaDB and VBA to read/write a flat database using ADODB. This is not by choice however I've been asked to make it work in this manner. An alternative would be to directly use SQL queries however this is a port of a very old VB3 application.
Here is my code that connects to the database, pulls back all records, updates the last record, then calls update to effectively write it back to the database
Global DB As New ADODB.Connection
Global TD As New ADODB.Recordset
DB.Open "Driver={MariaDB ODBC 2.0 Driver};Server=localhost;UID=???;PWD=???;DB=sf_log;Port=3306"
Dim query As String: query = "SELECT * FROM `" & TableName & "` ORDER BY `Record ID`"
TD.CursorLocation = adUseServer
TD.CursorType = adOpenDynamic
TD.Open query, DB, adOpenKeyset, adLockOptimistic
TD.MoveLast
Dim TestColumnField as string
TestColumnField = TD.Fields("TestColumn") 'This returns the correct value from the database indicating the connection was successful
TD.Fields("TestColumn") = "test"
TD.UpdateBatch (adAffectCurrent) ' This line throws the error
Error that is reported is "Query cannot be updated because it contains no searchable columns to use as a key"
The database is a flat relationship-less database with no keys. I have tried setting "record id" to be a primary key with no luck.
Is this error due to MariaDB not implementing/supporting ADODB recorset? Is it due to my database structure? Or is it simply I am utilising the ADODB recorset incorrectly?
Edit: Here is an example that shows you do not need an SQL update statement. You can simply select the data and call Update.
http://www.accessallinone.com/updating-adding-and-deleting-records-in-a-recordset/
Sub ADODBUpdating()
Dim sql As String
Dim rs As adodb.Recordset
sql = "SELECT * FROM tblTeachers WHERE TeacherID=5"
Set rs = New adodb.Recordset
rs.Open sql, CurrentProject.Connection, adOpenDynamic, adLockOptimistic
'Open RecordSet
With rs
If Not .BOF And Not .EOF Then
.MoveLast
If .Supports(adUpdate) Then
![FirstName] = "x" & ![FirstName]
.Update
End If
End If
.Close
End With
Server side cursor implementation seems to be limited, use client side cursors (DB.CursorLocation = adUseClient) instead.
1.) You can't do an update in SQL with a SELECT-Statement. Instead use the UPDATE-Statement.
2.) Dont't try to update all the records. Only Update the single row you want to update. As you write this should be the last record.
You update the testfield and you have to be sufficiently specific in the WHERE-Clause, that you only select the one and only record record you want to update.

How to run a SQL select statement in VB

I have been looking around but can't seem to find out how to do this.
I'm trying to execute a SELECT sql statement in VB that takes in a parameter from a form. For example the user selects a From and a To date and the SQL should take what they selected.
I know that you cannot use the DoCmd.Execute method for SELECT SQL so I would need to open the record set - but how? This is what I have tried so far
Dim recordSet As DAO.recordSet
Dim SQL As String
SQL = "SELECT * FROM tblWebMeetingData"
Set recordSet = CurrentDb.OpenRecordset(SQL)
'More code in here
recordSet.Close
Set recordSet = Nothing
Because this executes without an error I assume it's actually getting the results - so is there a way to see what it is actually returning?
Thanks
First: It's a good advice to rename the recordset to rs, for example, because "recordset" is a reserved name. This is misunderstandable.
This recordset contains the records you queried by your SQL statement. You may access those data by rs.fields("fieldname").value. Move to the next recordset with rs.movenext.
To incorporate the form's control value I use the way to build the full SQL statement prior to opening the recordset. Say the form is named "myform" and the control "mycontrol", you may write some kind of
SQL = "SELECT * FROM tblWebMeetingData WHERE myfield = " & forms!myform.mycontrol.value
Please be sure the form only contains valid values, because any wrong formatted value will directly lead to an SQL execution error.
I hope it was this, what you wanted.
Here you have come sample code about iterating trought RecordSet and using values from it( I hope it helps a bit):
Dim i As Integer
Do While Not rs.EOF
Sheets("D_" & day).Cells(i, 1) = rs.Fields(0).Value
Sheets("D_" & day).Cells(i, 2) = rs.Fields(1).Value
rs.MoveNext
i = i + 1
Loop
rs.Close