I have an Access Database and I'm using a pass through query to return records from an AS400 table. The connection string and pass through query work fine, but now I'm trying to populate the results of the p-t query into a local table within the db and my code is timing out. This is my first attempt at ADO so I'm disclaiming my code with "I'm not 100% sure what I'm doing!". Could you look at this and see if there is something obvious that I'm doing wrong? Any direction would be appreciated. Thank you in advance.
Sub mod_ADODBConnect()
Const NewTableName = "MyNewTable"
Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset
Dim db As DAO.Database
Dim sSQL1 As String
Dim sSQL2 As String
sSQL1 = "SELECT ITMNUM, ITMDS, ITPKDS, MJCMCD, SBCMCD, STATUS, PRITIN, OGEXDT from PDBLLIB007.BLPMST07"
sSQL2 = "INSERT INTO ' & NewTableName & ' SELECT [" & sSQL1 & "].* from [" & sSQL1 & "]"
Set cn = New ADODB.Connection
cn.Open "Driver={Client Access ODBC Driver (32-bit)};" & _
"System=DC007; Uid=XXXXX; Pwd=XXXXXX; MgDSN=0; ConnType=2;" & _
"BlockSize=512; MaxFieldLen=2048; LazyClose=1; Prefetch=1; QueryTimeOut=0; Translate=1"
Set rs = New ADODB.Recordset
rs.Open sSQL1, cn, adOpenDynamic, adLockOptimistic
Do While Not rs.EOF
rs.MoveNext
Loop
Set db = CurrentDb
db.Execute ("sSQL2")
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
Set db = Nothing
End Sub
You have a pass-through query which works fine and returns the rows you want. Now you want to store those rows in a new local (Jet/ACE) table. Seems to me a simpler approach would be to use the pass-through as the data source in a new "make table" query.
SELECT * INTO MyNewTable FROM YourPassThruQuery;
Oops, looks like you meant to append those rows to an existing table.
INSERT INTO MyNewTable
SELECT * FROM YourPassThruQuery;
If the table structures don't match, you can use field lists for both tables.
INSERT INTO MyNewTable (fld1, fld2)
SELECT first_field, second_field FROM YourPassThruQuery;
Related
This question already has answers here:
ASP 3.0 Declare ADO Constants w/out Including ADOVBS.inc
(3 answers)
Closed 12 months ago.
I have a piece of VBScript that queries an MS Access database. When the recordset query is on a table, I can go through my recordset and do a rs.MoveFirst to go back to the beginning. But when the recordset query is on a query, rs.MoveFirst fails with the error "Operation is not supported for this type of object" Code: 800004005.
Is this a known limitation? Can I get get around it by opening the recordset in a different way?
I have tried rs.Open like many examples online, but rs.Open strQuery, Cn, adOpenDynamic, adLockPessimistic, adCmdText fails with "Arguments are of the wront type, are out of acceptable range, or are in conflict with one another."
This code works because MyTable is a table:
Set rs = CreateObject("ADODB.Recordset")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\MyAccessDB.accdb;Mode=Read;"
connection.Open strConnection
Set rs = connection.Execute("SELECT * FROM MyTable")
MsgBox(rs.fields(1))
rs.MoveNext
rs.MoveFirst
MsgBox(rs.fields(1))
This code fails because MyQuery is a query in the database
Set rs = CreateObject("ADODB.Recordset")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\MyAccessDB.accdb;Mode=Read;"
connection.Open strConnection
Set rs = connection.Execute("SELECT * FROM MyQuery")
MsgBox(rs.fields(1))
rs.MoveNext
rs.MoveFirst
MsgBox(rs.fields(1))
Using rs.Open and defining the constants does not work. This shows the same error "Operation is not supported for this type of object" on the rs.movefirst command.
const adOpenDynamic = 2
const adLockPessimistic = 2
const adCmdText = 1
Set connection = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\MyAccessDB.accdb;Mode=Read;"
connection.Open strConnection
strsql = "SELECT * FROM MyQuery"
rs.Open strsql, connection, adOpenDynamic, adLockPessimistic, adCmdText
Do While Not rs.EOF
msgbox(rs.fields(1))
rs.movenext
msgbox(rs.fields(1))
rs.movefirst
msgbox(rs.fields(1))
Loop
There is a far easier way to deal with this problem and that is to negate ADODB.Recordset entirely and not have to worry about cursor and locking support. It's worth mentioning this will only work for reading the data.
Use GetRows() to retrieve a two-dimensional Array and use that to navigate the data.
Dim strConnection, connection, rs, data
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\MyAccessDB.accdb;Mode=Read;"
Call connection.Open(strConnection)
Set rs = connection.Execute("SELECT * FROM MyTable")
If Not rs.EOF Then data = rs.GetRows()
'Release recordset as it's no longer needed.
Call rs.Close()
Set rs = Nothing
Dim row, rows
Const fld_field1 = 1
If IsArray(data) Then
rows = UBound(data, 2) 'Number of rows
row = 0
Call MsgBox(data(fld_field1, row) 'Second column of First Row
row = 1
Call MsgBox(data(fld_field1, row) 'Second column of Second Row
row = 0
Call MsgBox(data(fld_field1, row) 'Second column of First Row
'If you want to loop the data
For row = 0 To rows
Call MsgBox(data(1, row) 'Second Column of N Row
Next
End If
This will work.
You don't need to declare const, variables, whatelse.
You just need to set a reference to ADODB, in your case a reference to Microsoft Activex Data Objects 2.8 Library.
There is no reason this would not work.
Set Connection = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
Dim strConnection
Dim sql
strConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\MyAccessDB.accdb;Mode=Read;"
Connection.Open strConnection
sql = "SELECT * FROM MyQuery"
rs.Open sql, Connection, adOpenStatic, adLockReadOnly, adCmdText
MsgBox (rs.Fields(1))
rs.MoveNext
MsgBox (rs.Fields(1))
rs.MoveFirst
MsgBox (rs.Fields(1))
rs.Close
Set rs = Nothing
Connection.Close
Set Connection = Nothing
EDIT: I overlooked the fact you wrote "piece of vbscript". If you are using this code in a vbs file, then you need to declare the constants
Const adOpenStatic = 3
Const adLockReadOnly = 1
Const adCmdText = &H0001
I am trying to retrieve records from a table in access using VBA. So far I have this simple function:
Private Function GNCN() As String
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim cm As ADODB.Command
Dim strSQL As String
Dim intYD As Integer
Set cn = CurrentProject.Connection
'cn.CursorLocation = adUseClient
rs.CursorLocation = adUseClient
rs.LockType = adLockReadOnly
intYD = 16
strSQL = "SELECT DCN FROM tblDCD WHERE (DCN like '" & intYD & "*')"
Set rs = cn.Execute(strSQL)
Debug.Print rs.RecordCount
Set rs = Nothing
Set cm = Nothing
Set cn = Nothing
End Function
When I run this, I don't get any records returned.
However if I take the SQL query:
SELECT DCN FROM tblDCD WHERE (DCN like '16*')
and run this within Access' query builder, I get around 912 records returned, so I know I am able to retrieve the records and that the query itself appears to be correct.
The table is simple data which consists of string values such as (in the DCN column):
"13000"
"17001"
"16003"
Around 38000 in total so I shaln't print them all here...
Does anyone know why this will work via the query builder but not via VBA?
Thanks
Appear to be mixing DAO and ADODB. Consider:
Private Function GNCN() As String
Dim rs As DAO.Recordset
Dim strSQL As String
Dim intYD As Integer
intYD = 13
strSQL = "SELECT DCN FROM Rates WHERE DCN like '" & intYD & "*';"
Set rs = CurrentDb.OpenRecordset(strSQL)
rs.MoveLast
Debug.Print rs.RecordCount
Set rs = Nothing
End Function
So I want to insert the result of a query into an array then I will loop over the array to insert new rows to a new table.
Here is the code I've done:
Public cnn As New ADODB.Connection
Public db As DAO.Database
Public Sub SUD_Main()
Set db = Access.Application.CurrentDb
Set cnn = CurrentProject.Connection
Refreash
End Sub
Private Sub Refreash()
Dim DataArr() As String
Dim p As Variant
Dim sql As String
Dim XDATA As New ADODB.Recordset
Dim RDS As DAO.Recordset
Set RDS = db.OpenRecordset("tbl_dets")
sql = "SELECT DISTINCT NAME FROM Types_tbl WHERE NAME LIKE 'Rob%'"
XDATA.Open sql, cnn, adOpenStatic
'''
'' HERE I WANT TO FILL DataArr FROM XDATA
'''
DataArr = XDATA.GetRows
XDATA.Close
For Each p In DataArr
sql = "SELECT DISTINCT TID FROM Types_tbl WHERE NAME ='" & p & "'"
XDATA .Open sql, cnn, adOpenStatic
Do Until XDATA.EOF
DoEvents
'''Inserting new records to tbl_dets
RDS.AddNew
RDS!Name = p
RDS!TID= XDATA!TID
RDS.Update
XDATA.MoveNext
Loop
XDATA.Close
Next
End Sub
So what I am missing? I thing that the error is in the Array but didn't know how to fix it.
Your code is mostly valid, but you are making some mistakes.
GetRows returns a multi-dimensional array with rownumbers and fields. As such, you can't fit it into a string. You need to use an array of type variant.
Private Sub Refreash()
Dim DataArr() As Variant
Dim p As Variant
Dim sql As String
Dim XDATA As New ADODB.Recordset
Dim RDS As DAO.Recordset
Set RDS = db.OpenRecordset("tbl_dets")
sql = "SELECT DISTINCT NAME FROM Types_tbl WHERE NAME LIKE 'Rob%'"
XDATA.Open sql, cnn, adOpenStatic
'''
'' HERE I WANT TO FILL DataArr FROM XDATA
'''
'Make sure XData fetches all records
XData.MoveLast
XData.MoveFirst
DataArr = XDATA.GetRows
XDATA.Close
For Each p In PATTs
sql = "SELECT DISTINCT TID FROM Types_tbl WHERE NAME ='" & p & "'"
XDATA .Open sql, cnn, adOpenStatic
Do Until XDATA.EOF
DoEvents
'''Inserting new records to tbl_dets
RDS.AddNew
RDS!Name = p
RDS!TID= XDATA!TID
RDS.Update
XDATA.MoveNext
Loop
XDATA.Close
Next
End Sub
Note that there are some things I still don't understand about this sub, possibly because it is not finished, such as it not using DataArr anywhere after setting it and the use of both ADO and DAO (I'd prefer to only do DAO in this case).
I am using an MS Access append query to append inventory transactions to my ERP database (MYSQL).
Please advise how I would go about to modify my query to automatically insert the next sequential transaction ID (primary key) into the Inventory_transaction table, with ability to append multiple records at once.
My existing query works fine, but only when I append just one record.
I usually need to append multiple records simultaneously. Each record needs to have a unique sequential transaction ID (primary key). There would be multiple users using this app simultaneously, so I need minimal chance of duplicate a key violation, to prevent roll backs. I tried appending without using a primary key to see if my database would automatically assign a transaction ID, but unfortunately this this ERP field is not an auto-number and I cant modify the table structure...
Below are 2 queries.
This one currently works for generating a transaction ID for just one record.
SELECT Max([SYSADM_INVENTORY_TRANS].[TRANSACTION_ID])+1 AS new_inventory_transaction_ID
FROM SYSADM_INVENTORY_TRANS;
The 2nd query is the append query that contains the first query and I would much appreciate it if someone can modify the query so the user has ability to append multiple records at once with a unique transaction ID.
INSERT INTO SYSADM_INVENTORY_TRANS ( TRANSACTION_ID, WORKORDER_TYPE,
WORKORDER_BASE_ID, WORKORDER_LOT_ID, WORKORDER_SPLIT_ID, WORKORDER_SUB_ID,
OPERATION_SEQ_NO, REQ_PIECE_NO, PART_ID, TYPE, CLASS, QTY, COSTED_QTY,
TRANSACTION_DATE, WAREHOUSE_ID, LOCATION_ID, USER_ID, POSTING_CANDIDATE,
ACT_MATERIAL_COST, ACT_LABOR_COST, ACT_BURDEN_COST, ACT_SERVICE_COST,
CREATE_DATE, ADD_BURDEN, COUNT_SEQUENCE, DESCRIPTION )
SELECT T.new_inventory_transaction_ID, S.WORKORDER_TYPE, D.WORKORDER_BASE_ID,
D.WORKORDER_LOT_ID, D.WORKORDER_SPLIT_ID, D.WORKORDER_SUB_ID, D.OPERATION_SEQ_NO,
D.PIECE_NO, D.auto_issue_part_ID, S.TYPE, S.CLASS, D.[total_auto_issue Qty],
0 AS Expr6, Date() AS Expr1, D.BACKFLUSH_WHS_ID, D.BACKFLUSH_LOC_ID,
"SYSADM" AS Expr3, S.POSTING_CANDIDATE, S.ACT_MATERIAL_COST, S.ACT_LABOR_COST,
S.ACT_BURDEN_COST, S.ACT_SERVICE_COST, Date() AS Expr2, S.ADD_BURDEN,
S.COUNT_SEQUENCE, "ENTERED WITH ACCESS APP" AS Expr5
FROM tbl_static_autoissue_data AS S,
tbl_dynamic_autoissue_data AS D,
qry_transaction_ID_generator AS T;
Here are some notes that may help you towards your goal, however life would be a lot easier and a lot safer with autonumbers. This is VBA as you mention MS Access.
Function NextTranNumber(ByRef FirstTran As Long, _
ByRef LastTran As Long, Optional BlockSize = 1)
Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim strSQL As String
Dim lngResult As Long
Dim strCon As String
lngResult = 0 'assume fail
strCon = TestCon ''Connection to back-end
cn.Open strCon
rs.CursorType = adOpenKeyset
rs.LockType = adLockPessimistic
rs.CursorLocation = adUseServer
''Where BEInfo is a single line table that holds a transaction seed
strSQL = "SELECT ASeqNumber FROM BEInfo"
rs.Open strSQL, cn, , , adCmdText
'Note this is ADO, so no rs.Edit
FirstTran = rs!ASeqNumber + 1
rs!ASeqNumber = rs!ASeqNumber + BlockSize
rs.Update
LastTran = rs!ASeqNumber
rs.Close
Set rs = Nothing
End Function
Sub TransactionProcessing()
Dim FirstTran As Long
Dim LastTran As Long
Dim db As Database
Dim sSQL As String
Dim Block As Long
Dim rs As DAO.Recordset
Set db = CurrentDb
'Existing temporary table
sSQL = "DELETE FROM FETempTrans"
db.Execute sSQL, dbFailOnError
'The records to be added to the main table
sSQL = "INSERT INTO FETempTrans ( ID, AText ) SELECT 0 AS ID, AText FROM Table1"
db.Execute sSQL, dbFailOnError
Block = db.RecordsAffected
'Reserve a transaction block based on the temp table count
NextTranNumber FirstTran, LastTran, Block
Set rs = db.OpenRecordset("FETempTrans")
Do While Not rs.EOF
rs.Edit
rs!ID = FirstTran
rs.Update
FirstTran = FirstTran + 1
rs.MoveNext
Loop
If FirstTran - 1 = LastTran Then
'compare the temp set to the main table
'if it passes, update the main table
Else
'fail
End If
End Sub
I'm trying to filter records using "Like" with asterisks, it works when using Access 2010 returning many records. I'm stumped why it returns nothing when used with ADO. The code includes multiple tables and columns so to troubleshoot I made a simple query. Here's the code:
strsql = "SELECT tproducts.Prod_Name FROM tproducts " _
& " WHERE tproducts.Prod_Name Like " & Chr(34) & "SO*" & Chr(34)
Set cn = New ADODB.Connection
cn = connString
cn.Open
Set rs = New ADODB.Recordset
rs.Open strsql, cn, adOpenStatic, adLockOptimistic
' test here
iRecCount = rs.RecordCount
rs.MoveFirst
Recordcount returns -1.
When "Like" is replaced by "equals" it returns correct record so I'm sure it's able to connect to the database, for example:
strsql = "SELECT tproducts.Prod_Name FROM tproducts " _
& " WHERE tproducts.Prod_Name = " & Chr(34) & "SONY Vaio SVD13213CXB" & Chr(34)
Is there a special way to use the Like operator in ADO?
What other ways can I filter to give results same as using "Like"? For example, to find all "SVD" products?
In MS Access, the wildcard is nearly always *, outside of MS Access it is nearly always %, so
str = "SELECT tproducts.Prod_Name FROM tproducts) " _
& " WHERE tproducts.Prod_Name Like ""SO%"""
However, I strongly recommend that you move to parameters to avoid a number of serious problems.
DAO is by far the better choice for ACE / Jet ( rough example Loop table rows in Access, with or without use of Private Const )
You cannot count on RecordCount. It often returns -1 even if rows were returned. It will only return actual count if you are using a client side cursor.
Instead, use rs.EOF to check for end of recordset. Try something like the following:
Set cn = New ADODB.Connection
cn = connString
cn.Open
Set rs = New ADODB.Recordset
rs.Open strsql, cn, adOpenStatic, adLockOptimistic
' very innefficient way to find the record count, but gives you the idea. If you just care about record count use "COUNT(*)" in your query
do while not rs.eof
iRecCount = iRecCount + 1
rs.MoveNext
loop
dim strSQL as string
dim RC as variant
dim rs as adodb.recordset
set rs = new adodb.recordset
strSQL = "Select * from sometable"
rs.open strSQL,currentproject.connection,
adopenDynamic, adlockOptimistic
RC = rs.recordcount
rs.close
set rs = nothing
is a problem but..
dim strSQL as string
dim RC as variant
dim rs as adodb.recordset
set rs = new adodb.recordset
strSQL = "Select * from sometable"
rs.Open strSQL, CurrentProject.Connection,
adOpenKeyset, adLockReadOnly
RC = rs.recordcount
rs.close
set rs = nothing
will return the correct record count.