Write data to MS Access using VB6 - vb6

This is my first VB6 application. My problem is there is no helpful example of writing data (including current date & time) from a form to an Access database. Here's my code based on all my research from different websites.
If you can't understand my code or if it is wrong, please show me a working example.
Private Sub Command1_Click()
Dim conConnection As New ADODB.Connection
Dim cmdCommand As New ADODB.Command
Dim rstRecordSet As New ADODB.Recordset
Dim logInId As Integer
Dim guardId As String
Dim studentId As String
Dim laptopName As String
Dim laptopBrand As String
Dim logInDate As Date
Dim logInTime As Date
guardId = Text2.Text
studentId = Text3.Text
laptopName = Text4.Text
laptopBrand = Text5.Text
logInDate = DateVal(Now)
logInTime = TimeVal(Now)
conConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
App.Path & "\" & "Database.accdb;Mode=Read|Write"
conConnection.CursorLocation = adUseClient
conConnection.Open
rstRecordSet.Open "laptopLoggedInLoggedOutInfo", conConnection
logInId = rstRecordSet.RecordCount
With cmdCommand
.ActiveConnection = conConnection
.CommandType = adCmdText
'f means field
.CommandText = "INSERT INTO laptopLoggedInLoggedOutInfo(f1,f2,f3,f4,f5,f6,f7) VALUES (?,?,?,?,?,?,?) "
.Prepared = True
.Parameters.Append .CreateParameter("f1", adInteger, adParamInput, , logInId + 1)
.Parameters.Append .CreateParameter("f2", adChar, adParamInput, 20, guardId)
.Parameters.Append .CreateParameter("f3", adChar, adParamInput, 20, studentId)
.Parameters.Append .CreateParameter("f4", adChar, adParamInput, 20, laptopName)
.Parameters.Append .CreateParameter("f5", adChar, adParamInput, 20, laptopBrand)
.Parameters.Append .CreateParameter("f6", adDate, adParamInput, , logInDate)
.Parameters.Append .CreateParameter("f7", adDate, adParamInput, , logInTime)
Set rstRecordSet = cmdCommand.Execute
End With
conConnection.Close
Set conConnection = Nothing
Set cmdCommand = Nothing
Set rstRecordSet = Nothing
End Sub

I've made in-line comments on your code:
Private Sub Command1_Click()
Whilst this doesn't matter for this particular example, generally don't declare object variables "As New". It is better if you instantiate them manually. Essentially, "As New" declared variables are checked every time you try to use a property or method on them, and if the variable Is Nothing, it creates a new instance. This may not necessarily be what you intend.
Dim conConnection As New ADODB.Connection
Dim cmdCommand As New ADODB.Command
Dim rstRecordSet As New ADODB.Recordset
Dim logInId As Integer
Dim guardId As String
Dim studentId As String
Dim laptopName As String
Dim laptopBrand As String
Dim logInDate As Date
Dim logInTime As Date
guardId = Text2.Text
studentId = Text3.Text
laptopName = Text4.Text
laptopBrand = Text5.Text
logInDate = DateVal(Now)
logInTime = TimeVal(Now)
Make sure that the Data Source substring is points to your Access database.
conConnection.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
App.Path & "\" & "Database.accdb;Mode=Read|Write"
conConnection.CursorLocation = adUseClient
conConnection.Open
I see that you are using a recordset just to receive a count of records in logInId. I really wouldn't use this as an ID. If you delete records from the table, then your ID will become smaller. Generally, if you want a unique ID, you must ensure that the ID always increments.
rstRecordSet.Open "laptopLoggedInLoggedOutInfo", conConnection
logInId = rstRecordSet.RecordCount
My suggestion: use "SELECT MAX(f1) FROM laptopLoggedInLoggedOutInfo", and retrieve the first value, ensuring that if the value is null, it returns zero, e.g.
rstRecordSet.Open "SELECT MAX(logInId) FROM laptopLoggedInLoggedOutInfo", conConnection
logInId = IIf(IsNull(rstRecordSet.Fields(0)), 0, IsNull(rstRecordSet.Fields(0)))
With cmdCommand
.ActiveConnection = conConnection
.CommandType = adCmdText
'f means field
Are these really your fieldnames: f1, f2, f2, etc.? I would be surprised. Replace them with the correct field names.
.CommandText = "INSERT INTO laptopLoggedInLoggedOutInfo(f1,f2,f3,f4,f5,f6,f7) VALUES (?,?,?,?,?,?,?) "
Note that the actual parameter names, e.g. f1,f2,f3, etc. seem not to matter. It is the order in the INSERT statement that matters.
.Prepared = True
.Parameters.Append .CreateParameter("f1", adInteger, adParamInput, , logInId + 1)
.Parameters.Append .CreateParameter("f2", adChar, adParamInput, 20, guardId)
.Parameters.Append .CreateParameter("f3", adChar, adParamInput, 20, studentId)
.Parameters.Append .CreateParameter("f4", adChar, adParamInput, 20, laptopName)
.Parameters.Append .CreateParameter("f5", adChar, adParamInput, 20, laptopBrand)
.Parameters.Append .CreateParameter("f6", adDate, adParamInput, , logInDate)
.Parameters.Append .CreateParameter("f7", adDate, adParamInput, , logInTime)
Don't use a return value in use the following line. And INSERT statement returns no values:
Set rstRecordSet = cmdCommand.Execute
Do this instead:
cmdCommand.Execute
End With
conConnection.Close
You probably don't need to set these variables to Nothing - VB does it for you, anyway. However, if you do, it is generally good practice to do this in reverse order of creation.
Set conConnection = Nothing
Set cmdCommand = Nothing
Set rstRecordSet = Nothing
End Sub

There really isn't much advantage in using ACE formats, you only limit portability. MDBs are almost always a better idea.
You also have a ton of code there for something this minimal. And don't forget to escape the DB path, you can use apostrophes or quotes in the connection string.
Make your "f1" field type IDENTITY ("autonumber").
Private Sub Command1_Click()
Dim cn As ADODB.Connection
Dim cm As ADODB.Command
Set cn = New ADODB.Connection
cn.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" _
& App.Path & "\Database.accdb';Mode=Read|Write"
Set cm = New ADODB.Command
With cm
.CommandType = adCmdText
'Assume "f1" is type IDENTITY ("Autonumber").
.CommandText = _
"INSERT INTO laptopLoggedInLoggedOutInfo(f2,f3,f4,f5,f6,f7) " _
& "VALUES (?,?,?,?,?,?)"
Set .ActiveConnection = cn
'Seriously? Give those TextBoxes names!
.Execute , _
Array(Text2.Text, Text3.Text, Text4.Text, Text5.Text, Date, Time()), _
adExecuteNoRecords
End With
End Sub

Related

VBScript unaltered Date and Time for database migration

I'm doing a MSSQL to MySQL data migration. My date/time value is exactly how it needs to be in both databases. However, VBScript converts this (by default):
2016-01-06 10:26:30.363
To this (which errors on INSERT):
1/6/2016 10:26:30 AM
I'm aware I can construct the value again with Year(), Month(), etc. Anyone know how to get this date/time value unaltered from the database using VBScript?
UPDATE: Per the "show my code" comment, here's a section:
strSQL = "SELECT * FROM Users"
Set objRS = CreateObject("ADODB.RecordSet")
objRS.Open strSQL, objConn,3,3
Do While Not objRS.EOF
sUserId = objRS("UserId")
sCreatedDate = objRS("CreatedDate") '<-- At this point, it's "converted" already
wscript.echo sCreatedDate '<-- This displays 1/6/2016 10:26:30 AM format
insertSQL = "INSERT INTO northwind.usersetting (UserId,CreatedDate) "
insertSQL = insertSQL & "VALUES ('"&sUserId&"','"&sCreatedDate &"');"
objConn2.Execute = (insertSQL)
objRS.MoveNext
Loop
Just your standard vbscript. I think I can get away with this in MSSQL, but MySQL doesn't like it. In the meantime, I have done this to work around the issue:
Function FormatDate4Insert(date)
FormatDate4Insert = Year(date) & "-" & Month(date) & "-" & Day(date) & " " & Hour(date) & ":" & Minute(date) & ":" & Second(date)
End Function
I would love to do a straight non-conversion, but vbs seems to convert no matter what I do. I tried converting to string and a few other things with no joy...
P.S. I'm not sure what you mean by database import export mechanisms. However, I tried the MySQL migration tool as well as exporting and import mechanisms (to csv...with different delimiters and such... and even a json export, massaging the data with Notepad++ and Excel, etc) and can't get the data to jive with my selective import. I can migrate an entire database without issue for the most part, but simply want to do the data from an individual table. When I kill too much time, I usually just fall back to vbscript or whatever scripting makes sense.
I find both databases more forgiving and finicky in some areas. However, with MSSQL to MySQL, I have to convert empty values to "NULL" and True/False to their bit values (e.g. b'0') and other little tweaks that scripting makes easier (at least for me).
UPDATE 2: The error as requested:
Microsoft OLE DB Provider for ODBC Drivers: [MySQL][ODBC 8.0(w)
Driver][mysqld-8.0.16]Incorrect datetime value: '1/6/2016 10:26:30 AM'
for column 'CreatedDate' at row 1.
I can't reproduce the other error, but I was also getting an error that was something similar to this:
ERROR: You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '1/6/2016 10:26:30 AM'
That was in reference to the Insert statement.
Try a parameterized query:
' *** ADO ***
'---- CommandTypeEnum Values ----
Const adCmdText = &H0001
'---- DataTypeEnum Values ----
Const adInteger = 3
Const adDate = 7
'---- ParameterDirectionEnum Values ----
Const adParamInput = &H0001
Dim cmd
Dim sSQL
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cn ' Assumes cn is an actice ADOB.Connection object
cmd.CommandType = adCmdText
sSQL = "INSERT INTO northwind.usersetting (UserId, CreatedDate) VALUES (?, ?);"
cmd.CommandText = sSQL
Set prm = cmd.CreateParameter("UserId", adInteger, adParamInput, , UserId) ' Assuming UserId is a integer, adjust as needed
cmd.Parameters.Append prm
Set prm = cmd.CreateParameter("CreatedDate", adDate, adParamInput, , CreatedDate)
cmd.Parameters.Append prm
cmd.Execute , , adExecuteNoRecords
[Added]
Try the following snippet just to make sure that MySQL accepts a date value:
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cn ' Assumes cn is an actice ADOB.Connection object
cmd.CommandType = adCmdText
sSQL = "INSERT INTO northwind.usersetting (CreatedDate) VALUES (?);"
cmd.CommandText = sSQL
Set prm = cmd.CreateParameter("CreatedDate", adDate, adParamInput, , Now())
cmd.Parameters.Append prm
cmd.Execute , , adExecuteNoRecords
If this works, than you might want to try the following line in the first sample I posted:
Set prm = cmd.CreateParameter("CreatedDate", adDate, adParamInput, , CDate(CreatedDate))
Note the explicit date conversion with CDate().
The ADO constants at the top of the first code snippet are taken from a file called adovbs.inc, distributed by Microsoft. Unfortunately a quick search didn't bring up a download from MS. But here's a gist with its contents. Scroll down to '---- DataTypeEnum Values ----. There are a few other date related constants, e.g. Const adDBDate = 133. You might try out those and see if it yields the expected result.
[Added 2]
' *** ADO ***
'---- CommandTypeEnum Values ----
Const adCmdText = &H0001
'---- DataTypeEnum Values ----
Const adInteger = 3
Const adDate = 7
'---- ParameterDirectionEnum Values ----
Const adParamInput = &H0001
Dim strSQL
Dim cmd, rs
Set cmd = CreateObject("ADODB.Command")
Set cmd.ActiveConnection = cnMSSQL ' Assumes cnMSSQL is an actice ADOB.Connection object connected to the MS SQL server
cmd.CommandType = adCmdText
' Fill the recordset from a command object connecting to the source MS SQL
strSQL = "SELECT * FROM Users"
cmd.CommandText = strSQL
Set rs = cmd.Execute()
' Now use the Command object to fill the MySQL DB
Set cmd.ActiveConnection = cnMySQL ' ' Assumes cnMySQL is an actice ADOB.Connection object connected to the MySQL server
strSQL = "INSERT INTO northwind.usersetting (UserId, CreatedDate) VALUES (?, ?);"
cmd.CommandText = strSQL
Do While Not rs.EOF
' This assumes that the columns in source MS SQL also are named 'UserId' and 'CreateDate'.
' Adjust the rs.Fields("UserId").Value and rs.Fields("CreateDate").Value as needed
Set prm = cmd.CreateParameter("UserId", adInteger, adParamInput, , rs.Fields("UserId").Value) ' Assuming UserId is a integer, adjust as needed
cmd.Parameters.Append prm
Set prm = cmd.CreateParameter("CreatedDate", adDate, adParamInput, , rs.Fields("CreateDate").Value)
cmd.Parameters.Append prm
cmd.Execute , , adExecuteNoRecords
' Clear/reset the parameter collection
rs.MoveNext
Loop

VBA calling function via VBA and ADO

I have a problem with calling my functions on Oracle server via VBA.
When I try calling function without parameters. It´s ok.
But, when I Calling functions with parameter. I get error ([Microsoft][ODBC driver for Oracle]Invalid parameter type)
Have any idea?
This is vba code and plsql (I make elementary function for test)
Vba
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & ";driver={Microsoft ODBC for Oracle};" & _
"SERVER=xx.xxx;"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
Set param1 = cmd.CreateParameter("P1", adLongVarChar, adParamInput, 256)
cmd.Parameters.Append param1
cmd.Parameters(0).Value = "ahoj1"
cmd.Execute
End Sub
And function
CREATE OR REPLACE FUNCTION EL_TEST
(
P1 IN VARCHAR2
) RETURN VARCHAR2 AS
BEGIN
RETURN 'Ahoj';
END EL_TEST;
Thanky you.
Get function return value with OLEDB
I searched high and low for this but finally solved the problem myself.
My solution is in VBScript but I have represented it in the (untested) code below.
The trick is that the first parameter is the return value.
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim param0 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & ";driver={Microsoft ODBC for Oracle};" & _
"SERVER=xx.xxx;"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
Set param0 = cmd.CreateParameter("P0", adLongVarChar, adParamReturnValue, 256)
Set param1 = cmd.CreateParameter("P1", adLongVarChar, adParamInput, 256)
cmd.Parameters.Append param0
cmd.Parameters.Append param1
cmd.Execute
Dim result As String
result = param0.Value ' Use the variable you set. Same as cmd.Parameters(1).Value '
End Sub
I admit, I've never tried to execute a function like this through code, but I'm surprise this worked without the parameter because the way you have your function set up. I think the way you would want to get the value would be:
select el_test('ahoj1') from dual;
If you made this change from a function to a procedure, I think it will work the way you expect:
CREATE OR REPLACE procedure EL_TEST
( P1 IN VARCHAR2,
p2 out varchar2) is
BEGIN
p2 := 'Ahoj';
END EL_TEST;
And then your VBA would look like this:
Private Sub test()
Dim Oracon As ADODB.Connection
Dim cmd As New ADODB.Command
Dim param1 As New ADODB.Parameter
Dim objErr As ADODB.Error
Set Oracon = CreateObject("ADODB.Connection")
mujuser = "xxxx"
mujPWD = "xxxxxx"
strConn = "UID=" & mujuser & ";PWD=" & mujPWD & _
";driver={Microsoft ODBC for Oracle};SERVER=xxxx-xx"
Oracon.ConnectionString = strConn
Oracon.Open
cmd.ActiveConnection = Oracon
cmd.CommandText = "el_test"
cmd.CommandType = adCmdStoredProc
cmd.NamedParameters = True
cmd.Parameters.Append cmd.CreateParameter("P1", adVarChar, adParamInput, 256, "ahoj1")
cmd.Parameters.Append cmd.CreateParameter("P2", adVarChar, adParamOutput, 256)
cmd.Execute
Dim result As String
result = cmd.Parameters(1).Value
End Sub

PL/SQL stored procedure out cursor to VBA ADODB.RecordSet?

To preface this post, I want to say that I am fairly new to Excel 2007 vba macros. I am trying to call an Oracle PL/SQL stored procedure that has a cursor as an output parameter. The procedure spec looks like this:
PROCEDURE get_product
(
out_cur_data OUT SYS_REFCURSOR,
rptid IN NUMBER,
scenario IN VARCHAR2
);
And I have written my macro as:
Sub GetProduct()
Const StartRow As Integer = 4
Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
With conn
.ConnectionString = "<my connection string>"
.Open
End With
Dim cmd As ADODB.Command
Set cmd = New ADODB.Command
With cmd
.ActiveConnection = conn
.CommandType = adCmdText
.CommandText = "{call their_package.get_product({out_cur_data 100},?,?)}"
.NamedParameters = True
.Parameters.Append cmd.CreateParameter("rptid", adNumeric, adParamInput, 0, 98)
.Parameters.Append cmd.CreateParameter("scenario", adVarChar, adParamInput, 4, "decline001")
End With
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
With rs
.CursorType = adOpenStatic
.CursorLocation = adUseClient
.LockType = adLockOptimistic
End With
Set rs = cmd.Execute
Cells(StartRow + 1, 1).CopyFromRecordset rs
rs.Close
conn.Close
End Sub
This does not work obviously, I get a run-time error '-2147217900 (80040e14): One or more errors occurred during processing of command.' So, OK.
I am looking for some guidance/advice on how to bring back that cursor into an ADODB.RecordSet. I don't think I have set up the output cursor correctly for "out_cur_data", but my searches online for any help have come up dry so far. Can any give me a basic working example to help me understand what I am doing wrong?
BTW... I do not have control of the stored procedure at all, it is from an external package.
Any help is really appreciated.
Thanks,
Doran
I think it should be this one:
With cmd
.Properties("PLSQLRSet") = TRUE
.ActiveConnection = conn
.CommandType = adCmdText
.CommandText = "{call their_package.get_product(?,?)}"
.NamedParameters = True
.Parameters.Append cmd.CreateParameter("rptid", adNumeric, adParamInput, 0, 98)
.Parameters.Append cmd.CreateParameter("scenario", adVarChar, adParamInput, 4, "decline001")
End With
...
Set rs = cmd.Execute
cmd.Properties("PLSQLRSet") = FALSE
Note:
Although their_package.get_product() takes three parameters, only two need to be bound because Ref cursor parameters are automatically bound by the provider.
For more information check Oracle documentation: Oracle Provider for OLE DB Developer's Guide - "Using OraOLEDB with Visual Basic"

214721900 error during run time

What is wrong in this code:
Dim con As ADODB.Connection
Dim rec As ADODB.Recordset
Set con = New ADODB.Connection
Set rec = New ADODB.Recordset
Dim count As Integer
con.Open "Provider=MSDAORA.1;Password=****;User ID=system;Persist Security Info=False"
con.CursorLocation = adUseClient
rec.Open "select count(*) as c from login_hisab where username = " & Text1.Text & " and password = " & Text2.Text & "", con, adOpenDynamic, adLockOptimistic
count = rec.Fields("c")
If count = 0 Then
MsgBox "Invalid USERNAME or PASSWORD"
End If
You probably have to put your sql values inside single quotes:
where username = '" & Text1.Text & "' and password = '" & Text2.Text & "'"
Try using a parameterized query like this (air code). Means you don't have to worry about passwords containing ' or ", you don't have to worry about SQL Injection, etc.
dim cmd As ADODB.Command
Set cmd = New ADODB.Command
cmd.CommandType = adCmdText
cmd.CommandTimeout = 30
cmd.CommandText = "select count(*) as c from login_hisab where username = ? and password = ?"
cmd.Parameters.Append cmd.CreateParameter("userid", adVarChar, _
adParamInput, Len(Text1.Text), Text1.Text)
cmd.Parameters.Append cmd.CreateParameter("pwd", adVarChar, _
adParamInput, Len(Text2.Text), Text2.Text)
cmd.ActiveConnection = con
Set rec = cmd.Execute()
count = rec.Fields("c")
If count = 0 Then
MsgBox "Invalid USERNAME or PASSWORD"
End If

How to properly add new records to empty recordset manually?

How to add new records to a new & empty ADODB.Recordset manually?
Right now, here's what I'm doing that isn't working:
Dim rs as ADODB.Recordset
rs.Open
Dim Fields() as String
Fields(0) = "SomeFieldName"
Dim Values() as String
Value(0) = "SomeValue"
rs.AddNew Fields, Values
In-place:
rs.AddNew "SomeFieldName", "SomeValue"
Or in-place multiple fields
rs.AddNew Array("SomeFieldName", "AnotherFieldName"), Array("SomeValue", 1234)
Or using separate vars
Dim Fields As Variant
Dim Values As Variant
Fields = Array("SomeFieldName")
Values = Array("SomeValue")
rs.AddNew Fields, Values
Edit: This is how to synthesize a recordset for the AddNew sample above
Set rs = new Recordset
rs.Fields.Append "SomeFieldName", adVarChar, 1000, adFldIsNullable
rs.Fields.Append "AnotherFieldName", adInteger, , adFldIsNullable
rs.Open
I'm usually using a helper function CreateRecordset as seen this answer.
Update 2018-11-12
You can also use field indexes as ordinals instead of field names as strings for the fields array like this
rs.AddNew Array(0, 1), Array("SomeValue", 1234)
set rs = new ADODB.Recordset
rs.Open "Select SomeFieldName, AnotherFieldName FROM MyTable", myConnection, adOpenDynamic, adLockOptimistic
rs.AddNew
rs("SomeFieldName").Value = "SomeValue"
rs("AnotherFieldName").Value = 1
rs.Update
rs.AddNew
rs("SomeFieldName").Value = "AnotherValue"
rs("AnotherFieldName").Value = 2
rs.Update
rs.Close
With an open connection Conn:
sSql="INSERT into mytable (somefieldname, anotherfieldname) values ('Somevalue','Anothervalue')"
Conn.Execute sSql

Resources