My first ever Access VBA Code - How'm I doin?

W

wdsnews

Here is my first ever VBA code. I come from an ObjectPal background where I
was very comfortable. But I'm new to Access, VBA, and SQL. This code is
attached to the 'Click On' event of a button to normalize data and turn a
flat file into a relational database. I would enjoy hearing two things.
Will this code work? What are your suggestions? I added _ line breaks
hoping it translates properly for email. Note that 'PhoneComm' is the name
of a text field in a child table that is also named 'PhoneComm'. The
existing flat file is called 'People'.

Private Sub btnMovePhones_Click()

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

'INSERT INTO PhoneComm ( [People ID], [Contact ID], PhoneComm )
strSQLHomePhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLCellPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLParentPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone & " SELECT People.ID AS _
[People ID], 1 AS [Contact ID], People.[Home Phone] AS PhoneComm"
strSQLCellPhone = strSQLCellPhone & " SELECT People.ID AS _
[People ID], 3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"
strSQLParentPhone = strSQLParentPhone & " SELECT People.ID AS _
[People ID], 9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLCellPhone = strSQLCellPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLParentPhone = strSQLParentPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone & " WHERE (((People.[Home Phone]) _
IS NOT NULL"
strSQLCellPhone = strSQLCellPhone & " WHERE (((People.[Cell Phone]) _
IS NOT NULL"
strSQLParentPhone = strSQLParentPhone & " WHERE (((People.[Parents Phone]) _
IS NOT NULL"

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False
DoCmd.RunSQL strSQLHomePhone
DoCmd.RunSQL strSQLCellPhone
DoCmd.RunSQL strSQLParentPhone
DoCmd.SetWarnings True

End Sub

Thanks for your comments.
 
G

Guest

Congratulations on writing your first procedure!
I would enjoy hearing two things. Will this code work? What are your suggestions? I added _ line breaks hoping it translates properly for email.

Not in it's present form. It appears as if you split the lines of code and
added the line breaks after pasting the code into a new message. The reason I
say this is that a direct copy and paste of your code into a new form module
resulted in several lines shown in red font (errors). After fixing this
problem, I added three Debug.Print statements and ran the code:

Debug.Print strSQLHomePhone
Debug.Print strSQLCellPhone
Debug.Print strSQLParentPhone

The resulting SQL statements are not valid. In each case, there is an extra
two opening parentheses that are not balanced with matching closing
parentheses:

WHERE (((People

The solution is to simply eliminate two of these in each of the three
statements, so that you end up with, for example:

& " WHERE (People.[Home Phone]) IS NOT NULL"

=======================================

The next problem became evident after I ran your code, after inserting some
test data into the People table. I had added the following data into this
table:

ID Home Phone Cell Phone Parents Phone
1 11111 22222 33333
2 44444
3 55555
4 66666



This produced the following result in the PhoneComm table:

People ID Contact ID PhoneComm
1 9 33333
1 9 33333
1 3 22222
1 1 11111
2 1 44444
3 3 55555
4 9 66666

Notice that there are (7) new records, where there should only be (6) new
records. One of the records is duplicated. The reason for this is the Left
Joins that you used:

"Include ALL records from 'People' and only those records from 'PhoneComm'
where the joined fields are equal."

The trouble is that the third SQL Insert statement, for this sample of data
in the People table, results in three records being inserted instead of just
two:

1 9 33333
1 9 33333
4 9 66666



The reason is that you already had two records inserted into the PhoneComm
table at this point, with PeopleID = 1. You do not need to include the
PhoneComm table in the join. Change the three lines of code under this
comment, as indicated below:

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

=======================================

Declaration of variables

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

Only the last variable indicated, strSQLParentPhone is initially typecast as
a string variable. The other two variables are initially created as empty
variants. You should always typecast your variables. Use one of the following
forms:

All on one line (this will be word wrapped in this reply):

Dim strSQLHomePhone As String, strSQLCellPhone As String, strSQLParentPhone
As String

or, as three separate lines of code:

Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String



=======================================

Insert error handling code.

Pretty much all procedures should include code to handle errors. A basic
skeleton is as follows.

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError
:
Your code goes here
:
ExitProc:
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub


Note:
If you do not have the two very important words "Option Explicit" shown as
the second line of code at the top of all modules, then add it. This link
explains why this statement is so important, and how to configure your Visual
Basic Editor (VBE) to include it in all new modules:

Always Use Option Explicit
http://www.access.qbuilt.com/html/gem_tips.html#VBEOptions


=======================================

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False

Setting warnings to false can be dangerous. The reason is that if one of the
lines of code that follows this statement fails, before the line of code that
sets warnings back on is executed, then warnings will be left off for the
user. If you must set warnings to false, then make sure to turn them back on
in the ExitProc section of your procedure. For example:

ExitProc:
DoCmd.SetWarnings True
Exit Sub
ProcError:

A better alternative for running action queries is the .execute method of
the current database. For example:

CurrentDB.Execute strSQLHomePhone, dbFailOnError

Notes:
1.) The use of the optional dbFailOnError parameter requires that you set a
reference to the Microsoft DAO Object Library.

2.) Since you have more than one insert statement, it is more economical to
set a variable equal to CurrentDB, instead of calling this three times. For
example:

Dim db As DAO.Database
Set db = CurrentDB()
and then:

db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

This allows you to get rid of the DoCmd.SetWarning statements. You should
set this variable to nothing in the ExitProc section of your procedure. For
example:

ExitProc:
Set db = Nothing
Exit Sub
ProcError:

For more information on this issue, you can download a Word document that I
have made available in zipped form:

http://home.comcast.net/~tutorme2/samples/ActionQueryExamplesWithSetWarnings.doc

=======================================

Here are two forms of a revised procedure for you:

Form 1: Similar to the form you layed out:

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String

Set db = CurrentDb()

strSQLHomePhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLCellPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLParentPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone _
& " SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm"

strSQLCellPhone = strSQLCellPhone _
& " SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"

strSQLParentPhone = strSQLParentPhone _
& " SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone _
& " WHERE (People.[Home Phone]) IS NOT NULL"
strSQLCellPhone = strSQLCellPhone _
& " WHERE (People.[Cell Phone]) IS NOT NULL"
strSQLParentPhone = strSQLParentPhone _
& " WHERE (People.[Parents Phone]) IS NOT NULL"

'Execute SQL Inserts
db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub

================================

Form 2: Create and execute each SQL statement in order

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDb()

'Insert Home Phone numbers first
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Home Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Cell Phone numbers next
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Cell Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Parents Phone numbers last
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Parents Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub



Hope you found this helpful.


Tom Wickerath
Microsoft Access MVP
https://mvp.support.microsoft.com/profile/Tom
http://www.access.qbuilt.com/html/expert_contributors.html
__________________________________________

wdsnews said:
Here is my first ever VBA code. I come from an ObjectPal background where I
was very comfortable. But I'm new to Access, VBA, and SQL. This code is
attached to the 'Click On' event of a button to normalize data and turn a
flat file into a relational database. I would enjoy hearing two things.
Will this code work? What are your suggestions? I added _ line breaks
hoping it translates properly for email. Note that 'PhoneComm' is the name
of a text field in a child table that is also named 'PhoneComm'. The
existing flat file is called 'People'.

Private Sub btnMovePhones_Click()

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

'INSERT INTO PhoneComm ( [People ID], [Contact ID], PhoneComm )
strSQLHomePhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLCellPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLParentPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone & " SELECT People.ID AS _
[People ID], 1 AS [Contact ID], People.[Home Phone] AS PhoneComm"
strSQLCellPhone = strSQLCellPhone & " SELECT People.ID AS _
[People ID], 3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"
strSQLParentPhone = strSQLParentPhone & " SELECT People.ID AS _
[People ID], 9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLCellPhone = strSQLCellPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLParentPhone = strSQLParentPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone & " WHERE (((People.[Home Phone]) _
IS NOT NULL"
strSQLCellPhone = strSQLCellPhone & " WHERE (((People.[Cell Phone]) _
IS NOT NULL"
strSQLParentPhone = strSQLParentPhone & " WHERE (((People.[Parents Phone]) _
IS NOT NULL"

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False
DoCmd.RunSQL strSQLHomePhone
DoCmd.RunSQL strSQLCellPhone
DoCmd.RunSQL strSQLParentPhone
DoCmd.SetWarnings True

End Sub

Thanks for your comments.
 
I

IRS Intern

Warning; Tom Wickerath is a cry baby database pussy and you shouldn't
listen to him for anything

go and talk to someone that knows SQL Server, kids




Congratulations on writing your first procedure!
I would enjoy hearing two things. Will this code work? What are your suggestions? I added _ line breaks hoping it translates properly for email.

Not in it's present form. It appears as if you split the lines of code and
added the line breaks after pasting the code into a new message. The reason I
say this is that a direct copy and paste of your code into a new form module
resulted in several lines shown in red font (errors). After fixing this
problem, I added three Debug.Print statements and ran the code:

Debug.Print strSQLHomePhone
Debug.Print strSQLCellPhone
Debug.Print strSQLParentPhone

The resulting SQL statements are not valid. In each case, there is an extra
two opening parentheses that are not balanced with matching closing
parentheses:

WHERE (((People

The solution is to simply eliminate two of these in each of the three
statements, so that you end up with, for example:

& " WHERE (People.[Home Phone]) IS NOT NULL"

=======================================

The next problem became evident after I ran your code, after inserting some
test data into the People table. I had added the following data into this
table:

ID Home Phone Cell Phone Parents Phone
1 11111 22222 33333
2 44444
3 55555
4 66666

This produced the following result in the PhoneComm table:

People ID Contact ID PhoneComm
1 9 33333
1 9 33333
1 3 22222
1 1 11111
2 1 44444
3 3 55555
4 9 66666

Notice that there are (7) new records, where there should only be (6) new
records. One of the records is duplicated. The reason for this is the Left
Joins that you used:

"Include ALL records from 'People' and only those records from 'PhoneComm'
where the joined fields are equal."

The trouble is that the third SQL Insert statement, for this sample of data
in the People table, results in three records being inserted instead of just
two:

1 9 33333
1 9 33333
4 9 66666

The reason is that you already had two records inserted into the PhoneComm
table at this point, with PeopleID = 1. You do not need to include the
PhoneComm table in the join. Change the three lines of code under this
comment, as indicated below:

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

=======================================

Declaration of variables

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

Only the last variable indicated, strSQLParentPhone is initially typecastas
a string variable. The other two variables are initially created as empty
variants. You should always typecast your variables. Use one of the following
forms:

All on one line (this will be word wrapped in this reply):

Dim strSQLHomePhone As String, strSQLCellPhone As String, strSQLParentPhone
As String

or, as three separate lines of code:

Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String

=======================================

Insert error handling code.

Pretty much all procedures should include code to handle errors. A basic
skeleton is as follows.

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError
:
Your code goes here
:
ExitProc:
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub

Note:
If you do not have the two very important words "Option Explicit" shown as
the second line of code at the top of all modules, then add it. This link
explains why this statement is so important, and how to configure your Visual
Basic Editor (VBE) to include it in all new modules:

Always Use Option Explicit
http://www.access.qbuilt.com/html/gem_tips.html#VBEOptions

=======================================

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False

Setting warnings to false can be dangerous. The reason is that if one of the
lines of code that follows this statement fails, before the line of code that
sets warnings back on is executed, then warnings will be left off for the
user. If you must set warnings to false, then make sure to turn them backon
in the ExitProc section of your procedure. For example:

ExitProc:
DoCmd.SetWarnings True
Exit Sub
ProcError:

A better alternative for running action queries is the .execute method of
the current database. For example:

CurrentDB.Execute strSQLHomePhone, dbFailOnError

Notes:
1.) The use of the optional dbFailOnError parameter requires that you seta
reference to the Microsoft DAO Object Library.

2.) Since you have more than one insert statement, it is more economical to
set a variable equal to CurrentDB, instead of calling this three times. For
example:

Dim db As DAO.Database
Set db = CurrentDB()
and then:

db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

This allows you to get rid of the DoCmd.SetWarning statements. You should
set this variable to nothing in the ExitProc section of your procedure. For
example:

ExitProc:
Set db = Nothing
Exit Sub
ProcError:

For more information on this issue, you can download a Word document thatI
have made available in zipped form:

http://home.comcast.net/~tutorme2/samples/ActionQueryExamplesWithSetW...

=======================================

Here are two forms of a revised procedure for you:

Form 1: Similar to the form you layed out:

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String

Set db = CurrentDb()

strSQLHomePhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLCellPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLParentPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone _
& " SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm"

strSQLCellPhone = strSQLCellPhone _
& " SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"

strSQLParentPhone = strSQLParentPhone _
& " SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone _
& " WHERE (People.[Home Phone]) IS NOT NULL"
strSQLCellPhone = strSQLCellPhone _
& " WHERE (People.[Cell Phone]) IS NOT NULL"
strSQLParentPhone = strSQLParentPhone _
& " WHERE (People.[Parents Phone]) IS NOT NULL"

'Execute SQL Inserts
db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub

================================

Form 2: Create and execute each SQL statement in order

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDb()

'Insert Home Phone numbers first
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Home Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Cell Phone numbers next
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Cell Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Parents Phone numbers last
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Parents Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
...

read more »
 
W

wdsnews

Tom,

I am so very impressed with the depth of your reply. You have taught me
much, including the value and ease of building a temporary database for
testing. Here are my comments in the same order as yours. The most
significant question in my mind is whether I can stick with ADO, or whether
there is a need to use the DAO interface. My intention is to design for
long-term maintenance and eventually convert all of this to ASP, with SQL on
the back-end and web interfaces on the front-end. (of course ASP is just as
new to me.)

My parenthesis error embarrasses me. Even as a beginner I should have
caught that.

Your catch of the extra record insertion problem and the realization that we
don't need to join the child table was very helpful. It helps me to better
understand SQL and how to think about it.

On the Dim statement, one of my books explained that beginning with 2003,
VBA now correctly types multiple variables even if the 'As' statement is
only attached to the last one. However, even if they're correct, I like
your suggestion to give each variable its own type statement. This will
allow backwards compatibility.

I added a ProcError section. Very wise.

Concerning the "DoCmd.SetWarnings False" issue, this is the only way I know
how to do it with ADO. The method that you suggest seems to require ADO. I
understand that ADO is more robust, however, looking toward the future, I
feel strongly that I need ADO. I'd enjoy hearing opinions about using ADO
vs. DAO, or both?

THANK YOU VERY VERY MUCH. Between, Access, SQL, and VBA, my learning curve
is steep, but this group has been very helpful to help me to travel a long
ways in a short time. Thank you for your time, your experience, and your
advice.



Tom Wickerath said:
Congratulations on writing your first procedure!
I would enjoy hearing two things. Will this code work? What are your
suggestions? I added _ line breaks hoping it translates properly for
email.

Not in it's present form. It appears as if you split the lines of code and
added the line breaks after pasting the code into a new message. The
reason I
say this is that a direct copy and paste of your code into a new form
module
resulted in several lines shown in red font (errors). After fixing this
problem, I added three Debug.Print statements and ran the code:

Debug.Print strSQLHomePhone
Debug.Print strSQLCellPhone
Debug.Print strSQLParentPhone

The resulting SQL statements are not valid. In each case, there is an
extra
two opening parentheses that are not balanced with matching closing
parentheses:

WHERE (((People

The solution is to simply eliminate two of these in each of the three
statements, so that you end up with, for example:

& " WHERE (People.[Home Phone]) IS NOT NULL"

=======================================

The next problem became evident after I ran your code, after inserting
some
test data into the People table. I had added the following data into this
table:

ID Home Phone Cell Phone Parents Phone
1 11111 22222 33333
2 44444
3 55555
4 66666



This produced the following result in the PhoneComm table:

People ID Contact ID PhoneComm
1 9 33333
1 9 33333
1 3 22222
1 1 11111
2 1 44444
3 3 55555
4 9 66666

Notice that there are (7) new records, where there should only be (6) new
records. One of the records is duplicated. The reason for this is the Left
Joins that you used:

"Include ALL records from 'People' and only those records from 'PhoneComm'
where the joined fields are equal."

The trouble is that the third SQL Insert statement, for this sample of
data
in the People table, results in three records being inserted instead of
just
two:

1 9 33333
1 9 33333
4 9 66666



The reason is that you already had two records inserted into the PhoneComm
table at this point, with PeopleID = 1. You do not need to include the
PhoneComm table in the join. Change the three lines of code under this
comment, as indicated below:

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

=======================================

Declaration of variables

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

Only the last variable indicated, strSQLParentPhone is initially typecast
as
a string variable. The other two variables are initially created as empty
variants. You should always typecast your variables. Use one of the
following
forms:

All on one line (this will be word wrapped in this reply):

Dim strSQLHomePhone As String, strSQLCellPhone As String,
strSQLParentPhone
As String

or, as three separate lines of code:

Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String



=======================================

Insert error handling code.

Pretty much all procedures should include code to handle errors. A basic
skeleton is as follows.

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError
:
Your code goes here
:
ExitProc:
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub


Note:
If you do not have the two very important words "Option Explicit" shown as
the second line of code at the top of all modules, then add it. This link
explains why this statement is so important, and how to configure your
Visual
Basic Editor (VBE) to include it in all new modules:

Always Use Option Explicit
http://www.access.qbuilt.com/html/gem_tips.html#VBEOptions


=======================================

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False

Setting warnings to false can be dangerous. The reason is that if one of
the
lines of code that follows this statement fails, before the line of code
that
sets warnings back on is executed, then warnings will be left off for the
user. If you must set warnings to false, then make sure to turn them back
on
in the ExitProc section of your procedure. For example:

ExitProc:
DoCmd.SetWarnings True
Exit Sub
ProcError:

A better alternative for running action queries is the .execute method of
the current database. For example:

CurrentDB.Execute strSQLHomePhone, dbFailOnError

Notes:
1.) The use of the optional dbFailOnError parameter requires that you set
a
reference to the Microsoft DAO Object Library.

2.) Since you have more than one insert statement, it is more economical
to
set a variable equal to CurrentDB, instead of calling this three times.
For
example:

Dim db As DAO.Database
Set db = CurrentDB()
and then:

db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

This allows you to get rid of the DoCmd.SetWarning statements. You should
set this variable to nothing in the ExitProc section of your procedure.
For
example:

ExitProc:
Set db = Nothing
Exit Sub
ProcError:

For more information on this issue, you can download a Word document that
I
have made available in zipped form:

http://home.comcast.net/~tutorme2/samples/ActionQueryExamplesWithSetWarnings.doc

=======================================

Here are two forms of a revised procedure for you:

Form 1: Similar to the form you layed out:

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQLHomePhone As String
Dim strSQLCellPhone As String
Dim strSQLParentPhone As String

Set db = CurrentDb()

strSQLHomePhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLCellPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLParentPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone _
& " SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm"

strSQLCellPhone = strSQLCellPhone _
& " SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"

strSQLParentPhone = strSQLParentPhone _
& " SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People
strSQLHomePhone = strSQLHomePhone & " FROM People"
strSQLCellPhone = strSQLCellPhone & " FROM People"
strSQLParentPhone = strSQLParentPhone & " FROM People"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone _
& " WHERE (People.[Home Phone]) IS NOT NULL"
strSQLCellPhone = strSQLCellPhone _
& " WHERE (People.[Cell Phone]) IS NOT NULL"
strSQLParentPhone = strSQLParentPhone _
& " WHERE (People.[Parents Phone]) IS NOT NULL"

'Execute SQL Inserts
db.Execute strSQLHomePhone, dbFailOnError
db.Execute strSQLCellPhone, dbFailOnError
db.Execute strSQLParentPhone, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub

================================

Form 2: Create and execute each SQL statement in order

Option Compare Database
Option Explicit

Private Sub btnMovePhones_Click()
On Error GoTo ProcError

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQL As String

Set db = CurrentDb()

'Insert Home Phone numbers first
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "1 AS [Contact ID], People.[Home Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Home Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Cell Phone numbers next
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "3 AS [Contact ID], People.[Cell Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Cell Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Insert Parents Phone numbers last
strSQL = "INSERT INTO PhoneComm " _
& "([People ID], [Contact ID], PhoneComm) " _
& "SELECT People.ID AS [People ID], " _
& "9 AS [Contact ID], People.[Parents Phone] AS PhoneComm " _
& "FROM People " _
& "WHERE (People.[Parents Phone]) IS NOT NULL"

db.Execute strSQL, dbFailOnError

'Notify user
MsgBox "All records successfully inserted.", vbInformation, "Finished..."

ExitProc:
Set db = Nothing
Exit Sub
ProcError:
MsgBox "Error " & Err.Number & ": " & Err.Description, _
vbCritical, "Error in procedure btnMovePhones_Click..."
Resume ExitProc
End Sub



Hope you found this helpful.


Tom Wickerath
Microsoft Access MVP
https://mvp.support.microsoft.com/profile/Tom
http://www.access.qbuilt.com/html/expert_contributors.html
__________________________________________

wdsnews said:
Here is my first ever VBA code. I come from an ObjectPal background
where I
was very comfortable. But I'm new to Access, VBA, and SQL. This code is
attached to the 'Click On' event of a button to normalize data and turn a
flat file into a relational database. I would enjoy hearing two things.
Will this code work? What are your suggestions? I added _ line breaks
hoping it translates properly for email. Note that 'PhoneComm' is the
name
of a text field in a child table that is also named 'PhoneComm'. The
existing flat file is called 'People'.

Private Sub btnMovePhones_Click()

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

'INSERT INTO PhoneComm ( [People ID], [Contact ID], PhoneComm )
strSQLHomePhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLCellPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"
strSQLParentPhone = "INSERT INTO PhoneComm ( [People ID], [Contact ID],
PhoneComm )"

'SELECT People.ID, (x), People.[xxx Phone]
strSQLHomePhone = strSQLHomePhone & " SELECT People.ID AS _
[People ID], 1 AS [Contact ID], People.[Home Phone] AS PhoneComm"
strSQLCellPhone = strSQLCellPhone & " SELECT People.ID AS _
[People ID], 3 AS [Contact ID], People.[Cell Phone] AS PhoneComm"
strSQLParentPhone = strSQLParentPhone & " SELECT People.ID AS _
[People ID], 9 AS [Contact ID], People.[Parents Phone] AS PhoneComm"

'FROM People LEFT JOIN PhoneComm ON People.ID = PhoneComm.[People ID]
strSQLHomePhone = strSQLHomePhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLCellPhone = strSQLCellPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"
strSQLParentPhone = strSQLParentPhone & " FROM People LEFT JOIN _
PhoneComm ON People.ID = PhoneComm.[People ID]"

'WHERE (((People.[xxx Phone]) Is Not Null));
strSQLHomePhone = strSQLHomePhone & " WHERE (((People.[Home Phone]) _
IS NOT NULL"
strSQLCellPhone = strSQLCellPhone & " WHERE (((People.[Cell Phone]) _
IS NOT NULL"
strSQLParentPhone = strSQLParentPhone & " WHERE (((People.[Parents
Phone]) _
IS NOT NULL"

'Hide Warnings and Execute SQL
DoCmd.SetWarnings False
DoCmd.RunSQL strSQLHomePhone
DoCmd.RunSQL strSQLCellPhone
DoCmd.RunSQL strSQLParentPhone
DoCmd.SetWarnings True

End Sub

Thanks for your comments.
 
G

Guest

Hello Wdsnews -

You most certainly can stick with using ADO. Did you download this document?

http://home.comcast.net/~tutorme2/samples/ActionQueryExamplesWithSetWarnings.doc

The last example is an ADO code example.
On the Dim statement, one of my books explained that beginning with 2003,
VBA now correctly types multiple variables even if the 'As' statement is
only attached to the last one.

Sorry, but your book is incorrect. You might want to contact the publisher,
and ask them to post a correction in an errata section. Some publishers (not
all, sadly) maintain a page of corrections for each book they print. Here is
a simple experiment that you can conduct to prove this to yourself, using the
built-in TypeName function. You can also use the built-in VarType function,
but this returns a number. If you have your mouse cursor set blinking within
either of these function names in code (or selected), and you press the F1
key, you should see context-sensitive help for these functions, assuming your
Help files are working properly <smile>.

Private Sub btnMovePhones_Click()

'If Home Phone exists, move it to PhoneComm (1)
'If Cell Phone exists, move it to PhoneComm (3)
'If Parents Phone exists, move it to PhoneComm (9)

Dim db As DAO.Database
Dim strSQLHomePhone, strSQLCellPhone, strSQLParentPhone As String

Set db = CurrentDb()
db.Execute "DELETE * from PhoneComm"

Debug.Print "strSQLHomePhone: " & TypeName(strSQLHomePhone)
Debug.Print "strSQLCellPhone is: " & TypeName(strSQLCellPhone)
Debug.Print "strSQLParentPhone: " & TypeName(strSQLParentPhone)
Debug.Print

strSQLHomePhone = 123456
strSQLCellPhone = #6/25/2007#

Debug.Print "strSQLHomePhone: " & TypeName(strSQLHomePhone)
Debug.Print "strSQLCellPhone is: " & TypeName(strSQLCellPhone)
Debug.Print

strSQLHomePhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLCellPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

strSQLParentPhone = "INSERT INTO PhoneComm " _
& "( [People ID], [Contact ID], PhoneComm )"

Debug.Print "strSQLHomePhone: " & TypeName(strSQLHomePhone)
Debug.Print "strSQLCellPhone is: " & TypeName(strSQLCellPhone)
Debug.Print "strSQLParentPhone: " & TypeName(strSQLParentPhone)

End Sub


You should see the following results, in the Immediate Window:

strSQLHomePhone: Empty
strSQLCellPhone is: Empty
strSQLParentPhone: String

strSQLHomePhone: Long
strSQLCellPhone is: Date

strSQLHomePhone: String
strSQLCellPhone is: String
strSQLParentPhone: String


Note: I added a new line to the code, db.Execute "DELETE * from PhoneComm",
to clear this table each time the procedure is run. You might want to add
this to the full procedure.
Concerning the "DoCmd.SetWarnings False" issue, this is the only way I know
how to do it with ADO.

In Access, you can use something like this, as shown on page 3 of the Word
document:

CurrentProject.Connection.Execute strSQL, lngRecordsAffected, adCmdText

I dunno for using ADO with ASP or ASP.Net.

The method that you suggest seems to require ADO.

I think you meant to type "DAO". However, the answer is that it does not
require DAO.

I understand that ADO is more robust, however, looking toward the future, I
feel strongly that I need ADO. I'd enjoy hearing opinions about using ADO
vs. DAO, or both?

If you are using a JET back-end database, then (my opinion only) you are
better off to stick with DAO. If you are using any other data store, for
example, SQL Server, Oracle, Sybase, etc., then yes, you are better off to
use ADO. Here is an opinion published by Michael Kaplan concerning ADO:

What does DAO have that ADO/ADOx/JRO do not have (and might never have!)
http://www.trigeminal.com/usenet/usenet025.asp?1033

Although originally posted 5/24/2000, I think the information is still
current.
THANK YOU VERY VERY MUCH. Between, Access, SQL, and VBA, my learning curve
is steep, but this group has been very helpful to help me to travel a long
ways in a short time. Thank you for your time, your experience, and your
advice.

You're very welcome!


Tom Wickerath
Microsoft Access MVP
https://mvp.support.microsoft.com/profile/Tom
http://www.access.qbuilt.com/html/expert_contributors.html
__________________________________________
 
D

David W. Fenton

Concerning the "DoCmd.SetWarnings False" issue, this is the only
way I know how to do it with ADO.

Using Docmd.RunSQL uses neither ADO nor DAO.
The method that you suggest seems to require ADO. I
understand that ADO is more robust, however, looking toward the
future, I feel strongly that I need ADO.

ADO is not more robust. It is, in fact, dead, while DAO, with the
release of A2K7, is now in continuing development.

Now, ADO *may* be a better choice for a SQL Server back end.

But MDB to ODBC to SQL Server is going to work fine with DAO, too.

Search this newsgroup on Google Groups for DAO vs. ADO. ADO is old
and dead. DAO is specific to Jet and in current development, with
new life in A2K7 and the new ACE database format. DAO can be used
with Jet to get to any database engine that supports ODBC.

I see no reason whatsoever at this point for you to choose ADO. It
is a complete dead end.
 
I

IRS Intern

ADO is dead?

where do you come up with this crap, kid?

ADO.net is the worlds most popular language.

and I don't see the point in going back to a language that is SLOWER
and LESS POWERFUL

DAO has been dead for a decade; i don't see any reason for you to
proclaim that it is not dead.

I mean-- get real kid.

There is a new version of ADO in vista.

is there a new version of DAO? NOPE
 
I

IRS Intern

re:

DAO can be used
with Jet to get to any database engine that supports ODBC


uh.. except JET?

Jet can't even get to JET via ODBC so stfu kid
 
J

Jamie Collins

Here is an opinion published by Michael Kaplan concerning ADO:

What does DAO have that ADO/ADOx/JRO do not have (and might never have!)
http://www.trigeminal.com/usenet/usenet025.asp?1033

Although originally posted 5/24/2000, I think the information is still
current.

I consider the article to be biased, making unfair comparisons in
addition to containing inaccuracies ('current' is a moot point because
the article has always been biased and inaccurate <g>). For detailed
debunking of some of this article's points, see:

http://groups.google.com/group/microsoft.public.access/msg/70625c56d5b49a8e

Jamie.

--
 
J

Jamie Collins

Search this newsgroup on Google Groups for DAO vs. ADO. ADO is old
and dead.

What about DAO's Lost Weekend from 3.60 to ACEDAO i.e. missing Jet 4.0
functionality? For example, how do you create a CHECK constraint in
your shiny new DAO <g>?

ADO may be in maintenance mode but until DAO catches up after its Lost
Weekend ADO will still be relevant for Access/Jet. Sorry 'bout that!
DAO can be used
with Jet to get to any database engine that supports ODBC.

But only in the unlikely event that DAO can accurately map the
source's data types.

Jamie.

--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top