Using VB 6 and Access 2003
I want to copy a table from one database to other database.
Database1
Table1
Table2
Database2
Table3
Above, I want to copy the Table3 to Database-1
Expected Output
Table1
Table2
Table3
How to write a code?
Need VB6 Code Help.
Using ADOX to copy the structure of the data would probably be the easiest way.
Dim sourceCat As New ADOX.Catalog
Dim targetCat As New ADOX.Catalog
Set sourceCat.ActiveConnection = connSource
targetCat.ActiveConnection = connTarget
Dim sourceTable As ADOX.Table
Set sourceTable = sourceCat.Tables("TableName")
Dim newTable As New ADOX.Table
Set newTable.ParentCatalog = targetCat
newTable.Name = sourceTable.Name
Dim sourceCol As ADOX.Column
Dim newCol As ADOX.Column
For Each sourceCol In sourceTable.Columns
Set newCol = New ADOX.Column
newCol.Name = sourceCol.Name
newCol.Type = sourceCol.Type
newCol.DefinedSize = sourceCol.DefinedSize
newCol.ParentCatalog = targetCat
newTable.Columns.Append newCol
Next sourceCol
targetCat.Tables.Append newTable
This is a fairly basic example, it ignores all indexes
and column properties (such as autoincrement).
A much more complete example can be found here.
Be aware that you cannot be sure you have extracted all of a table's schema even when using both ADO (which you need for CHECK constraints, WITH COMPRESSION, etc) and ACEDAO (which you need for complex data types, etc).
Here's an example of such a table:
Sub CantGetCheck()
On Error Resume Next
Kill Environ$("temp") & "\DropMe.mdb"
On Error GoTo 0
Dim cat
Set cat = CreateObject("ADOX.Catalog")
With cat
.Create _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & _
Environ$("temp") & "\DropMe.mdb"
With .ActiveConnection
Dim Sql As String
Sql = _
"CREATE TABLE Test " & _
"(" & _
" data_col INTEGER NOT NULL, " & _
" CONSTRAINT data_col__be_positive " & _
" CHECK (data_col >= 0), " & _
" CONSTRAINT data_col__values " & _
" CHECK ( " & _
" data_col = 0 OR data_col = 1 OR data_col = 2 " & _
" OR data_col = 3 OR data_col = 4 OR data_col = 5 " & _
" OR data_col = 6 OR data_col = 7 OR data_col = 8 " & _
" OR data_col = 9 OR data_col = 10 OR data_col = 11 " & _
" OR data_col = 12 OR data_col = 13 OR data_col = 14 " & _
" OR data_col = 15 OR data_col = 16 OR data_col = 17 " & _
" OR data_col = 18 OR data_col = 19 OR data_col = 20 " & _
" ) " & _
");"
.Execute Sql
Dim rs
' 5 = adSchemaCheckConstraints
Set rs = .OpenSchema(5)
MsgBox rs.GetString
End With
Set .ActiveConnection = Nothing
End With
End Sub
The output shows that while the definition for the constraint named data_col__be_positive can indeed be extracted, the data_col__values definition cannot (because it exceeds 255 characters).
So really the solution is to always retain the code you used to create and subsequently alter the table. For me, using SQL DDL scripts for the purpose make a lot of sense (I do not need the few features that are not creatable via DDL).
Related
I have 8 combo boxes in an Access database. Each combo box can either have a value or not have a value (2 options). In total, there can be 256 combinations (2^8). I am trying to create some code in VBA that loops through these combinations to determine which combination currently exists, with the ultimate goal of writing an SQL query within VBA based on that combination. So for example, let's say combo1 and combo2 both have selections, but not combo3 through combo8. If that is the combination I would like my SQL query to do a SELECT FROM query WHERE a column in db = combo1 and a column in db = combo2. Can anyone provide hints as to how I would structure my code?
Thanks!
Dim a as string, b as string
const myAND as string = "AND "
a = ""
a = "SELECT * FROM a table "
b = ""
if cbo1.value <> "" then
b = b & myAND & "AND field1 = '" & cbo1.value & "'"
end if
if cbo2.value <> "" then
b = b & myAND & "field2 = '" & cbo2.value & "'"
end if
etc for each cbo box
If b <> "" Then
' Lazy way
' a = a & "WHERE 1=1 " & b
' remove the first AND way
a = a & "WHERE 1=1 " & mid(b,len(myAND))
End if
' a now contains the SQL you need.
Dim where_condtion as String
Dim sqlquery as String
where_condtion = ""
IF combo1 <>"" then
where_condtion = where_condtion + "~fieldname~ = " & combo1
End IF
IF combo2 <>"" then
where_condtion = where_condtion + "AND ~fieldname~ = " & combo2
End IF
*
*
*
IF combo8 <>"" then
where_condtion = where_condtion + "AND ~fieldname~ =" & combo8
End IF
IF where_condtion <> "" then
sqlquery = "Select * from ~table name~ where" + where_condtion
ELSE
sqlquery = "Select * from ~table name~
End IF
sqlquery = Replace(sqlquery, "where AND ", "where ")
DoCmd.OpenQuery "sqlquery", acViewNormal, acEdit
OR
CurrentDb.OpenRecordset("sqlquery")
Am option would be a concatenated string
Code Example
Dim strSQL as String
'basic string
strSQL = "SELECT tbl.fieldA, tbl.fieldB FROM tbl "
Dim strSQLwhere as String
strSQLwhere = ""
'Combobox cmbbox1
If Not isNull(cmbbox1) And cmbbox1.ListIndex <> -1 then
strSQLwhere = strSQLwhere & "tbl.fieldToFilter1=" & cmbbox1
End if
'Combobox cmbbox2
If Not isNull(cmbbox2) And cmbbox2.ListIndex <> -1 then
iF NOT strSQLwhere = "" then
strSQLwhere = strSQLwhere & " AND "
end if
strSQLwhere = strSQLwhere & "tbl.fieldToFilter2=" & cmbbox2
End if
'And so on until cmbBox 8
'Combine all Strings
if not strSQLwhere = "" then
strSQL = strSQL & " WHERE (" & strSQLwhere & ")"
End if
'Add here further thing like ORDER BY, GROUP BY
'Show SQL sting if it is well fomratted, change string concatenation if not
debug.print strSQL
You could do the combobox if-then-(else) cases in a separate function if you are able to do that in VBA.
strSQL = " SELECT W.wrhID, " & _
" W.wrhName AS WName " & _
" FROM tblWarehouse AS W " & _
" WHERE W.wrhID IN ( " & Forms.frmStockControl.Form.txtwrhIDs & " )"
Set rst = CurrentDb.OpenRecordset(strSQL)
Do Until rst.EOF
Dim strlbl$, strlblV$
For i = 1 To rst.Fields.count
strlbl = "Me.lblWarehouse" & i
strlblV = "Me.lblWarehouse" & i
Me.Controls(strlbl).Caption = rst!WName
Me.Controls(strlblV).visible = True
Next
rst.MoveNext
Loop
I am getting error msg 2465 - Can not find the Field name
but field Name exists in my form.Pls help.
The correct syntax to addres a form control in VBA is either:
Forms![YourFormName]![YourControlName]
The brackets are only required if the name contains blanks.
or
Forms("YourFormName").Controls("YourControlName")
i changed
strlbl = "Me.lblWarehouse" & i
strlblV = "Me.lblWarehouse" & i
to :
strlbl = "lblWarehouse" & i
strlblV = "lblWarehouse" & i
and is working fine
I am trying to use a single SQL command to do two selects I want to select related data and insert it in another table from another database, but it isn't working, I am new to this, can someone help me? Thanks in advance.
Try
If CreateAccessDatabase("C:\Users\Utilizador.Utilizador-PC\Documents\Visual Studio 2013\Projects\WindowsApplication1\WindowsApplication1\Doc_Vendas_Cab.mdb") = True Then
MsgBox("Database Created")
Else
MsgBox("Database Creation Failed")
End If
Dim Sql As String = "Select strCodSeccao,strAbrevTpDoc,strCodExercicio,intNumero " & _
"From Mov_Venda_Cab where dtmdata between #d1 and #d2; Union" & _
"Select Mov_Venda_Lin.Strcodartigo" & _
"from Mov_Venda_Lin,Mov_Venda_Cab where Mov_Venda_Cab.intnumero=Mov_Venda_Lin.intnumero;"
Dim data1, data2 As DateTime
data1 = DateTime.Parse(txtData1.Text)
data2 = DateTime.Parse(txtData2.Text)
data2 = data2.AddMinutes(0)
data2 = data2.AddHours(0)
data2 = data2.AddSeconds(0)
data1 = data1.AddMinutes(0)
data1 = data1.AddHours(0)
data1 = data1.AddSeconds(0)
Dim x As Integer = 0
Dim temp1, temp2, temp3, temp4, temp5 As String
Using con = New SqlConnection("Data Source=" & txtserv.Text & ";" & "Initial Catalog=" & txtBD.Text & ";" & "User ID=" & txtuser.Text & ";" & "Password=" & txtPass.Text & "")
Using cmd = New SqlCommand(Sql, con)
con.Open()
cmd.Parameters.AddWithValue("#d1", data1)
cmd.Parameters.AddWithValue("#d2", data2)
Using reader = cmd.ExecuteReader()
While reader.Read()
Dim strCodSeccao = reader("strCodSeccao").ToString()
temp1 = reader.Item(x)
temp2 = reader.Item(x + 1)
temp3 = reader.Item(x + 2)
temp4 = reader.Item(x + 3)
temp5 = reader.Item(x + 4)
Dim Con2 As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Utilizador.Utilizador-PC\Documents\Visual Studio 2013\Projects\WindowsApplication1\WindowsApplication1\Doc_Vendas_Cab.mdb;Persist Security Info=True")
Con2.Open()
Dim Ole2 As String = "Insert into Mov_Venda_Cab values('" & temp1 & "','" & temp2 & "','" & temp3 & "','" & temp4 & "','" & temp5 & "');"
Dim OledbCom2 As New OleDb.OleDbCommand(Ole2, Con2)
Try
OledbCom2.ExecuteNonQuery()
Catch Ex As Exception
MsgBox(Ex)
End Try
Con2.Close()
End While
End Using
End Using
End Using
Catch Ex As Exception
MsgBox(Ex)
End Try
Your INSERT statement encloses all the values in single quotes. This will only work if the corresponding columns are all text columns (varchar, nvarchar etc.). Use command parameters instead:
Dim Ole2 As String = "Insert into Mov_Venda_Cab values(#p1, #p2, #p3, #p4, #p5);"
Dim OledbCom2 As New OleDb.OleDbCommand(Ole2, Con2)
OledbCom2.Parameters.AddWithValue("#p1", temp1)
OledbCom2.Parameters.AddWithValue("#p2", temp2)
OledbCom2.Parameters.AddWithValue("#p3", temp3)
OledbCom2.Parameters.AddWithValue("#p4", temp4)
OledbCom2.Parameters.AddWithValue("#p5", temp5)
This will work for any column type.
Also your SELECT statement lists only four columns, but you are accessing five columns in the reader.
SELECT strCodSeccao, strAbrevTpDoc, strCodExercicio, intNumero FROM ...
Other things in your code are strange as well. Your are defining two connections that are never used later.
You are adding zero hours, minutes and seconds to a date (this will not change the date). If you want the date part of the date without the time part, use the Date property instead, which returns the date component of the DateTime structure:
data1 = DateTime.Parse(txtData1.Text).Date
You are using a variable x for constant values.
You are opening and closing Con2 in the While-loop. Open it before the loop and close it after the loop. (You can do it with a Using-statement as for the other connection.)
I have very little experience with Access Databases however I have wrote a similar VBA macro in excel. I am trying to copy rows from one .mdb file into the exact same table on a different .mdb file. However I would like it to only import it if it does not already exsist. Could someone please advise me the best way to go about this and maybe some code I can use and modify? I have already looked around stack overflow and can't seem to find any examples that work.
There are 8 different tables and inside these a few hundred rows. with maybe 5-20 columns.
If the script could be made inside VBS this would be ideal, as it would allow me to run the updates without loading into access.
Thanks for any help or advice,
Simon
EDIT -
Zev's answer seems to do the job however I am getting this error, also the MDB inside site2 is the one I am copying from and putting it into site1
Error: Expected end of statement
Code: 800A0401
Line: 17
Char: 13
Code (saved as "update.vbs"):
Dim eng
Set eng = CreateObject("DAO.DBEngine.120")
Set dest = eng.OpenDatabase("C:\Users\simon\Documents\garden games redesign\import script\Site1\ActinicCatalog.mdb")
Sub CopyTable()
Dim rs
Set rs = dest.OpenRecordset("Person")
Dim sWhere
For Each fld In rs.Fields
sWhere = sWhere & " AND " & fld.Name & " <> t1." & fld.Name
Next
sWhere = Mid(sWhere, 6)
Dim sql: sql= _
"INSERT INTO Person " & _
"SELECT * " & _
"FROM Person AS t1 IN ""C:\Users\simon\Documents\garden games redesign\import script\Site2\ActinicCatalog.mdb"" " & _
"WHERE " & sWhere
dest.Execute(sql)
End Sub
Edit for more info:
\Site1\ActinicCatalog.mdb - is destination database
\Site2\ActinicCatalog.mdb - is original database
These databases have about 20 columns
Here is an example to get you started. It copies the content of [Table1] of the current database to [Table1] of a second database.
Option Compare Database
Option Explicit
Sub copyTables()
'Open source database
Dim dSource As Database
Set dSource = CurrentDb
'Open dest database
Dim dDest As Database
Set dDest = DAO.OpenDatabase("C:\Users\Admin\Desktop\DBdest.accdb")
'Open source recordset
Dim rSource As Recordset
Set rSource = dSource.OpenRecordset("Table1", dbOpenForwardOnly)
'Open dest recordset
Dim rDest As Recordset
Set rDest = dDest.OpenRecordset("Table1", dbOpenDynaset)
'Loop through source recordset
While Not rSource.EOF
'Look for record in dest recordset
rDest.FindFirst _
"Field1 = '" & rSource.Fields("Field1") & "' AND " & _
"Field2 = " & rSource.Fields("Field2")
'If not found, copy record - Field1 is text / Field2 is numeric
If rDest.NoMatch Then
rDest.AddNew
rDest.Fields("Field1") = rSource.Fields("Field1")
rDest.Fields("Field2") = rSource.Fields("Field2")
rDest.Update
End If
'Next source record
rSource.MoveNext
Wend
'Close dest recordset
rDest.Close
Set rDest = Nothing
'Close source recordset
rSource.Close
Set rSource = Nothing
'Close dest database
dDest.Close
Set dDest = Nothing
'Close source database
dSource.Close
Set dSource = Nothing
End Sub
I would suggest using an SQL statement if possible. From VBScript using DAO/ACE:
Dim eng
Set eng = CreateObject("DAO.DBEngine.120")
Set dest = eng.OpenDatabase("path\to\destination\database.accdb")
Using ADO:
Dim conn
Set conn = CreateObject("ADODB.Connection")
With conn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.ConnectionString = "Data Source=""path\to\destination\database.accdb"";"
.Open
End With
The SQL statement would be something like this:
INSERT INTO Table1
SELECT *
FROM Table1 AS t1 IN "path\to\source\database.accdb"
WHERE Table1.Field1 <> t1.Field1
and executed like this:
Dim sql = _
"INSERT INTO Table1 " & _
"SELECT * " & _
"FROM Table1 AS t1 IN "path\to\source\database.accdb" " & _
"WHERE Table1.Field1 <> t1.Field1"
'Using DAO or ADO
dest.Execute sql
Considering that each table has a variable number of columns, you might have to generate the WHERE expression dynamically:
Sub CopyTable(tablename)
Dim rs
Set rs = dest.OpenRecordset(tablename)
'if using ADO:
'Set rs = conn.Execute(tablename)
Dim sWhere
For Each fld In rs.Fields
sWhere = sWhere & " AND " & fld.Name & " <> t1." & fld.Name
Next
sWhere = Mid(sWhere, 6)
Dim sql
sql = _
"INSERT INTO " & tablename & " " & _
"SELECT * " & _
"FROM " & tablename & " AS t1 IN ""path\to\source\database.accdb"" " & _
"WHERE " & sWhere
dest.Execute(sql)
End Sub
Update
If you are only using one column to determine whether the record exists, the SQL statement should look like this:
INSERT INTO Table1
SELECT *
FROM Table1 AS t1 IN "path\to\source\database.accdb"
LEFT JOIN Table1 ON t1.FirstField = Table1.FirstField
WHERE Table1.FirstField IS NULL
and CopyTable like this:
Sub CopyTable(tablename)
Dim rs
Set rs = dest.OpenRecordset(tablename)
'if using ADO:
'Set rs = conn.Execute(tablename)
Dim field0Name
field0Name=rs.Fields(0).Name
Dim sql
sql = _
"INSERT INTO " & tablename & " " & _
"SELECT * " & _
"FROM " & tablename & " AS t1 IN ""path\to\source\database.accdb"" " & _
"LEFT JOIN " & tablename & " ON t1." & field0Name & "=" & tablename & "." & field0Name & " " & _
"WHERE " & tablename & "." & field0Name & " IS NULL"
dest.Execute(sql)
End Sub
I am trying to access certain lines from my SQL database from MSAccess and I keep getting an Invalid Argument Error on this line:
Set rs = CurrentDb.OpenRecordset("SELECT TimeID " & _
"FROM tblLunchTime " & _
"WHERE ProductionID = prodSelect AND EndTime is NULL AND StartTime < dateAdd('h', 3, NOW())", [dbSeeChanges])
Is something not right in this?
Private Sub cmdClockEnd_Click()
'Check if a group has been selected.
If frmChoice.value = 0 Then
MsgBox "Please select a production line."
End
End If
'Setup form for user input.
lblEnd.Visible = True
'Save end of lunch value.
lblEnd.Caption = Format(Now, "MMM/DD/YY hh:mm:ss AMPM")
'Declare database variables.
Dim dbName As DAO.Database
Dim strValuesQuery As String
Dim rs As DAO.Recordset
Dim prodSelect As String
Dim sSQL As String
Dim timeValue As String
Set dbName = CurrentDb
'Get values of Production Line.
If frmChoice.value = 1 Then
prodSelect = "L2"
ElseIf frmChoice.value = 2 Then
prodSelect = "L3"
End If
'Get the last TimeID with the following parameters.
sSQL = "SELECT TimeID " & _
"FROM tblLunchTime " & _
"WHERE ProductionID = prodSelect AND EndTime is NULL AND StartTime < #" & DateAdd("h", 3, Now()) & "#"
Set rs = dbName.OpenRecordset(sSQL, dbSeeChanges)
strValuesQuery = _
"UPDATE tblLunchTime " & _
"SET EndTime = '" & Now & "'" & _
"WHERE TimeID = " & rs![TimeID] & " "
'Turn warning messages off.
DoCmd.SetWarnings False
'Execute Query.
DoCmd.RunSQL strValuesQuery
'Turn warning messages back on.
DoCmd.SetWarnings True
End Sub
You need to put prodSelect outside the quotes:
"WHERE ProductionID = " & prodSelect & " AND ...
It is nearly always best to say:
sSQL="SELECT TimeID " & _
"FROM tblLunchTime " & _
"WHERE ProductionID = " & prodSelect & _
" AND EndTime is NULL AND StartTime < dateAdd('h', 3, NOW())"
''Debug.print sSQL
Set rs = CurrentDb.OpenRecordset(sSQL)
You can see the advantage in the use of Debug.Print.
AHA prodSelect is text! You need quotes!
sSQL="SELECT TimeID " & _
"FROM tblLunchTime " & _
"WHERE ProductionID = '" & prodSelect & _
"' AND EndTime is NULL AND StartTime < dateAdd('h', 3, NOW())"
There appears to be confusion about tblLunchTime ... whether it is a native Jet/ACE table or a link to a table in another database. Please show us the output from this command:
Debug.Print CurrentDb.TableDefs("tblLunchTime").Connect
You can paste that line into the Immediate Window and press the enter key to display the response. (You can open the Immediate Window with CTRL+g keystroke combination.)
Just in case the response starts with "ODBC", suggest you try this line in your code:
Set rs = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
Update: Now that you're past that hurdle, suggest you change your approach with the UPDATE statement. Don't turn off warnings; try something like this instead:
'Execute Query. '
CurrentDb.Execute strValuesQuery, dbFailOnError
And add an error handler to deal with any errors captured by dbFailOnError.
I think I would do the date criterion concatenation client-side, too, since it's one more thing that could go wrong:
"...StartTime < #" & DateAdd("h", 3, Now()) & "#"
I don't know that SQL Server doesn't have DateAdd() and Now() function nor that they don't behave exactly the same as in Access, but I wouldn't take the chance -- I'd do this calculation on the client instead of handing it off to the server.