Passing value from the textbox to "TOP n" clause in SQL query - sql

I believe I have quite simple question, that would help me finish my project. I don't usually work with Access, but I was asked to help someone so here I am.
My problem: I have a Form1 called "Start" in which there is a TextBox1 called "Kat1".
I also have a SQL Query as:
SELECT TOP 3 tbl.Example FROM TABLE TBL
What I want to achieve is to let the user to write some number in "Kat1" so that Query returns this much top rows.
I hope there is a way to this without using VBA, since my query is rather complicated, there are more textboxes, more subqueries with selecting top rows etc.
I tried putting SELECT TOP [Start]![Kat1]!Value or simmilar. There maybe something wrong with my syntax or maybe this is all wrong and there is another way.
Thank for help in advance.
Edit:
For future readers ;) This is how I solved it with VBA:
Sub Query_Change()
SQLstring = "SELECT TOP KAT1 col1 FROM TBL UNION SELECT TOP KAT2 col1 FROM TBL etc..."`
CurrentDb.QueryDefs("MyQuery").SQL = SQLstring
For i = 1 To 4
SQLstring = Replace(SQLstring, "KAT" & i, Forms!Start!("Kat" & i).Value)
Next i
CurrentDb.QueryDefs("MyQuery").SQL = SQLstring
End Sub
The code will run after user puts values into TextBoxes.

This is not possible in a Access query, the "TOP n" part cannot take a variable / parameter.
(It's possible in SQL Server, see Dynamic SELECT TOP #var In SQL Server )
You need VBA to do it. Either, since it's in the very first part of a SELECT statement, read the original Querydef.SQL and edit it (replace the 3rd "word").
Or have a table with template SQL code, with e.g.
SELECT TOP $count$ FROM table WHERE ...
Replace $count$ with your number and write the result to a querydef.
Edit
In this case, I would definitely go the template route.
Build your query "qUnionTop" with sample values for TOP n.
Copy the SQL to a table where you store the template SQL.
Edit the SQL with variables, e.g.
SELECT TOP $c1$ col1 FROM tblx UNION SELECT TOP $c2$ col1 FROM TBLY UNION ...
Before you open your query run code like this:
Sub DynamicQueryFromTemplate()
Dim S As String
Dim i As Long
' Read template SELECT SQL from tblTemplates
S = DLookup("Sql", "tblTemplates", "Key = 'qUnionTop'")
' Replace $c[x]$
For i = 1 To 4
S = Replace(S, "$c" & i & "$", Forms!Start("Kat" & i).Value)
Next i
CurrentDb.QueryDefs("qUnionTop").SQL = S
End Sub
Whenever your query needs to change, repeat steps 2.+3.

On the form properties go to the event tab. On the on load event you should create an Event Procedure looking like the following:
Option Compare Database
Private Sub Command0_Click()
Dim kat As String
kat = "SELECT TOP " +Me.Kat1.Value + "TableName.TableField "
CurrentDb.QueryDefs("QueryName") .SQL = kat
On Error Resume Nest
DoDmd.RunQuery "QueryName"
End Sub
Private Sub Form_Load()
End Sub
Private Sub testrun()
End Sub

Related

How to update text box based on combo box value

Beginner on Using MS access 2016 and VBA. I am trying to show information on how many items have been reserved or is in the reserve table based on what the user selects as the tool.
The tool combo box(cmbo_Tool) selects a tool from Table A. I need to count the amount of times this tool appears in Table B and then display it in textBox A.
I have made a query involving both tables, but i'm unsure on how to apply it to the label.
Instead I have used the AfterUpdate event on cmbo_tool and using the DCount option.
Another way I thought about is taking the Tool Id (in this case, say 5) from Table A, and searching for it in a column table B, and counting.
'using Dcount'
Private Sub cmbo_Tool_AfterUpdate()
Me.Text1404 = DCount("cmbo_Tool", "tbl_Booking", "Tool")
End Sub
'Using Table id'
Private Sub cmbo_Tool_AfterUpdate()
Dim T_var as integer
Dim FinalOut as integer
T_var = Me.cmbo_Tool.Column(0) 'This gives 5'
'I need to make T_Var link to Table b and count'
Me.Text1404 = FinalOut
End Sub
Using Dcount method, it gives a number im unsure of. I'm not even sure if im using dcount correctly.
Using the table id method, Im unsure how to take the value 5 and count it in table B, then display in the textbox.
I guess it could be something like this:
Private Sub cmbo_Tool_AfterUpdate()
Me!Text1404.Value = DCount("*", "tbl_Booking", "Tool = " & cmbo_Tool & "")
' If Tool is text, then use quotes:
' Me!Text1404.Value = DCount("*", "tbl_Booking", "Tool = '" & cmbo_Tool & "'")
End Sub
And do rename your controls to something meaningful.

Is it possible to make a dynamic sql statement based on combobox.value in access?

I made a form in access with 2 different comboboxes. The user of
This tool can choose in combobox1: the table (which has to be filtered) and the second combobox2 is the criteria to be filtered( for example Language= “EN”) and the output of this query has to be located in tablex.
The problen what I have is that i cant find a solution for passing the value of the combobox1 to the sql statement. The second one is just like: where [language] = forms!form!combo2.value, but the part where i cant find a solution for is: select * from (combobox1 value)? How can i pass the combobox value as table name to be filtered? Can anyone please help me?
You can't have the table name in the WHERE clause of your query (there might be a hacky way to do it, but it should be discouraged at any case).
If you want to select data from 1 of a number of tables, your best bet is to generate SQL dynamically using VBA. One way to do this (especially if you want/need your query to open in Datasheet View for the end user) is to have a "dummy" query whose SQL you can populate using the form selections.
For example, let's say we have 2 tables: tTable1 and tTable2. Both of these tables have a single column named Language. You want the user to select data from either the first or second table, with an optional filter.
Create a form with 2 combo boxes: One for the tables, and one with the criteria selections. It sounds like you've already done this step.
Have a button on this form that opens the query. The code for this button's press event should look something like this:
Private Sub cmdRunQuery_Click()
Dim sSQL As String
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
If Not IsNull(Me.cboTableName.Value) Then
sSQL = "SELECT * FROM " & Me.cboTableName.Value
If Not IsNull(Me.cboFilter.Value) Then
sSQL = sSQL & vbNewLine & _
"WHERE Language=""" & Me.cboFilter & """"
End If
Set db = CurrentDb
Set qdf = db.QueryDefs("qDummyQuery")
qdf.SQL = sSQL
DoCmd.OpenQuery qdf.Name
End If
End Sub
Note how the SQL is being generated. Of course, using this method, you need to protect yourself from SQL injection: You should only allow predefined values in the combo box. But this serves as a proof of concept.
If you don't need to show the query results, you don't need to use the dummy query: You could just open a recordset based on the SQL and process that.
If you run the code in the afterupdate event of the combobox you can set an SQL statement like this:
Private Sub combobox2_AfterUpdate()
someGlobalVar = "Select * FROM " & me.combobox1.value & " WHERE language = " & _
me.combobox2.value
End Sub
And then call the global with the SQL string wherever you need it.

How to use a query as a control source for a textbox on a form?

I have a form myForm that's binded to a table tbl in my database. (I don't know if binded is the correct term, but It shows records from tbl on by one.)
In the form:
contact: textbox, binded to tbl.contact.
dailyCount: textbox, should show the amount of contacts entered today.
In the table:
contact
dateEntry
The query I want to use is:
SELECT count(*)
FROM tbl
WHERE contact = currentContact
AND month(dateEntry) = month(now)
AND day(dateEntry) = day(now)
AND ear (dateEntry) = year(now)
Where currentContact is the contact that is showing on the form now.
I tried putting the query in the dailyCount dataSource, but It's not working. When I click on the three dots on datasource to access the wizard, I get a window to build functions and not queries.
How do I get the currentContact showing on the form into the query?
There are multiple ways to do this. For a couple of reasons, I don't like to hardcode queries in the datasource of a specific field, and I mostly build/assign all my queries in VBA. So here's how I would do it.
In the load event of you form :
Private Sub Form_Load()
Dim SQL As String
Dim RST As Recordset
dim theCOntact as string ' Change accordingly
theCOntact = Me.currentContact ' I don't know how your fields are named, so change accordingly
SQL = "SELECT count(*) AS cnt FROM tbl WHERE contact = " & theContact & "' AND month(dateEntry) = month(now) AND day(dateEntry) = day(now) AND Year(dateEntry) = year(now)"
Set RST = CurrentDb.OpenRecordset(RST)
If RST.BOF Then
dailyCount.Value = RST!cnt
Else
dailyCount.Value = 0
End If
End Sub
Assuming your contact field is string, if its a number remove the quotes in the SQL
Probably the simplest approach is to use the DLookup function with an associated query:
Create and save a named query with your SQL code or equivalent. Let's call it "qryDailyCount". Note that it should be modified to look something like this (in particular, name the column and change the record reference to a GROUP BY for now):
SELECT count(*) as DailyCount
FROM tbl
WHERE month(dateEntry) = month(now)
AND day(dateEntry) = day(now)
AND year (dateEntry) = year(now)
GROUP BY contact
In the dailyCount textbox, set the Control Source to something like this:
=DLookUp("Count";"qryDailyCount";"contact = [contact]")
(Note that if the contact field is a text field, you must enclose it with single quotes.)

Problems with field names and appending files in Access SQL

Okay, so I have nearly 200 tables in an Access database. The tables are of plant species abundance data, and I would like to combine them into a master data file. Each table contains basically the same columns of species; however, many are spelled slightly differently.
When I run an SQL query in MS Access it won't let me append the tables with each other because of the field names being spelled just a little different.
Any thoughts that would help?
The query I am running is an append query:
INSERT INTO masterTable SELECT * FROM siteTable
and, as an example, the differences in field names are pretty minor
(e.g. "Spp.A" vs "SppA" or "SpeciesOne" vs "Species1")
Thanks for any help,
Paul
You'll need to use vba for this, you'll also need to change the column names I'm using in the masterTable, which in my example are just column1, column2 & column3, and to set the maximum column index in a couple of places (I've stuck some comments in, so you can see what needs to be changed).
If you dont usually use vba, Create a form with a button, and a click event for the button & put this code in it, then open the form and click the button.
Dim db As Database
Dim tdf As TableDef
Dim ii As Long
dim sql as String
Set db = CurrentDb()
docmd.setwarnings false
For Each tdf In db.TableDefs
'change column list as required:
sql = "INSERT INTO masterTable (Column1, Column2, Column3) SELECT "
'change 2 to maximum column number - 1:
for ii = 0 to 2
sql = sql & tdf.Fields(ii).Name
'change 2 to maximum column number - 1 again:
if ii < 2 then
sql = sql & ","
end if
next
sql = sql & ")"
docmd.runsql sql
Next
docmd.setwarnings true
This should work I think. (I'm hoping there's no syntax errors, as I havent tested it, but the logic isnt exactly rocket science)
Hope this helps

how to replace text in a multifield value column in access

I've got a tablea such as below, I know its bad design having multifield value column but I'm really looking for a hack right now.
Student | Age | Classes
--------|------|----------
foo | 23 | classone, classtwo, classthree, classfour
bar | 24 | classtwo, classfive, classeight
When I run a simple select query as below, I want the results such a way that even occurrence of classtwo is displayed as class2
select student, classes from tablea;
I tried the replace() function but it doesnt work on multivalued fields >_<
You are in a tough situation and I can't think of a SQL solution for you. I think your best option would be to write a VB function that will take the string of data, parse it out (replacing) the returning you the updated string that you can update your data with.
I can cook up quite a few ways to solve this.
You can explode the mv by using Classes.Value in your query. This will cause one row to appear for each value in the query and thus you now can use replace on that. However, this will result in one separate row for each class.
So use this:
Select student, classes.Value from tablea
Or, for this example:
Select student, replace(classes.Value,"classtwo","class2") as myclass
from tablea
If you want one line, AND ALSO the multi value classes are NOT from another table (else they will be returning ID not text), then then you can use the following trick
Select student, dlookup("Classes","tablea","id = " & [id]) as sclasses
from tablea
The above will return the classes separated by a space as a string if you use dlookup(). So just add replace to the above SQL. I suppose if you want, you could also do replace on the space back to a "," for display.
Last but not least, if this those classes are coming from another table, then the dlookup() idea above will not work. So just simply create a VBA function.
You query becomes:
Select student, strClass([id]) as sclasses from tablea
And in a standard code module you create a public function like this:
Public Function strClass(id As Variant) As String
Dim rst As DAO.Recordset
If IsNull(id) = False Then
Set rst = CurrentDb.OpenRecordset("select Classes.Value from tableA where id = " & id)
Do While rst.EOF = False
If strClass <> "" Then strClass = strClass & ","
strClass = strClass & Replace(rst(0), "classtwo", "class2")
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
End If
End Function
Also, if you sending this out to a report, then you can DUMP ALL of the above ideas, and simply bind the above to a text box on the report and put the ONE replace command around that in the text box control. It is quite likely you going to send this out to a report, but you did ask how to do this in a query, and it might be the wrong question since you can "fix" this issue in the report writer and not modify the data at the query level. I also think the replace() command used in the report writer would likely perform the best. However, the above query can be exported, so it really depends on the final goal here.
So lots of easy ways to do this.