In MS Access I have 1 table that updates daily via external file and 50 queries (named 01_query, 02_query... 50_query), all with same columns and logic but with different filters. Some returns result, others are empty.
How can I get the list (using another query) with the names of NON empty queries?
I found the way to get a list of all query names with this code
SELECT MSysObjects.Name
FROM MsysObjects
WHERE (Left$([Name],1)<>"~") AND (MSysObjects.Type)=5
ORDER BY MSysObjects.Name
but I can't figure out how to filter out the "empty" queries.
If you absolutely must have an Access SQL solution to produce your list, consider something other than UNION of 50 data sources. Access does not allow you to UNION an unlimited number of data sources, but I don't recall what that limit is. And even if it allows you to UNION 50, I still wouldn't do it.
I tested this one in Access 2010 and it produces the result I think you're looking for. Since you've demonstrated you have read permission on MsysObjects it should work for you, too.
SELECT
sub.Name
FROM
(
SELECT
m.Name,
IIf(
m.Name ALike '[0-9][0-9][_]query' AND m.Type=5,
DCount('*', m.Name),
0
) AS non_empty_target_query
FROM MsysObjects AS m
) AS sub
WHERE sub.non_empty_target_query=True
ORDER BY sub.Name;
The IIf() expression is the key to this query. In human-like speak it says, if the object is a query and its name starts with 2 digits followed by an underscore followed by "query", return the count of rows from that query; otherwise just return zero.
Then the parent query filters away those rows where non_empty_target_query is zero (False), leaving only rows containing the names of your "non-empty" queries.
Assuming that all your queries follow the same format, you actually don't need to do anything with MSysObjects. You can just do a simple loop (in VBA):
Public Sub GetNonEmptyQueries()
Dim db As DAO.Database, qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim queryName As String
Dim i As Integer
Set db = CurrentDb
For i = 1 To 50
queryName = format(i, "00") & "_query"
Set qdf = db.QueryDefs(format(i, "00") & "_query")
Set rs = qdf.OpenRecordset
If rs.recordCount > 0 Then
' do whatever you need to do with the query name here
Debug.Print qdf.Name
End If
Next i
End Sub
If you don't want to use VBA, it's possible to write a query that UNIONs the COUNT(*) of all your queries. Something like this:
SELECT "01_query" AS QueryName, Count(*) AS [Count] FROM 01_query HAVING COUNT(*) > 0
UNION
SELECT "02_query", COUNT(*) FROM 02_query HAVING count(*) > 0
...
UNION
SELECT "50_query", COUNT(*) FROM 50_query HAVING COUNT(*) > 0
Of course, you're going to have to add all the queries by hand, which is going to get rather tedious. I think the time you would spend hand-writing such a query might be better-spent reading up on VBA, so you can use the first option. :)
Related
I have several tables with the same data structure (they're filled with a bunch of stuff, in separate .accdb files to account for the 2GB limit) and need to retrieve info from one of them based on a field in a form.
Upon researching I came up with the following, but it won't seem to work.
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM Switch([Forms]![View_Info]![Contract] = "Contract1", "tblContract1", [Forms]![View_Info]![Contract] = "Contract2", "tblContract2")
WHERE (MyNumber = [Forms]![View_Info]![MyNumber])
Syntax error in FROM clause.
In this example I only used 4 fields and 2 tables but in fact there are around 9 tables and 20 fields in each that I wish to retrieve.
Can someone shed some light on this? I have a really hard time with SQL, so I apologize if this is quite basic.
Thanks in advance, Rafael.
You cannot return the table name from a function in the SQL FROM clause. If your table is determined dynamically, then you must build the SQL command string dynamically.
Dim tableName As String, sql As String
tableName = Switch(...)
sql = "SELECT ... FROM [" & tableName & "] WHERE ..."
As #forpas explains in his answer, you can use a UNION query, but this will always query all the tables. Since the filter is not based on a table column, the filtering will occur on the client side, i.e. in your application.
Try this UNION:
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM tblContract1
WHERE (MyNumber = [Forms]![View_Info]![MyNumber]) AND [Forms]![View_Info]![Contract] = "Contract1"
UNION
SELECT MyNumber, MyName, MyPage, MyDrawing
FROM tblContract2
WHERE (MyNumber = [Forms]![View_Info]![MyNumber]) AND [Forms]![View_Info]![Contract] = "Contract2"
Each query of the UNION contains in the WHERE clause the condition:
[Forms]![View_Info]![Contract] = "Contract?"
There are three mdb files in folders on a network drive that may hold the required record(s). How do I determine which db holds the record(s), ideally without data transfer/linking/etc.? Then a single SQL or DAO select can get the data from the correct db. Note: I'm trying to use Access as a front end to SQL using existing Access data spread all around the network drives.
My current solution of configuring 3 DAO objects and checking for no results, in succession until found, seems to load the remote tables to the local recordset and takes too long.
Is there a way to use IF EXISTS in this scenario?
This code throws "Invalid SQL statement; expected DELETE,INSERT,PROCEDURE,SELECT,OR UPDATE" error but is generally what I'd like to do :
Dim strSQL As String
Dim strSku As String
Dim intDbToSearch As Integer
strSku = DLookup("SKUNo", "tblCurrentItem") 'Note: this returns valid SKU#
strSQL = "IF EXISTS(SELECT xxTable.SKUNo "
strSQL = strSQL & "FROM [S:\Our Inventory\Cust Sleeves.mdb].[xxTable] "
strSQL = strSQL & "Where xxTable.SKUNo = " & "'" & strSku & "') Then intDbToSearch = 1"
DoCmd.RunSQL strSQL
This is one of three IF Exists that would run if SKUNo not found in db 1 or 2.
Ultimately intDbToSearch should point to db 1,2,or 3 if SKUNo found or 0 if not.
Thanks
In the end, I pushed usage rules for the 3 databases upstream and can now predetermine which database to search. Thanks again for your input.
Will the sought for SKU always occur in only 1 of the tables?
If you don't want to set table links or use VBA recordsets, only other approach I can see is a query object with a dynamic parameter that references a form control for the SKU input. No idea if this will be faster and will need a query for each remote table.
SELECT SKUNo FROM xxTable IN "S:\Our Inventory\Cust Sleeves.mdb" WHERE SKUNo = Forms!formname!cbxSKU
Then just do DCount on the query.
Dim intDbToSearch As Integer
If DCount("*", "xxQuery") > 0 Then
intDbToSearch = 1
End If
Could UNION the SELECT statements so would have only 1 query object to work with.
SELECT "x1" AS Source, SKUNo FROM xxTable IN "S:\Our Inventory 1\Cust Sleeves.mdb" WHERE SKUNo = Forms!formname!cbxSKU
UNION SELECT "x2", SKUNo FROM xxTable IN "S:\Our Inventory 2\Cust Sleeves.mdb" WHERE SKUNo = Forms!formname!cbxSKU
UNION SELECT "x3", SKUNo FROM xxTable IN "S:\Our Inventory 3\Cust Sleeves.mdb" WHERE SKUNo = Forms!formname!cbxSKU;
How about a simple Function to check if exists by passing the table name and value?
Something like this:
Public Function ExistInTable(Byval TableName As String, ByVal Value As String) As Boolean
ExistInTable = (DCount("*", TableName, "[SKUNo]='" & Value & "'" > 0)
End Function
To call it:
Sub Test()
If ExistInTable("T1", "Whatever") Then 'Exists in T1
If ExistInTable("T2", "Whatever") Then 'Exists in T2
'....
End Sub
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
can this be done, say I have rows (1,2,3,4,5) and I want to grab three rows, select one randomly and then get it's neighbors, so maybe the random selection is row (3), I can also grab (2,4) if I wanted its neighbors, do I just pick one at random and then look for the unique key before and after like this or can I do it all in one sql statement.
I was going to use ADO from excel to pull records (so VBA connects to access, opens a recordset with sql instructions and so on).
Hope I was clear!
I would love to just do this all in a SQL statement
I am not sure Access is capable of all the SQL commands such as SQL Server, so this may be a bit of a problem. If you have a primary key though, you can easly generate a Select query in VBA and then pass open recordset with this SQL.
Dim sSQL as String
Dim lRand as Long
Dim rs as ADODB.Recordset 'or DAO.Recordset'
lRand = VBA.Int(VBA.Rnd() * TableRecordCount) ' TableRecordCount is the number of records in the table that you need to get somehow'
sSQL = "SELECT * FROM TableName WHERE (ID>=" & lRand - 1 & " AND ID <=" & lRand + 1
set rs = CurrentDB.OpenRecordset(sSQL, ...)
I am now not absolutely sure of what you want to use and depending on ADODB or DAO choice, you need to open the recordset accordingly with wither Call rs.Open or Set rs = DB.OpenRecordset
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