Get data from Access given only the primary key of the Table - sql

So I have a question regarding data referencing in Access using VBA and SQL. I have a table in my dataset with like 50 columns, and I need to make a query that a user can run that will manipulate the data in like 30 of these columns with a not-so straightforward algorithm. So the query will prompt the user for the primary key and then run a vba function for getting the value that the user wants, I was just wondering if it was possible that It could be done like this
SELECT Hardware_Type,
Func32(Hardware_Type)
FROM Table1
WHERE (([Hardware_Type]) = [Hardware_Type]);
where Hardware_type is the primary key and Func32 is a Visual Basic Function.
So now Func32 only takes Hardware_type as an Input but needs to use 30 pieces of Data that are in the Row of that specific Hardware_Type. I just need to know that does there exist a way to do this and if there does, I would request a hint, because I really don't want to type in 30 different fields in the query and the function. Oh, and all of this is in Microsoft Access!
Thanks in Advance!

You can avoid passing a whole bunch of parameters to your VBA function but it will cost you one database hit for each time the function is called (i.e., once per row in the query that calls the function). Your function could do something like:
Option Compare Database
Option Explicit
Public Function Func32(HardwareType As String) As Variant
Dim cdb As DAO.Database, qdf As DAO.QueryDef, rst As DAO.Recordset
Dim sql As String
Set cdb = CurrentDb
sql = ""
sql = sql & "PARAMETERS prmHardwareType TEXT(255);"
sql = sql & "SELECT * FROM Table1 WHERE Hardware_Type=[prmHardwareType]"
Set qdf = cdb.CreateQueryDef("", sql)
' assign the PK argument as the query parameter and open it as a Recordset
qdf!prmHardwareType = HardwareType
Set rst = qdf.OpenRecordset(dbOpenSnapshot)
' do your calculations and assign the return value to the function name
Func32 = rst!Field1 + rst!Field2 + rst!Field3
rst.Close
Set rst = Nothing
Set qdf = Nothing
Set cdb = Nothing
End Function

Related

Most efficient way to query 1 of 4 large Access tables based on condition (using VBA module)

For the past couple weeks I've been working on a very unconventional solution to a problem for my job. I'm almost there, but I need to know the most efficient way to do the last step. I will dumb it down so I don't have to write an essay describing the insane nature of the problem I've been working on.
I have four large local tables in MS Access with a total of over 500,000 records.
Each table represents a different type of product.
The productID for table1 always starts with "9"
The productID for table2 always starts with "8"
The productID for table3 always starts with "4"
The productID for table4 always starts with "3"
I have a vba procedure written that does exactly what I need it to do except I have it querying information using only table1 thus far. Basically, a user inputs a productID and the procedure searches the table for that record and sends the information to a sharepoint list. Speed of execution is HIGHLY important in my situation. So, what is the fastest way to have it run? Should I write a statement that says "If the ID starts with 9 then search this table, ElseIF ..... and so on." Or, should I combine all the tables into one and not have it look at the first digit of the ID?
I know this sounds like a simple issue but trust me, this is a wild over simplification of the real issue and it would take 2,000 words to explain how ridiculous it actually is; I'm not kidding. However, I am fairly confident that the answer to the above question will give me all the information I need to finish this project successfully. I have come so far and all I have left is to figure out the most efficient way to apply it to the 3 other tables.
Thanks!
As the tables are local, use the Seek method which is extremely fast:
Recordset.Seek method (DAO)
If the tables were linked, you could still using Seek by opening the backend database. This is an example:
Function SeekTable()
Const cstrTable As String = "tblValue01"
Const cstrAttached As String = ";DATABASE="
Dim wks As Workspace
Dim dbs As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim strConnect As String
Dim strTablename As String
Set wks = DBEngine(0)
Set dbs = wks(0)
Set tdf = dbs.TableDefs(cstrTable)
strConnect = tdf.Connect
strTablename = tdf.SourceTableName
Set tdf = Nothing
If InStr(1, strConnect, cstrAttached, vbBinaryCompare) = 1 Then
strConnect = Mid(strConnect, Len(cstrAttached) + 1)
' Open database shared and read-only.
Set dbs = wks.OpenDatabase(strConnect, False, True)
Set rst = dbs.OpenRecordset(strTablename)
'
' Perform Seek operation. Example.
rst.Index = "ID"
rst.Seek "=", 10010
Debug.Print rst!Value
'
rst.Close
Set rst = Nothing
End If
dbs.Close
Set dbs = Nothing
Set wks = Nothing
End Function

Access subtract form value from another query

In MS Access using VBA trying to subtract a calculated value (time between dates) from a total amount of time in another table.
The query holding the total amount of time is QryScsBatchHandler the field I want to subtract the value from is FreezerLifeUsed and the match condtion is BatchID
The query holding the value I want to subtract is QrySCSMaterialFreezerLog or the form is Frm_MaterialFreezerLog.. the value is AccumilatedTime and the Match condition is Batch ID
Private Sub BkInFrzr_Click()
Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim strSQL As String
Set db = CurrentDb()
strSQL = "SELECT FreezerLifeUsed FROM QryScsBatchHandler WHERE [BatchID] = BatchID"
Set rst = db.OpenRecordset(strSQL, dbOpenDynaset)
With rst
.MoveFirst
.Edit
FreezerLifeUsed = -AccumilatedTime
.Update
End With
End Sub
I can’t seem to get this simple subtraction to work… any suggestions on what’s not right?
Any help will be greatly appreciated..
At least 3 issues with code.
concatenate reference to form field/control for dynamic criteria in SQL:
strSQL = "SELECT FreezerLifeUsed FROM QryScsBatchHandler WHERE [BatchID] = " & Me.BatchID
The VBA needs to use dot or bang when referencing controls or fields and qualifying with prefix is advised:
!FreezerLifeUsed
Me.AccumilatedTime
Nothing is subtracted from anything, so consider:
!FreezerLifeUsed = !FreezerLifeUsed - Me.AccumilatedTime
However, if query is expected to return only one record, don't bother with loop. Also, instead of opening a recordset, an UPDATE action would work.

In MS Access, is it possible to add an updatable blank field to a query to calculate it's values programmatically in VBA?

In MS Access, in order to prevent nesting queries, because it has become really slow, I'm trying to calculate programmatically in VBA all calculated fields for my queries using a Loop. In general, the idea is to stop using calculated fields on queries at all, to perform all calculations from the backend.
I am having problems showing the values in a TextBox in a Continuous Form. I'm trying to create a query in VBA with an empty field and then update the field with the calculated values, so then I can set the ControlSource of the textbox to that field for it to show properly. The problem is that since the empty field is a calculated field, I cannot update it's value. Is there any other way to add a field to a query that remains empty and updatable until I can calculate it's values?
An alternative solution would be to create a temporal table instead of a query and update the values, but I would really prefer not to create temporal tables every time an user needs to do a query with calculated fields (especially nested ones).
Is there a way to accomplish this?
Here is what I tried:
Private Sub Form_Load()
Dim SQLQ As string
Dim rs As DAO.Recordset
Dim dbs As DAO.Database
Dim qrydef As DAO.QueryDef
Dim i As Integer
'calcField1 is not a member of Items, and it's intended to be updated later on
SQLQ = "SELECT Items.Price, calcField1 FROM Items;"
Set dbs = CurrentDb()
Set qrydef = dbs.CreateQueryDef("testqry", SQLQ)
'Field is prompted for a value when the query is called and has no source
qrydef!calcField1 = vbNullString
Set rs = qrydef.OpenRecordset()
i = 0
Do Until rs.EOF
rs.Edit
rs!calcField1 = rs!Price *2 'Error here because calcField1 is a Calculated Field
rs.Update
i = i + 1
rs.MoveNext
Loop
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.Recordset = rs
Me.Refresh
End Sub
I think it is better to create another table where you can insert the new calculated record with a reference to the original table so they are linked.
for example:
table 1:
item_id, item_desc, price
table 2:
item_id, calculated_value
then, the calculated value can be inserted or modified depending on the purpose of your calculation process.
Can you add the calculated field into a query and use that as the Record Source?
Private Sub Form_Load()
Dim strSQL As string
'calcField1 is calculated
strSQL = "SELECT Items.Price, (Items.Price * 2) AS calcField1 FROM Items;"
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.RecordSource = SQLQ
Me.Refresh
End Sub
or if the logic is more complex you can put it into a function
'in the form
Private Sub Form_Load()
Dim strSQL As string
'calcField1 is computed by a function
strSQL = "SELECT Items.Price, MyFunction(Items.Price) AS calcField1 FROM Items;"
Me.TextBox1.ControlSource = "=Price"
Me.TextBox2.ControlSource = "=calcField1"
Set Me.RecordSource = strSQL
Me.Refresh
End Sub
'in a module
Public Function MyFunction(dbl As Double) As Double
MyFunction = dbl * 2
End Function

Data Conversion error 3421 on OpenRecordset method of DAO QueryDef

I want to pass one parameter to a saved query in MS Access 2010 and then also get the results from the query: its my saved query:
SELECT Count(*)
FROM tb_KonzeptDaten
WHERE ( Konzept=[fzg_ID] and (DCMFile is null or (DCMFile='')));
and here is my VBA code to invoke this query:
Dim db As DAO.Database
Dim qry As DAO.QueryDef
Set qry = db.QueryDefs("Test_qr_emptyDCM")
qry.Parameters("fzg_ID").Value = ID
Set rs = qry.OpenRecordset("Test_qr_emptyDCM")
also the Type of ID in VBA code is Long and the field of Konzept is Database is Long integer
Why do I get this error and how can I solve it?
Your problem is with the qry.OpenRecordset statement. The first parameter for QueryDef.OpenRecordset is [Type] (e.g., dbOpenSnapshot). You don't need to provide the query name because you already supplied that when you created the QueryDef object.
Try using just
Set rs = qry.OpenRecordset

Is it possible to pass parameters programmatically in a Microsoft Access update query?

I have a query that's rather large, joining over a dozen tables, and I want to pull back records based on an id field (e.g.: between nStartID and nEndID).
I created two parameters and tested them as criteria and they work fine.
The issue is, I need to run an insert query from this main query, and need the parameters where they are, in the main query. So, I need to pass parameters to it programmatically.
Anyone have a clue as to how this can be done?
Thanks.
I just tested this and it works in Access 2010.
Say you have a SELECT query with parameters:
PARAMETERS startID Long, endID Long;
SELECT Members.*
FROM Members
WHERE (((Members.memberID) Between [startID] And [endID]));
You run that query interactively and it prompts you for [startID] and [endID]. That works, so you save that query as [MemberSubset].
Now you create an UPDATE query based on that query:
UPDATE Members SET Members.age = [age]+1
WHERE (((Members.memberID) In (SELECT memberID FROM [MemberSubset])));
You run that query interactively and again you are prompted for [startID] and [endID] and it works well, so you save it as [MemberSubsetUpdate].
You can run [MemberSubsetUpdate] from VBA code by specifying [startID] and [endID] values as parameters to [MemberSubsetUpdate], even though they are actually parameters of [MemberSubset]. Those parameter values "trickle down" to where they are needed, and the query does work without human intervention:
Sub paramTest()
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.QueryDefs("MemberSubsetUpdate")
qdf!startID = 1 ' specify
qdf!endID = 2 ' parameters
qdf.Execute
Set qdf = Nothing
End Sub
Try using the QueryDefs. Create the query with parameters. Then use something like this:
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Set dbs = CurrentDb
Set qdf = dbs.QueryDefs("Your Query Name")
qdf.Parameters("Parameter 1").Value = "Parameter Value"
qdf.Parameters("Parameter 2").Value = "Parameter Value"
qdf.Execute
qdf.Close
Set qdf = Nothing
Set dbs = Nothing
Many thanks for the information about using the QueryDefs collection! I have been wondering about this for a while.
I did it a different way, without using VBA, by using a table containing the query parameters.
E.g:
SELECT a_table.a_field
FROM QueryParameters, a_table
WHERE a_table.a_field BETWEEN QueryParameters.a_field_min
AND QueryParameters.a_field_max
Where QueryParameters is a table with two fields, a_field_min and a_field_max
It can even be used with GROUP BY, if you include the query parameter fields in the GROUP BY clause, and the FIRST operator on the parameter fields in the HAVING clause.
You can also use TempVars - note '!' syntax is essential
Plenty of responses already, but you can use this:
Sub runQry(qDefName)
Dim db As DAO.Database, qd As QueryDef, par As Parameter
Set db = CurrentDb
Set qd = db.QueryDefs(qDefName)
On Error Resume Next
For Each par In qd.Parameters
Err.Clear
par.Value = Eval(par.Name) 'try evaluating param
If Err.Number <> 0 Then 'failed ?
par.Value = InputBox(par.Name) 'ask for value
End If
Next par
On Error GoTo 0
qd.Execute dbFailOnError
End Sub
Sub runQry_test()
runQry "test" 'qryDef name
End Sub