ms access query with loop to create multiple tables - sql

I have one table in oracle database - which will have two columns (project name, view name). In that table when you filter project name, we will get all view names related to that project, based on those view names again we need to write query like select * from projectname$viewaname; to fetch that view related data.
Doing this manually is taking long time for each project. So my idea is to create MS ACCESS database to create tables for selected project and export them as excel files to C:\temp folder.
I need your help to create multiple tables in one go (using query/passthrough query or any other option) in MS Access fetching data from oracle database.
For that I have created MS access file, created one linked table (in which i have project and view names).
After that I have created one form, using project field as combo box from linked table and updated settings like, this form should be opened at start-up.
When I open access file, automatically this form is opening and asking me to enter oracle database user id and password - after entering credentials, combo box is updating and I can select my project in that list.
After that, I have created one query using main table and applied filter condition based on the selection in the form. Now I got results like project and view name for the end user selected project.
I need your help like,
now we have data in table like below.
Project | Viewname
A | A1
A | A2
A | A3
A | A4
A | A5
SQL query to see individual view data is :
select * from projectname$view_name;
ex: select * from A$A1;
project name, view name and no of rows(views), columns in views are dynamic - will change based on project.
I need your help to create multiple tables(one per one view) dynamically - Please suggest me the best option.
Regards,
Murali

Consider iteratively looping through the project/view name query in a recordset and creating the pass-through query that then exports to an Excel spreadsheet.
Public Sub ImportOracleProjectViews()
Dim db As Database, rst As Recordset, qdef As QueryDef
Dim constr As String, strSQL As String, mkTBL As String
Set db = CurrentDb
' ENTER QUERY HOLDING PROJECT AND VIEW NAMES '
Set rst = db.OpenRecordset("QUERYNAME")
' DELETE TEMP QUERYDEF IF EXISTS '
For Each qdef In db.QueryDefs
If qdef.Name = "temp" Then
db.QueryDefs.Delete ("temp")
End If
Next qdef
If rst.RecordCount = 0 Then Exit Sub
rst.MoveLast: rst.MoveFirst
' LOOP THROUGH EACH RECORD OF RECORDSET '
Do While Not rst.EOF
' SQL STATEMENTS '
strSQL = "SELECT * FROM " & rst!projectname & "$" & rst!viewname
' ORACLE CONNECTION STRING '
constr = "ODBC;Driver={Microsoft ODBC for Oracle};Server=myServerAddress;" _
& "Uid=myUsername;Pwd=myPassword;"
' PASS THRU QUERY '
Set qdef = db.CreateQueryDef("temp")
qdef.Connect = constr
qdef.SQL = strSQL
qdef.Close
' EXPORT TO MS EXCEL SPREADSHEET '
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel12Xml, temp, _
"C:\Path\To\Output\Folder\" & rst!projectname & "_" & rst!viewname & ".xlsx", _
True
rst.MoveNext
Loop
rst.Close
Set rst = Nothing
Set qdef = Nothing
Set db = Nothing
MsgBox "Successfully imported views to local tables and " _
& "Excel spreadsheets!", vbInformation
End Sub
Resources
Open Recordset VBA
Method
Oracle Connections
Strings
Creating Pass-Through Query in VBA Code

You have asked multiple questions, so the answer is structured correspondingly:
In order to create MS Access Table using VBA refer to the following sample code snippet:
Public Sub CreateTableVBA()
Dim SQL As String
SQL = "CREATE TABLE ThisTable " & "(FirstName CHAR, LastName CHAR);"
DoCmd.RunSQL SQL
End Sub
In order to create multiple Tables you should have an array of Table names and corresponding array of SQL statements, like the one shown above. Then you can loop through the array using VBA For-Next code block, running DoCmd.RunSQL command.
Alternatively, instead of DoCmd.RunSQL you may use Execute() function on VBA Database object, like shown below:
Sub CreateTableXSQL()
Dim dbs As Database
' include the path to MyDb.mdb on your computer.
Set dbs = OpenDatabase([Path to MyDb.mdb])
' create a table SQL with two text fields.
dbs.Execute "CREATE TABLE ThisTable " & "(FirstName CHAR, LastName CHAR);"
dbs.Close
End Sub
Hope this may help.

Related

Export select query with VBA in Access

My app is developed with Access.
I am trying to:
generate a select query
export the result in an Outlook mail (or at least in Excel)
destroy the query at the end so there are no duplicates
My code:
Private Sub Commande24_Click()
Dim db As Database
Dim Qdf As QueryDef
Dim strSQL As String
Dim matr As Double
matr = DLookup("Matricule", "Employée", "Nom = '" & Me.Nom & "'")
strSQL = "SELECT Employée.Matricule, Employée.Département, Employée.Nom, Employée.Prénom, Employée.Grade, Employée.Silo, Entree.date_entree_g, Sortie.Date_sortie_e, Sortie.Type_s FROM (Employée INNER JOIN Entree ON Employée.N° = Entree.N_emp) INNER JOIN Sortie ON Employée.N° = Sortie.N_emp WHERE Employée.Matricule = '" & matr & "'"
Debug.Print sql
You dont have to write a single line of code to achieve this. Ms access using macros can do it.
Create a delete query that will delete all values from the table
Create a select query,for the values you want to export to excel
Create a report using the select query as the record source
Create a macro with two actions
A. Export with formating( use the report name in 3 above as object name, and report as object type,output format-choose excel
B Open query ,choose the delete query
Then attach the macro to a command button on click event.

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 can I add criteria based on a form field to an Access query?

How do I get an operator to work in a query criteria based on a form field. Ideally I would like it to be something like:
IIf([Afloat]="No",<[Forms]![DASF]![Text222],"")
When I remove the operator it finds anything exactly to the criteria in that field but the moment I try to put an operator like greater than or less than it does not work. I am trying to find all records less than the value in that form field.
Any advice on how I can fix this? Or is it not possible in MS Access?
QBF (Query By Form) can't accept operators in the formula. Your only option is to write the query on the fly. You can use the CreateQueryDef method to define the SQL in a specific query, and attach your form or report to the specific query name.
Something like:
Dim db as Database
Dim rec as Recordset
Dim qdf As QueryDef
Dim strSQL as String
Set db = CurrentDB
On Error Resume Next
'First, delete the query if it exists
db.QueryDefs.Delete "MyQueryName"
'Then, set up the query string
strSQL = "Select * From MyTable Where MyField < " & [Forms]![DASF]![Text222] & " and [Afloat] = 'No' "
strSQL = strSQL & "UNION "
strSQL = strSQL & "Select * From MyTable Where MyField = '' and [Afloat] <> 'No' "
'Now, recreate the query
Set qdf = db.CreateQueryDef("MyQueryName", strSQL)
DoCmd.OpenQuery qdf.Name
You could try changing the first criteria to:
>IIf([Afloat]="No",[Forms]![DASF]![Text222])
And then add a second criteria below it in the Or line:
=IIf([Afloat]<>"No","")
I ended up solving my problem by separating it into two separate queries. Below are my steps:
Instead of having a logical expression to decide I separated it into
FLOAT and NONFLOAT queries.
Then I created a command button to open
each query depending on the criteria in a combo box (yes or no).
Here is the code:
Private Sub Command2_Click()
DoCmd.SetWarnings False
If Me.Combo272 = "Yes" Then
DoCmd.OpenQuery "DASF_AGED_AS1_FLOAT", acViewNormal, acEdit
Else
DoCmd.OpenQuery "DASF_AGED_AS1_NONFLOAT", acViewNormal, acEdit
End If
End Sub
This created another problem, I was still unable to reference the txt boxes necessary for my query criteria. To solve this, I made all the text boxes unbound by using the below VBA to auto populate the text boxes based on another combo box. Here is the VBA I used:
Me.Text220 = DLookup("REGION", "TDD_TABLE", "[ID]= " & Me.Combo236)

How to run parameterized query from VBA. Parameters sourced from recordset

I have a form where a user selects a vendor's name from a combobox, whose catalog file is to be imported. The combobox selection then drives a query to create a one-record recordset (rsProfile) containing several profile variables queried from a table of all vendor profiles. These variables are then used in a series of different queries to reformat, translate and normalize the vendor's uniquely structured files to a standardized format that can be imported into our system.
I am frustrated that I can't figure out how to build my stored queries that will use one or more parameters that are automatically populated from the profile recordset.
Here is my rsProfile harvesting code. It works. Note that intVdrProfileID is a global variable set and used in other places.
Private Sub btn_Process_Click()
Dim ws As Workspace
Dim db, dbBkp As DAO.Database
Dim qdf As DAO.QueryDef
Dim rsProfile, rsSubscrip As Recordset
Dim strSQL As String
Dim strBkpDBName As String
Dim strBkpDBFullName As String
strBkpDBName = Left(strVdrImportFileName, InStr(strVdrImportFileName, ".") - 1) & "BkpDB.mdb"
strBkpDBFullName = strBkpFilePath & "\" & strBkpDBName
Set db = CurrentDb
Set ws = DBEngine.Workspaces(0)
MsgBox ("Vendor Profile ID = " & intVdrProfileID & vbCrLf & vbCrLf & "Backup file path: " & strBkpFilePath)
' Harvest Vendor Profile fields used in this sub
strSQL = "SELECT VendorID, Div, VPNPrefix, ImportTemplate, " & _
"VenSrcID, VenClaID, ProTyp, ProSeq, ProOrdPkg, ProOrdPkgTyp, JdeSRP4Code, " & _
"PriceMeth, " & _
"ProCost1Frml, ProCost2Frml, " & _
"ProAmt1Frml, ProAmt2Frml, ProAmt3Frml, ProAmt4Frml, ProAmt5Frml " & _
"FROM tZ100_VendorProfiles " & _
"WHERE VendorID = " & intVdrProfileID & ";"
Set qdf = db.QueryDefs("qZ140_GetProfileProcessParms")
qdf.SQL = strSQL
Set rsProfile = qdf.OpenRecordset(dbOpenSnapshot)
DoCmd.OpenQuery "qZ140_GetProfileProcessParms"
' MsgBox (qdf.SQL)
I have used QueryDefs to rewrite stored queries at runtime, and although it works, it is quite cumbersome and does not work for everything.
I was hoping for something like the sample below as a stored query using DLookups. I can get this to work in VBA, but I can't get anything to work with stored queries. I am open to other suggestions.
Stored Query "qP0060c_DirectImportTape":
SELECT
DLookUp("[VPNPrefix]","rsProfile","[VendorID]=" & intVdrProfileID) & [PartNo] AS VenPrtId,
Description AS Des,
DLookup("[Jobber]","rsProfile",[VendorID=" & intVdrProfileID) AS Amt1,
INTO tP006_DirectImportTape
FROM tJ000_VendorFileIn;
ADDENDUM:
Let me adjust the problem to make it a bit more complex. I have a collection of about 40 queries each of which use a different collection of parameters (or none). I also have a table containing the particular set of queries that each vendor 'subscribes' to. The goal is to have a database where a non-coding user can add new vendor profiles and create/modify the particular set of queries which would be run against that vendor file. I have almost 100 vendors so far, so coding every vendor seperately is not practical. Each vendor file will be subjected to an average of 14 different update queries.
Simplified Example:
Vendor1 file needs to be processed with queries 1, 2 and 5. Vendor2 file might need only update queries 2 and 4. The parameters for these queries might be as follows:
query1 (parm1)
query2 (parm1, parm4, parm8, parm11)
query4 (parm5, parm6, parm7, parm8, parm9, parm10, parm11)
query5 () -no parms required
This is the core query processing that loops through only the queries relevant to the current vendor file. rsSubscrip is the recordset (queried from a master table) containing this filtered list of queries.
' Run all subscribed queries
MsgBox "Ready to process query subscription list."
With rsSubscrip
Do While Not .EOF
db.Execute !QueryName, dbFailOnError
.MoveNext
Loop
.Close
End With
You can set the parameters of a predefined query using the syntax;
Set qdf = CurrentDB.QueryDefs(QueryName)
qdf.Parameters(ParameterName) = MyValue
To add parameters to the query, add the following before the SELECT statement in the sql
PARAMETERS [ParameterOne] DataType, [ParameterTwo] DataType;
SELECT * FROM tblTest;

Does MS access(2003) have anything comparable to Stored procedure. I want to run a complex query in MS acceess

I have a table, call it TBL. It has two columns,call them A and B. Now in the query I require one column as A and other column should be a comma seprated list of all B's which are against A in TBL.
e.g. TBL is like this
1 Alpha
2 Beta
1 Gamma
1 Delta
Result of query should be
1 Alpha,Gamma,Delta
2 Beta
This type of thing is very easy to do with cursors in stored procedure. But I am not able to do it through MS Access, because apparently it does not support stored procedures.
Is there a way to run stored procedure in MS access? or is there a way through SQL to run this type of query
You can concatenate the records with a User Defined Function (UDF).
The code below can be pasted 'as is' into a standard module. The SQL for you example would be:
SELECT tbl.A, Concatenate("SELECT B FROM tbl
WHERE A = " & [A]) AS ConcA
FROM tbl
GROUP BY tbl.A
This code is by DHookom, Access MVP, and is taken from http://www.tek-tips.com/faqs.cfm?fid=4233
Function Concatenate(pstrSQL As String, _
Optional pstrDelim As String = ", ") _
As String
'example
'tblFamily with FamID as numeric primary key
'tblFamMem with FamID, FirstName, DOB,...
'return a comma separated list of FirstNames
'for a FamID
' John, Mary, Susan
'in a Query
'(This SQL statement assumes FamID is numeric)
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =" & [FamID]) as FirstNames
'FROM tblFamily
'===================================
'
'If the FamID is a string then the SQL would be
'===================================
'SELECT FamID,
'Concatenate("SELECT FirstName FROM tblFamMem
' WHERE FamID =""" & [FamID] & """") as FirstNames
'FROM tblFamily
'===================================
'======For DAO uncomment next 4 lines=======
'====== comment out ADO below =======
'Dim db As DAO.Database
'Dim rs As DAO.Recordset
'Set db = CurrentDb
'Set rs = db.OpenRecordset(pstrSQL)
'======For ADO uncomment next two lines=====
'====== comment out DAO above ======
Dim rs As New ADODB.Recordset
rs.Open pstrSQL, CurrentProject.Connection, _
adOpenKeyset, adLockOptimistic
Dim strConcat As String 'build return string
With rs
If Not .EOF Then
.MoveFirst
Do While Not .EOF
strConcat = strConcat & _
.Fields(0) & pstrDelim
.MoveNext
Loop
End If
.Close
End With
Set rs = Nothing
'====== uncomment next line for DAO ========
'Set db = Nothing
If Len(strConcat) > 0 Then
strConcat = Left(strConcat, _
Len(strConcat) - Len(pstrDelim))
End If
Concatenate = strConcat
End Function
I believe you can create VBA functions and use them in your access queries. That might help you.
There is not a way that I know of to run stored procedures in an Access database. However, Access can execute stored procedures if it is being used against a SQL backend. If you can not split the UI to Access and data to SQL, then your best bet will probably be to code a VBA module to give you the output you need.
To accomplish your task you will need to use code. One solution, using more meaningful names, is as follows:
Main table with two applicable columns:
Table Name: Widgets
Field 1: ID (Long)
Field 2: Color (Text 32)
Add table with two columns:
Table Name: ColorListByWidget
Field 1: ID (Long)
Field 2: ColorList (Text 255)
Add the following code to a module and call as needed to update the ColorListByWidget table:
Public Sub GenerateColorList()
Dim cn As New ADODB.Connection
Dim Widgets As New ADODB.Recordset
Dim ColorListByWidget As New ADODB.Recordset
Dim ColorList As String
Set cn = CurrentProject.Connection
cn.Execute "DELETE * FROM ColorListByWidget"
cn.Execute "INSERT INTO ColorListByWidget (ID) SELECT ID FROM Widgets GROUP BY ID"
With ColorListByWidget
.Open "ColorListByWidget", cn, adOpenForwardOnly, adLockOptimistic, adCmdTable
If Not (.BOF And .EOF) Then
.MoveFirst
Do Until .EOF
Widgets.Open "SELECT Color FROM Widgets WHERE ID = " & .Fields("ID"), cn
If Not (.BOF And .EOF) Then
Widgets.MoveFirst
ColorList = ""
Do Until Widgets.EOF
ColorList = ColorList & Widgets.Fields("Color").Value & ", "
Widgets.MoveNext
Loop
End If
.Fields("ColorList") = Left$(ColorList, Len(ColorList) - 2)
.MoveNext
Widgets.Close
Loop
End If
End With
End Sub
The ColorListByWidget Table now contains your desired information. Be careful that the list (colors in this example) does not exceed 255 characters.
No stored procedures, no temporary tables.
If you needed to return the query as a recordset, you could use a disconnected recordset.
Perhaps instead of asking if Jet has stored procedures, you should explain what you want to accomplish and then we can explain how to do it with Jet (it's not clear if you're using Access for your application, or just using a Jet MDB as your data store).
Well, you can use a Recordset object to loop through your query in VBA, concatenating field values based on whatever criteria you need.
If you want to return the results as strings, you'll be fine. If you want to return them as a query, that will be more complicated. You might have to create a temporary table and store the results in there so you can return them as a table or query.
You can use GetString in VBA which will return the recordset separated by any value you like (e.g. comma, dash, table cells etc.) although I have to admit I've only used it in VBScript, not Visual Basic. W3Schools has a good tutorial which will hopefully lend itself to your needs.
You can write your stored procedure as text and send it against the database with:
Dim sp as string
sp = "your stored procedure here" (you can load it from a text file or a memo field?)
Access.CurrentProject.AccessConnection.Execute sp
This supposes you are using ADODB objects (ActiveX data Objects Library is coorectly referenced in your app).
I am sure there is something similar with DAO ...
#Remou on DHookom's Concatenate function: neither the SQL standard nor the Jet has a CONCATENATE() set function. Simply put, this is because it is a violation of 1NF. I'd prefer to do this on the application side rather than try to force SQL to do something it wasn't designed to do. Perhaps ACE's (Access2007) multi-valued types is a better fit: still NFNF but at least there is engine-level support. Remember, the question relates to a stored object: how would a user query a non-scalar column using SQL...?
#David W. Fenton on whether Jet has stored procedures: didn't you and I discuss this in the newsgroups a couple of years ago. Since version 4.0, Jet/ACE has supported the
following syntax in ANSI-92 Query Mode:
CREATE PROCEDURE procedure (param1 datatype[, param2 datatype][, ...]) AS sqlstatement;
EXECUTE procedure [param1[, param2[, ...]];
So Jet is creating and executing something it knows (in one mode at least) as a 'procedure' that is 'stored' in the MDB file. However, Jet/ACE SQL is pure and simple: it has no control-of-flow syntax and a PROCEDURE can only contain one SQL statement, so any procedural code is out of the question. Therefore, the answer to whether Jet has stored procedures is subjective.