I need some help with passing a parameter to a MySQL database table query. I have multiple unique tables which I need to query depending on the "client*" parameter.
In order to avoid writing endless if statements, I need a way to pass each unique client parameter .i.e "client1_" to the database query below. So instead of hard coding the "client1_accounts" etc in the query below each time, I need a way to be able to just attach the "client*" parameter to sections of the query where required and avoid writing an if statement as the parameter for each instance will be declared.
If tablePrefix = "client1_" Then
Set myconn = New ADODB.Connection
Set rs_client1_accounts = New ADODB.Recordset
myconn.Open "Driver={MySQL ODBC 3.51 Driver};server=" & frmSettings.Text1(0).Text & ";uid=" & frmSettings.Text1(2).Text & ";pwd=" & frmSettings.Text1(3).Text & ";database=" & frmSettings.Text1(1).Text & ""
mysql = "SELECT * FROM client1_accounts"
rs_client1_accounts.Open mysql, myconn, adOpenKeyset, adLockPessimistic
Do Until rs_client1_accounts.EOF = True
List1.AddItem rs_client1_accounts!account
rs_client1_accounts.MoveNext
Loop
ElseIf tablePrefix = "client2_ Then
.... etc ... etc
End if
I hope I've explained properly what I want to do but if I haven't please ask any question and I'll do my best to clarify.
Thanks for your help!
Instead of
mysql = "SELECT * FROM client1_accounts"
use
mysql = "SELECT * FROM " & tablePrefix & "accounts"
The result of the second example is a string concatenation identical to the string in the first example.
Related
I am told (and agree) that it is better to replace the SQL in an existing querydef, rather than delete and re-define the querydef each time the query needs to change. But my code only seems to work the second way. Here is the code I have that works:
Dim db As Database
Set db = CurrentDb
Dim QD As QueryDef
Dim mySql As String
mySql = ""
mySql = "TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code]"
On Error Resume Next
db.QueryDefs.Delete "qryX" 'Remove temporary query if exists
Set QD = db.CreateQueryDef("qryX", mySql) 'create temporary query
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Here is the code I can't get to work
Dim db As Database
Set db = CurrentDb
Dim QD As QueryDef
Dim mySql As String
mySql = " "
Set QD = db.CreateQueryDef(("qryX"), mySql)
mySql = "TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code]"
QD.SQL = mySQL 'overwrite query SQL
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Oddly, the second version doesn't throw any errors at me, but it doesn't make the crosstab table at all.
Edit: Maybe I wasn't clear enough. The problem is that the second set of code Does. Not. Execute. The. SQL. If it executed the code, I would be happy to re-write and use the same temp query over and over, but it does. not. execute. the. SQL..
Please respond with how to make the code in the second block actually execute the indicated SQL statement and build the desired table.
I know I have to remake a query if I delete it. Duh.
I know I "should" be able to re-use the same query if I can get the Set statement to properly overwrite the previous sql with the desired sql.
I know you all want to provide an answer, but please make it an answer to the question I am asking.
You can recycle the object if you don't delete it:
' On Error Resume Next
Set QD = db.QueryDefs("qryX")
QD.SQL = mySQL
DoCmd.RunSQL "SELECT * INTO tblDocsCrossTabX FROM qryX;"
Solved.
In the first block of code, when I delete and recreate the query, the string mySql contains a valid SQL statement, so Access is able to assign that SQL to the querydef when I completely recreate it with SET. Specifically,
mySql = "Transform..."
Comes Before
Set QD = db.CreateQueryDef("qryX", mySql)
In the second set of code, the string mySql contains only a space when the Set command is used, as " " is not a valid SQL Statement, the Set command won't even get executed, and the QueryDef QD never even gets created.
Specifically, the error in the second code occurs because
mySql = " " 'NOT a valid SQL Statement
comes before the attempt to create the queryDef
Set QD = db.CreateQueryDef(("qryX"), mySql) 'QD never gets created because mySql is not valid SQL
preventing the assignment of a valid SQL statement later, and so no table gets created.
If you can use a subquery, you can use a tempory QueryDef instead of bothering with checking forQueryDefalready existing or not, just combine the SELECT and the INSERT-Query to use a temporaryQueryDef
Unfortunally you can't useTransformin a subquery so this code leads toRuntime-Error 3129 Invalid SQL statement.
Sql = "SELECT * INTO tblDocsCrossTabX FROM (TRANSFORM COUNT(tblDocs.Document) AS CountOfDocument " & _
"SELECT tblDocs.[Contractor Dept], " & _
"COUNT(tblDocs.Document) AS [Total Of Document] " & _
"FROM tblDocs " & _
"GROUP BY tblDocs.[Contractor Dept] " & _
"PIVOT tblDocs.[Engineering Status Code])"
With CurrentDb.CreateQueryDef(vbNullString) 'or db.CreateQueryDef("") creates a not named and therefore temporary QueryDef
.SQL = Sql
.Execute dbFailOnError
End With
Sample of successful code.
Dim db As Database
Set db = CurrentDb
Dim QueryString As String
Dim QDDocsCross As QueryDef
Set QDDocsCross = db.CreateQueryDef("DocsCross")
QueryString = "TRANSFORM COUNT(Docs.Document) AS CountOfDocument " & _
"SELECT Docs.[Contractor Dept], " & _
"COUNT(Docs.Document) AS [Total Of Document] " & _
"FROM Docs " & _
"GROUP BY Docs.[Contractor Dept] " & _
"PIVOT Docs.[Engineering Status Code]"
QDDocsCross.SQL = QueryString
I am trying to make an Update to a Passthrough query using MS Access to an ODBC server that I have no control over. The reason I have to use a Passthrough is that the records I am accessing have more than 255 fields (I would use a linked table if I could).
I've been using this resource to get the data using Passthrough (http://www.techonthenet.com/access/tutorials/passthrough/basics09.php)
The query is simply: SELECT FullName, PointNumber FROM DNP3.CDNP3AnalogIn
The ODBC Connect Str is: ODBC;DSN=SCX6_DB;LOCATION=Main;UID=admin;PWD=password;LOCALTIME=False;
Now inside an Access Database I have a table (SCADA DB Tags) with same name for the Fields (FullName, PointNumber), and I want to update the fields inside the ODBC Database using an Update Passthrough query, but I am unsure how to do this.
I saved the previous Query as DNP3_CDNP3AnalogIn Query, and tried to make a new Query:
UPDATE [DNP3_CDNP3AnalogIn Query] INNER JOIN [SCADA DB Tags] ON
[DNP3_CDNP3AnalogInQuery].FullName = [SCADA DB Tags].FullName
SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = [SCADA DB Tags].[PointNumber];
But I get an error from Access: Operation must use an updateable query.
I know there is someway to do this but I can't seem to find an example (I might not be googling the correct phrase). Microsoft page (http://technet.microsoft.com/en-us/library/bb188204%28v=sql.90%29.aspx) says: There is, however, one important limitation: the results returned by SQL pass-through queries are always read-only. If you want to enable users to perform updates based on the data retrieved, you must write code to handle this. Unfortunately it doesn't give an example to do it!
Can anyone give me a solution, I can use VBA if required? I can also give more background if required. Unfortunately I'm not an expert in Access, I'm just trying to come up with an automated solution that could save me some time.
When they said that "If you want to enable users to perform updates based on the data retrieved [from a pass-through query], you must write code to handle this" they probably meant something like this:
Option Compare Database
Option Explicit
Public Sub UpdateSqlServer()
Dim cdb As DAO.Database, rst As DAO.Recordset
Dim con As Object ' ADODB.Connection
Dim cmd As Object ' ADODB.Command
Const adParamInput = 1
Const adInteger = 3
Const adVarWChar = 202
Set cdb = CurrentDb
Set rst = cdb.OpenRecordset( _
"SELECT " & _
"[SCADA DB Tags].FullName, " & _
"[SCADA DB Tags].PointNumber " & _
"FROM " & _
"[DNP3_CDNP3AnalogIn Query] " & _
"INNER JOIN " & _
"[SCADA DB Tags] " & _
"ON [DNP3_CDNP3AnalogIn Query].FullName = [SCADA DB Tags].FullName", _
dbOpenSnapshot)
Set con = CreateObject("ADODB.Connection")
con.Open "DSN=SCX6_DB;"
Set cmd = CreateObject("ADODB.Command")
cmd.ActiveConnection = con
cmd.CommandText = _
"UPDATE DNP3.CDNP3AnalogIn SET " & _
"PointNumber=? " & _
"WHERE FullName=?"
cmd.Parameters.Append cmd.CreateParameter("?", adInteger, adParamInput) ' PointNumber
cmd.Parameters.Append cmd.CreateParameter("?", adVarWChar, adParamInput, 255) ' FullName
cmd.Prepared = True
Do Until rst.EOF
cmd.Parameters(0).Value = rst!PointNumber
cmd.Parameters(1).Value = rst!FullName
cmd.Execute
rst.MoveNext
Loop
Set cmd = Nothing
con.Close
Set con = Nothing
rst.Close
Set rst = Nothing
Set cdb = Nothing
End Sub
Notes:
The code uses your existing ODBC DNS.
It uses a Prepared Statement to perform the updates, increasing efficiency and protecting against failures related to SQL Injection.
The source Recordset performs an INNER JOIN on the pass-through query to ensure that the code only tries to update rows on the server that actually exist on the server.
Are you saying that [DNP3_CDNP3AnalogIn Query] is server side based and that table [SCADA DB Tags] is local based? In that case you cannot use a pass-through query.
However since the tables ARE in different locations pass-though cannot touch BOTH at the same time.
You can however execute "single" server side (pass-though) in a loop. If you setup a pass-though query and SAVE it, then this code will work:
Dim qdfPass As DAO.QueryDef
Dim rstLocal As DAO.Recordset
Dim strSQL As String
Dim strSQL2 As String
Set qdfPass = CurrentDb.QueryDefs("MyPass")
strSQL = "UPDATE [DNP3_CDNP3AnalogIn Query] " & _
"SET [DNP3_CDNP3AnalogIn Query].[PointNumber] = 'xxxx' " & _
"WHERE [DNP3_CDNP3AnalogInQuery].FullName = 'zzzz' "
Set rstLocal = CurrentDb.OpenRecordset("[SCADA DB Tags]")
Do While rstLocal.EOF = False
strSQL2 = Replace(strSQL, "xxxx", rstLocal!PointNumber)
strSQL2 = Replace(strSQL2, "zzzz", rstLocal!FullName)
qdfPass.SQL = strSQL2
qdfPass.Execute
rstLocal.MoveNext
Loop
rstLocal.Close
I have two databases, a "Master" source (held locally) and a "Copy" database (to be distributed). Neither will be able to see each other once distributed (either locally or across a network), so we can't perform queries across the databases after distribution. I need to remove some content from the Copy database before it is distributed, so I decided to create a VBA script to produce the Copy databases for distribution.
There are lookups in the tables, so I have decided to hold a template database (which was copied from the master source, and then stripped the tables out of them), then am dropping the tables and have recreated them in an appropriate order.
I'm now needing to remove some of the data, and I'm struggling.
DeviceTable:
AutoNumber(ID)
Text(DeviceName)
Integer(ClusterID)
Text(Distribution)
ClusterTable:
AutoNumber(ID)
Text(ClusterName)
VirtualSystemTable:
AutoNumber(ID)
Text(VirtualSystemName)
Integer(ClusterID)
Integer(DeviceID)
InterfaceTable:
AutoNumber(ID)
Integer(VirtualSystemID)
Integer(ClusterID)
Integer(DeviceID)
Text(Description)
I need to remove entries from DeviceTable, ClusterTable, VirtualSystemTable and InterfaceTable for anything which is not marked as Distribution: "Public"
Normally I would do (in psudocode):
arrDEV = SQL("SELECT ID, ClusterID FROM DeviceTable WHERE Distribution<>"Public"")
Then, for each response, I would
arrVSYS = SQL("SELECT ID FROM VirtualSystemTable WHERE DeviceID=$arrDEV.ID OR ClusterID=$arrDEV.ClusterID")
SQL("DELETE FROM InterfaceTable WHERE DeviceID=$arrDEV.ID OR ClusterID=$arrDEV.ClusterID OR VirtualSystemID=$arrVSYS.ID")
SQL("DELETE FROM VirtualSystemTable WHERE DeviceID=$arrDEV.ID OR ClusterID=$arrDEV.ClusterID")
SQL("DELETE FROM ClusterTable WHERE ID=$arrDEV.ClusterID")
My issue is that I can't work out how to perform these queries across the database link. I amusing ADODB. I normally code in PHP, so this is a bit of a struggle for me!
You have the right idea but VBA is quite a bit different from PHP. You can't use variables inside strings with first exiting the string, concatenating the variable, and then starting the string again.
Where you would typically use an array called arrDev or arrVSys, we use a DAO Recordset or ADO Recordset object inside MS Access.
Updated answer to reflect the information you gave:
Dim db As DAO.Database
Dim sSQL as String
Dim arrDEV As DAO.Recordset, Dim arrVSYS as DAO.Recordset
Set db = OpenDatabase("C:\SomeDatabase.accdb")
sSQL = "SELECT ID, ClusterID FROM DeviceTable WHERE Distribution <> 'Public'"
Set arrDEV = db.Open(sSQL)
If Not (arrDEV.EOF and arrDEV.BOF) Then
arrDEV.movefirst
Do Until arrDEV.eof = True
sSQL = "SELECT ID FROM VirtualSystemTable WHERE DeviceID = " & arrDEV("ID") & _
" OR ClusterID = " & arrDEV("ClusterID")
Set arrVSYS = CurrentDb.Open(sSQl)
sSQL = "DELETE FROM InterfaceTable WHERE DeviceID = " & arrDEV("ID") & _
" OR ClusterID = " & arrDEV("ClusterID") & " OR VirtualSystemID = " & arrVSYS("ID")
CurrentDb.Execute sSQl, dbFailOnError
sSQL = "DELETE FROM VirtualSystemTable WHERE DeviceID = " & arrDEV("ID") & " OR ClusterID = " & arrDEV("ClusterID")
CurrentDb.Execute sSQl, dbFailOnError
sSQL = "DELETE FROM ClusterTable WHERE ID = " & arrDEV("ClusterID")
CurrentDb.Execute sSQl, dbFailOnError
arrVSYS.Close
arrDEV.MoveNext
Loop
End If
'Cleanup
Set arrVSYS = Nothing
arrDEV.Close
Set arrDEV = Nothing
db.close
Set db = Nothing
The code is untested and could have some errors. The only thing I didn't plan for was having more than one record in arrVSYS. If that recordset will have multiple records then you'll need yet another loop.
As you can see, you don't need to use ADO to access another Access database. But if the "outside" database is something other than Access then yes, you would need to use ADO.
Normally, I would just loop through using Recordset.AddNew, but this is painfully slow when dealing with large recordsets -- is there a better way to do it? I was hoping there would be a way to simply write an insert statement to go from Oracle to Access, perhaps by using two ADO connects, but the only examples I can find are in VB.net (using OleDbCommand), which is sadly not an option. Is this simply a limitation of VBScript?
Thanks!
Your question tags include access-vba, so I'll suggest the DoCmd.TransferDatabase Method.
This example, near the bottom of the page, is to create an ODBC link to a SQL Server table. It assumes a DSN (data source name) named DataSource1. The link name in Access will be Authors, and the server source table is named dboAuthors.
DoCmd.TransferDatabase acLink, "ODBC Database", _
"ODBC;DSN=DataSource1;UID=User2;PWD=www;LANGUAGE=us_english;" _
& "DATABASE=pubs", acTable, "Authors", "dboAuthors"
You can adapt that for Oracle with an appropriate DSN. And if you want to import rather than link, substitute acImport for acLink.
And actually, you might not even need code for this. With a working DSN, you can import (or link) via the Access user interface.
Your title mentioned VBScript. Tell us if you actually must use VBScript instead of VBA.
After reading your comments, I think you would be better of with a different approach.
Create a database with an ODBC link to the Oracle table.
Then export subsets of that table data to your individual database files.
SELECT master_link.* INTO local_table IN 'c:\somefolder\db1.mdb'
FROM master_link
WHERE location = 'location1';
Then adjust the SQL for each target db file and data selection criterion. It should be easy to drive that from a simple VBA procedure.
Here are a few notes for VBScript using SQL Server, rather than Oracle, however, it should be possible to use something very similar.
Const CreatePath = "Z:\docs\"
Const Provider = "Microsoft.ACE.OLEDB.12.0;"
''The easiest way to get this line is from the connect property of
''a linked table
Const ServerInLine = "[ODBC;DRIVER=SQL Server;SERVER=server;Trusted_Connection=Yes;DATABASE=db]"
''Change this to the Oracle connection
Const ServerConnect = "Provider=sqloledb;Data Source=server;Initial Catalog=db;Integrated Security=SSPI;"
Dim cnSS ''As ADODB.Connection
Dim cnMSA ''As ADODB.Connection
Dim cat ''As New ADOX.Catalog
Set cat = CreateObject("ADOX.Catalog")
Set cnSS = CreateObject("ADODB.Connection")
Set cnMSA = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cnSS.Open ServerConnect
''Only the locations that exist. Assuming a location table
''with a description, Location
sSQL = "SELECT DISTINCT a.LocationID, b.Location FROM ATable a "
sSQL = sSQL & "INNER JOIN Location b ON a.LocationID = b.ID"
rs.Open sSQL, cnSS
Do While Not rs.EOF
DBName = CreatePath & Trim(rs.Fields("Location")) & ".accdb"
scn = "Provider=" & Provider & ";Data Source=" & DBName
cat.Create scn
cnMSA.Open scn
sSQL = "SELECT * INTO " & Replace(Trim(rs.Fields("Location")), " ", "")
sSQL = sSQL & " FROM " & ServerInLine & ".ATable"
sSQL = sSQL & " WHERE LocationID=" & rs.Fields("LocationID")
cnMSA.Execute sSQL, recs
sMsg = sMsg & vbCrLf & DBName & " created " & recs
rs.MoveNext
cnMSA.Close
Loop
MsgBox sMsg
I'm migrating an Access Database to MySQL.
Most of the program works well but I still have a problem with an SQL query.
I obtain a 3197 Run Time Error :
The Microsoft Office Access database engine stopped the process because you and another user are attempting to change the same data at the same time.
What I have already done :
Configure my ODBC Driver to allow Dynamic Cursors
Configure my ODBC Driver to return matched rows instead of affected rows
The code which causes the error :
Dim rsMain As Recordset
Dim rs As Recordset
Dim db As Database
Set db = CurrentDb
Dim sqlQuery As String
sqlQuery = "Select * from Table1 where field1 like '" & Me.field10 & "*' and field2=" & Me.field11 & " and field3=True"
Set rsMain = db.OpenRecordset(sqlQuery)
rsMain.MoveFirst
Do Until rsMain.EOF
sqlQuery = "select sum(field4) as Est, sum(field5) as Cons, sum(field6) as Prod from Table1 where field1 like '" & rsMain("field1") & "*' and field3=False and field5=" & Me.modifiedDate
Set rs = db.OpenRecordset(sqlQuery)
rsMain.Edit
rsMain.Fields("field4") = rs.Fields("Est")
Set rs = Nothing
rsMain.Update
rsMain.MoveNext
Loop
Set rsMain = Nothing
The rsMain.Update command fails, it's where the error come from.
I have similar code which don't cause any error. I am the only user at the time.
Thanks in advance for your insights
Instead of the rsMain.Edit/Update I used directly the SQL update using DoCmd.RunSQL SQLQuery where SQLQuery is my updated SQL query.