Using a query to loop through tables that are similar in structure but have different names - sql

I would like to use a query to loop through tables that are similar in structure but have different names (ie. tableJan2011, tableFeb2011, tableMar2011 etc.)
Is there a way in MS Access and in SQL Server to use the same query statement while varying the table name within it. (similar to using parameter values) (need this to add different input to each different month's table)

This is a bad table design. You should have a singe table, where you have a column(s) to indicate month/year. You would then just query this single table and add a WHERE month='X' and YEAR='Y' to limit your results to what you need.
without a table redesign use UNION and clever WHERE clause parameters, which will cause rows to only come from the table that applies.
SELECT
..
FROM tableJan2011
where...
UNION
SELECT
..
FROM tableFeb2011
where...
UNION
SELECT
..
FROM tableMar2011
where...

First off, listen to the people who are telling you to use one table. They know of which they speak.
If you can't do that for some obscure reason (such as inheriting the design & not being allowed to change it), then you're stuck writing VBA code. There's no way that I know of, in Access, to substitute source tables (or even source columns--values only), in a saved QueryDef.
You'll need something like this:
Private Function QueryTable (strTableName as String) As DAO.Recordset
Const theQuery as String = "SELECT tbl.* FROM [table] As tbl"
Dim sSql As String
Dim db As DAO.Database
Dim rs As DAO.Recordset
sSql = Replace(theQuery, "[table]", strTableName)
Set db = CurrentDb()
Set rs = db.OpenRecordset(sSql)
Set QueryTable = rs
End Function
Note that this is simplified code. There's no error handling, I haven't released the objects (which I usually do, even though they'll go out of scope), and SELECT * is almost always a bad idea.
You'd then call this function wherever you need it, passing in the name of the table.

consider moving the year and month out of the table name and into columns in one table.
you can create a table with query or table names to use at runtime, but you have to be able to write Access BASIC code in a module.
Here's an example, assuming you have a query built on a table with the query names you want to execute:
Set db = CurrentDb
Set rsPTAppend = db.OpenRecordset("qry_PTAppend")
rsPTAppend.MoveFirst
Do Until rsPTAppend.EOF
qryPT = rsPTAppend("PT")
Set qdef = db.QueryDefs(qryPT)
sqlOld = qdef.sql
sqlNew = sqlOld
' manipulate sql
If sqlNew <> sqlOld Then
qdef.sql = sqlNew
End If
db.QueryDefs(rsPTAppend("append")).Execute
If sqlNew <> sqlOld Then
qdef.sql = sqlOld
End If
rsPTAppend.MoveNext
Loop

Don't know what is possible in Access but in SQL Server you could create a view that use union to get all tables together and then build your queries against the view.
One other option you have could be to build your queries dynamically.

In sql server you can execute a string as sql.
http://msdn.microsoft.com/en-us/library/ms175170.aspx
I'm not aware of anything similar in MS Access (though my experience is limited). You could however dynamically generate your sql in code to accomplish this. Perhaps you could create a function to take the table suffix and parameters and build the desired sql that way.

Related

Get unique entries only using Where Statement?

I got the following set up: Oracle Database as back-end, a interface provided by our IT-Database Department and my Excel-VBA front-end.
The interface provides a variety of functions to insert, update and read data. The "DB_connection.read_test" function takes inputs:
TestID (0=ALL)
SQL Where Statement
Table name where the data will be stored
Set the header of the database as boolean true= set, false= leave as is
The function shows a view that the back-end guy prepared for me. Now there are two columns that I want to compare if they are unequal "PRODID" and "ArticleID" and get all unique pairs of "PRODID" and "ArticleID". The challenge is here that I only can write a where statement.
Sub query_ProdID_uneq_ArticleIDlocal()
Dim SQL_Where As String
SQL_Where = "PRODID <> ARTICLEID"
Call DB_connection.read_test(0, SQL_Where, "Pruefungen_Tab", True)
End Sub
This code above works but gets me all data where PRODID <> ARTICLEID. So they are not unique. I could work on in VBA-Excel and reduce the pairs to distinct pairs.
But is there a way to make this happen with the right WHERE Statement?
SQL_Where = "PRODID <> ARTICLEID and Unique(ArticleID)"
Or something like this?
Example Data:

Can I use a subquery to choose the column I want to select in SQL in MS Access?

I have a query written that will return a single record (a class number) from table1. This class number is the title of a column that I want to select in another table (table2). I want to use this subquery as a mechanism to select this column. Can this be done?
I know this may be bad design but I am just wondering if this sort of thing is possible in MS Access SQL. I know it is not as powerful as MySQL.
The only way you're ever going to do this is using VBA to write the SQL, which really isn't a bad thing. I'd do it sort of like this:
Dim db as Database
Dim rec as Recordset
Dim MyVar = String '(or whatever the datatype is for ClassNumber in Table1)
Dim sSQL as String
Dim qdfNew As DAO.QueryDef
Dim qryLoop As QueryDef
Set db = CurrentDB
Set rec = db.OpenRecordset("SELECT ClassNumber from Table1")
MyVar = rec(0)
'First check to see if the query already exists. If so, delete it.
For Each qryLoop In CurrentDb.QueryDefs
If qryLoop.Name = MyVar Then
DoCmd.DeleteObject acQuery, MyVar
End If
Next
'This will select only the field that relates to the ClassNumber above
sSQL = "SELECT " & MyVar & " FROM Table2"
Set qdfNew = db.CreateQueryDef("MyNewQuery", sSQL)
Then, MyNewQuery is a permanent query in your database which can be used in other queries.
There might be a better option, but I can only think of:
Heinous case statement to choose the right column.
Using VBA.
Correcting the table design, turning the field name into a value
that can be joined upon.

How to execute query only for existing tables?

I'm using MS Access 2003 and I have a "long" query like
SELECT * FROM [Table 1]
UNION ALL
SELECT * FROM [Table 2]
UNION ALL
SELECT * FROM [Table 3]
....
SELECT * FROM [Table 100]
Each of table linked to a certain table from HTML file.
Sometimes my HTML source file contains diff amount of tables - less than 100, and of course my query on execution return error "3078: Cannot find Table...". To avoid this error I was trying to build this query dynamically, by using VBA code. So I have next logic:
Check if table exist
Build query string (add to string "UNION ALL SELECT * FROM [Table " & i & "]")
On Error = 3078 execute query(based on query string).
It works, but it takes a lot of time to check if table exist(each time database trying to link this table from source). Do I have another way to do it? Is it possible to return like "partial" result from the "long" query(only for those tables which exists and skip another one's) and do not check them separately?
Rather than trying to count how many records you have in a table for each table you have you can access your tables through the TableDef option. This will allow you to build your query faster than querying each table as a means of seeing whether it exists or not. It does require your tables to be currently linked though.
Dim db as DAO.Database
Dim wrk as DAO.Workspace
Dim tdf as DAO.TableDef
Set wrk = DBEngine.Workspaces(0)
Set db = wrk.OpenDatabase(databasePath, False, False, connection type/password)
For Each tdf in db.TableDefs
'Add it to your query string here.
Next
db.close
wrk.close
Set tdf = Nothing
Set db = Nothing
Set wrk = Nothing
One way to handle it would be to create ~100 local tables, one for each of the (potential) tables in the HTML source. That would be quite easy to do with VBA because the table structures would be identical. You could just do this once and then re-use the local tables (see below).
Then, when you want to retrieve the latest version of the data you could just
DELETE FROM the local tables to remove all existing rows
run a loop to INSERT INTO [local Table n] SELECT * FROM [Table n] until you "run out of" HTML tables (i.e., when you receive an error)
then run your long UNION ALL query against the local tables.
That way, all of the local tables will always exist. (If the HTML table didn't exist then its corresponding local table would simply be empty.)

SQL Query in Access to prompt with Message Box asking to change table name

Is there a way to be prompted before you a run an SQL query in Access, to enter in the table name that you wish to query? For example, lets say the columns will always stay constant. The columns could be called "Fruit" and "Date." But, the table name could change depending on the batch number. Ie. table name could be "BatchNO_1" or "BatchNO_2" or "BatchNO_3" etc. So Lets say i have an SQL like:
select Fruit, Date from BatchNO_1 where Fruit = "Apples"
Is there a way that I can be prompted to enter in the table name and have the SQL use the table name i enter to perform the query?
No. The table name cannot be passed as parameter to a query. You will have to construct the query yourself.
Dim tableName as String, sql As String
tableName = InputBox("Please enter the table name")
If tableName <> "" Then
sql = "SELECT Fruit, Date FROM [" & tableName & "] WHERE Fruit = 'Apples'"
'TODO: execute the query here
End If
For instance, you could change the query text of an existing query like this:
CurrentDb.QueryDefs("myQuery").SQL = sql
Or you could execute the query like this
Dim db As DAO.Database, rs As DAO.Recordset
Set db = CurrentDb
Set rs = db.OpenRecordset(sql)
Do Until rs.EOF
Debug.Print rs!Fruit & " " & rs!Date
rs.MoveNext
Loop
rs.Close: Set rs = Nothing
db.Close: set db = Nothing
By putting the batch number in the table name instead of as a column, you are encoding data in the schema. This is not best practice, so in my opinion, the correct answer is to change your database design.
Make a single Batch table with all the columns from your current BatchNo tables, but add a column named BatchNo as part of the primary key. Load all the data from your BatchNo tables into this one, and then delete those tables. Then your query will straightforwardly look like this:
SELECT Fruit, Date
FROM Batch
WHERE
Fruit = "Apples"
AND BatchNo = [Enter Batch No];
Don't put data in table names. That is not the way databases are supposed to be made.
Just to explain a little bit, the reason that your current design violates best practice is due to exactly the problem you are facing now--the shenanigans and weird things you have to do to work with such a design and try to perform operations in a reasonable, data-driven, way.
By having the user enter the table name, you also create the danger of SQL injection if you aren't also careful to compare the user-provided table name to a whitelist of allowed table names. While this may not be such a big deal in Access, it is still heading down the wrong path and is training for something else besides professional database work. If you would ever like to grow your career, it would be regrettable to first have to unlearn a bunch of stuff before you could even start with a "clean slate" to learn the right way to do things.

I want to go to last record of access database without using ID

I have been trying to find this. I am using access 2010 and I have some data in a few tables and I want to select the last row from each one and add them to a new database. All the databases have random ID so I can't use the Sort by ID function.
If the table is small, you can pass it to a datatable in the frontend and use something like this,
lastRow = datatable.rows(datatable.rows.count-1)
Else, You can add a 'created_datetime' field in database which holds the inserted datetime and retrieve its maximum date since your ID field has random number...
open vba (alt + F11)
dim rst as recordset
set rst = docmd.runsql (sql statement here) e.g. (select * from tablename)
rst.movelast
you've gotten to your last record in vba
you can add it to a new table database by using an insert statement.