Access: Issue Creating SQL View Through VBA - Unions not allowed in subquery - sql

First of all, let me preface this with something I almost always say in my few posts so far, which is that I'm not an IT/tech person. I'm an accountant who likes to dabble a little bit in SQL and so forth but with very minimal knowledge of VBA, so I apologize in advance if this is a super-easy question or it's already been covered. But I was not able to find anything directly related to this specific error.
Trying to use MS Access to create a view from SQL that includes a Union and getting the following error: Run-time error '-2147217900 (800040e14)': Unions not allowed in a subquery. Code is as follows:
Sub Create_View()
Dim conn As ADODB.Connection
Set conn = CurrentProject.Connection
conn.Execute "CREATE VIEW Test_VW AS SELECT A.Unit as Unit, A.Spend as Spend, A.Date as Date, A.Type as Type FROM Table1 A UNION ALL SELECT B.Unit as Unit, B.Spend as Spend, B.Date as Date, B.Type as Type FROM Table2 B;"
Application.RefreshDatabaseWindow
End Sub
This is the code as it is right now, but I've also tried UNION instead of UNION ALL, SELECT * FROM both tables as opposed to the individual columns (both tables are only the 4 listed columns, which are also the same data type), and with the columns and tables unaliased.
Something I should point out that maybe could be the issue, but I wouldn't think it is is that the "Tables" in the code are actually views that I created in Access without VBA (as in just regular SQL). These now appear as "Queries" in the database. However, I did write the VBA with the initial SQL that's defining the views, and I returned the same error. So I don't think that's the issue.
EDIT: Also, I should point out that to test, I was able to create a view from the same VBA for the top level query without the UNION.
At any rate, I'm not sure where the subquery is in the SQL, so maybe it's a syntax error?
Any help would be greatly appreciated. Thanks!

That error message, "Unions not allowed in a subquery", is not very helpful in your situation.
Access supports 2 DDL operations related to queries: CREATE VIEW; and CREATE PROCEDURE.
CREATE VIEW can be used for only simple SELECT queries. CREATE PROCEDURE must be used for more complicated SELECT queries (such as UNION) and for "action" queries.
So you could avoid your current error by using CREATE PROCEDURE instead of CREATE VIEW. However you would then encounter a different error, "The SELECT statement includes a reserved word or an argument name that is misspelled or missing, or the punctuation is incorrect", due to unbracketed reserved words used as column aliases. You can drop the unneeded column aliases to avoid that error.
Here's an adaptation of your code which worked for me in Access 2010.
Dim strSql As String
strSql = "CREATE PROCEDURE Test_VW AS" & vbCrLf & _
"SELECT A.Unit, A.Spend, A.Date, A.Type FROM Table1 A" & vbCrLf & _
"UNION ALL SELECT B.Unit, B.Spend, B.Date, B.Type FROM Table2 B;"
CurrentProject.Connection.Execute strSql

QueryDefs can handle UNION. Alias field and table names are not needed.
Sub test()
Dim qdf As DAO.QueryDef
Set qdf = CurrentDb.CreateQueryDef("TestVW", "SELECT Unit, Spend, Date, Type FROM Table1 " & _
"UNION ALL SELECT Unit, Spend, Date, Type FROM Table2;"
Application.RefreshDatabaseWindow
End Sub
Strongly advise not to use reserved words like Date as names.

Related

Operation must use and updatable query. (Error 3073)

What is wrong with my logic below, is there any alternative to get calculatable column which will sum Balances for every unique KEY ?
Purpose: To create a summary column, calculation of Balances for each unique Key created ( Sort Code + Source Account) which will be used later to define whether acc type is Dr/Cr.
Code: below code should create summary column , but every time it triggers error depicted in attached screenshot.
***' Creating Sum of Balances based on Key , to differtiate Dr/Cr Account types
DoCmd.RunSQL "ALTER TABLE Output_File ADD Summing varchar(255)"
DoCmd.RunSQL "UPDATE Output_File SET Summing =" _
& "(SELECT SUM(Output_File.CURR_VALUE)" _
& " FROM Output_File GROUP BY Output_File.`UNIQUE KEYS`)"***
Error:
Error
In MS Access SQL, update queries must be updateable or not read-only. Any use of subqueries renders the query read-only. See Allen Browne's Why is my query read-only? One workaround is to use domain aggregates such as DSum available in Access SQL and VBA.
Ideally, too, consider using a saved query and avoid the need of building long SQL statements in VBA and have to worry about line breaks and concatenations. Below assumes UNIQUE KEYS is a number field. If text field, wrap in single quotes. If a date field, wrap in hashtags/pound symbols.
SQL (save as stored query)
UPDATE Output_File o
SET Summing = DSum("CURR_VALUE", "Output_File", "`UNIQUE KEYS` = " & o.`UNIQUE KEYS`)
VBA (reference above saved query)
DoCmd.OpenQuery "mySavedQuery" ' NO NEED TO CLOSE ACTION QUERIES
CurrentDb.Execute "mySavedQuery" ' ALTERNATIVE CALL

Access VBA dump recordset into an existing table

I have a recordset and a table, both in exactly the same format. What is the syntax to dump everything in the recordset to the table? This seems to be a very simple procedure but somehow I can't find any useful information online.
Edit1: to clarify, the recordset is obtained from Table A, now I want to dump it into Table B (which is empty). Table A and B have exactly the same format.
Edit2: I am working in Access.
here is the code I used to open the recordset:
Set Table_B_rs = CurrentDb.OpenRecordset("Table_B")
I didn't make any changes to the recordset.
Thanks for the help!
You don't do this with recordsets, but with SQL by running an INSERT INTO query.
CurrentDb.Execute "INSERT INTO TableB SELECT * FROM TableA " & _
"WHERE <same conditions you used to open the recordset>"
If there is no condition, it's simply
CurrentDb.Execute "INSERT INTO Table_B SELECT * FROM Table_A"

Using SQL statement to add a query to table

I am trying to add a query result to a table in MS Access 2010 by running a SQL statement, but I get a time-run error saying
Microsoft Access can not find the input table or query. make sure it exists and the name is spelled correctly.
This is my code, please help me to check where I am wrong.
Private Sub Command6_Click()
Dim strSql As String
strSql = "INSERT INTO test(ConsumedDate, FinishedProudct, ConsumedItem, ConsumptionQuantity, Unit), SELECT ProductDate, ProductCode, [Ingredient/Packaging material],Consumption, FROM FormulaQuery"
CurrentDb.Execute (strSql)
End Sub
Another question, can I use a datasheet form as input source in such condition?
Thanks
Jiangzhou
...,Consumption, FROM FormulaQuery"
there is some comma in plus ;)

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.

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

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.