BEST PRACTICES -> SQL with DAO

Irish_Griffin

Board Regular
Joined
Jan 16, 2009
Messages
138
Hi guys,
I've discovered excel can do SQL !!! It feels like I'm the primitive caveman discovering fire :laugh:

Well lets not talk about how much time I've wasted writing code that would have been soooooooo much easier in SQL :( .... Instead, lets talk about BEST PRACTICES using SQL in EXCEL :cool:

I would like to make this thread a good reference for others ( not much online surprisingly ). I'll make this a sweet thread if I can get the guru's help.

So first and foremost:
#1 - Is DAO the right choice ?

Remember to take learning one bite at a time:
QrUHZ.jpg
 
Blade

Creating charts in Excel from data from Access, that has got to be one of my pet hates.

No, wait a minute it's creating charts in Excel

Or maybe it's creating charts in Access - I can't make my mind up.

Oh, I've just thought of another candidate - trying to automate Excel from C#.

I really can't make my mind up - anybody got a 4-sided coin I could spin.

LOL... wow, I'm thrilled to be moving into this profession :laugh:


Thank you for the work already done so far. You guys are really taking this challenge to level I not even close to!!! :eeek:

I'm absorbing this stuff as time allows..... but up in the Detroit automotive industry, spare time to work on "Side Projects" is few and far between :(

I sit down for about an hour of reading then get pulled into some other cluster F^&K in the office ..... LOL

Gotta stay positive :cool: I will be compiling this information into a final template for the community. Just bare with my limited time =-)

-Griff
 
Upvote 0
Just passing by. Here's some hurried ADO code that I used once to copy from the NWind.mdb (MS Access) to a MySQL server on my website. Not sure whether this is more complicated than you want or will help because it has variety. Good luck with it!

Code:
Option Explicit

    Public dbname As String
    Public fldnames(100, 2) As String
    Public conn As ADODB.Connection
    Public sh As Worksheet


'
'   EXAMPLE VBA CODE: Use SQL statement to copy data from NWind.mdb
'
'   Single, simple function to copy data from mdb to the spreadsheet
Public Sub readNWind()
    Dim db As Database, rs As Recordset
    Set db = OpenDatabase("NWind.mdb")
    Set rs = db.OpenRecordset("SELECT Categories.CategoryID, Categories.CategoryName, " & _
    "Categories.Description, `Category Sales for 1995`.CategorySales " & _
    "FROM Categories Categories, `Category Sales for 1995` `Category Sales for 1995` " & _
    "WHERE `Category Sales for 1995`.CategoryName = Categories.CategoryName")
    ThisWorkbook.Worksheets("Sheet1").Range("A1").CopyFromRecordset rs
End Sub
'=======================================================================
'           3 ROUTINES TO COPY TABLES FROM NWind.mdb to MySQL
'=======================================================================
'
'       First routine: list table names in NWind.mdb, create if missing from MySQL,
'                      then copy data
'
Public Sub listDbFields()
    Dim db As Database, rs As Recordset, tdf As TableDef, fld As Field
    Dim SQL As String, nm As String
    Dim msqltyp As String, r As Integer, c As Integer, sh As Worksheet
    openMySQLConn
    'Set sh = ThisWorkbook.Worksheets("MySQLExamples")
    'sh.UsedRange.Clear
    Set db = OpenDatabase("Nwind.mdb")
    r = 1
    For Each tdf In db.TableDefs
        If Left(tdf.Name, 4) <> "MSys" Then
            SQL = "CREATE TABLE if not exists `" & tdf.Name & "`(" & vbCrLf & _
                   "ID integer PRIMARY KEY auto_increment," & vbCrLf
            
            'sh.Cells(r, 1) = tdf.Name
            c = 1
            
            ' The outside loop (above) takes the name of each of the Access tables.
            ' Using this tabledef, it loops through the individual fields
            ' below and builds a SQL statement to create the table in the
            ' MySQL database of choice. After adding the table to the database
            ' it loops through the records, creating INSERT statements which
            ' it then executes
            
            For Each fld In tdf.Fields
                '  Ascertain the type (simplifying: can be changed later)
                Select Case fld.Type
                    Case Is = dbInteger, dbBigInt, dbLong
                        msqltyp = "integer"
                    Case Is = dbFloat, dbDouble, dbSingle
                        msqltyp = "double"
                    Case Is = dbCurrency, dbNumeric
                        msqltyp = "decimal"
                    Case Is = dbText, dbChar, dbByte
                        msqltyp = "text"
                    Case Is = dbDate, dbTime
                        msqltyp = "datetime"
                    Case Is = dbVarBinary, dbLongBinary, dbBinary, dbMemo, dbGUID
                        msqltyp = "blob"
                    Case Is = dbBoolean
                        msqltyp = "boolean"
                    Case Else
                        msqltyp = "(unident)"
                End Select
                ' Create the field name/type in the CREATE statement
                fldnames(c, 1) = fld.Name: fldnames(c, 2) = msqltyp
                SQL = SQL & fld.Name & " " & msqltyp
                If c < tdf.Fields.Count Then SQL = SQL & "," & vbCrLf
                c = c + 1
            Next
            SQL = SQL & ")"
            nm = "`" & tdf.Name & "`"
            addMysqlTable nm, SQL       ' Create table in MySQL
            copyData db, nm             ' Copy the data
        End If
    Next
End Sub
'
'   Check to see if table exists, if it does drop it, then create it
'
Public Sub addMysqlTable(tbl As String, SQL As String)
    conn.Execute "DROP TABLE IF EXISTS " & tbl
    Debug.Print tbl & " created"
    conn.Execute SQL
End Sub
'
'   Copy data from database (mdb) to mysql
'
Public Sub copyData(db As Database, tblname As String)          ' conn is set for table
        Dim rs As Recordset, fld As Field, comma As String, vals As String
        Dim v As Variant
        Dim SQL As String, i As Integer
        Set rs = db.OpenRecordset("SELECT * FROM " & tblname)
        rs.MoveFirst
        While Not rs.EOF
            SQL = "INSERT INTO " & tblname & "("
            vals = ""
            For i = 1 To rs.Fields.Count
                comma = ","
                If fldnames(i, 2) <> "blob" Then
                    SQL = SQL & fldnames(i, 1) & comma
                    If fldnames(i, 2) = "text" Then
                        vals = vals & Chr(34) & rs.Fields(i - 1).Value & Chr(34) & comma
                    Else
                        v = rs.Fields(i - 1).Value
                        If v = "" Then v = 0
                        vals = vals & v & comma
                    End If
                End If
            Next i
            SQL = Left(SQL, Len(SQL) - 1) & ")" & " Values (" & Left(vals, Len(vals) - 1) & ")"
            'Debug.Print SQL
            On Error GoTo badrcd
            conn.Execute (SQL)

            rs.MoveNext
            Wend
        Exit Sub
badrcd:
    On Error GoTo 0
    Debug.Print "Ignoring " & SQL
    Resume Next
End Sub

Public Sub openMySQLConn()
    Dim SQL As String
    Set conn = New ADODB.Connection
    conn.ConnectionString = "DRIVER={MySQL ODBC 5.1 Driver};" _
        & " SERVER=[insert your server name here]; port=3307;" _
        & " DATABASE=[insert database name];" _
        & " UID=guest;PWD=[insert password];OPTION=3"
    conn.Open
End Sub
 
Upvote 0
OK guys, little bit of progress:

Template to:
1) Copy an excel sheet ( input_sheet )
2) Preform SQL comand ( SQL_text )
3) Paste to a second excel sheet ( output_sheet )

Notes:
This code assumes the first row in your input sheet contains column headings and then names the record source columns the same. Important to know when building your SQL code.

Code:
Sub Test()
Dim SQL_Text As String

SQL_Text = "WHERE Part_Type='Seal'"

Call Run_SQL("Input", SQL_Text, "Output")

End Sub
Code:
Sub Temp_SQL(Input_Sheet As String, SQL_Text As String, Output_Sheet As String)


Dim conn As New ADODB.Connection
Dim rs As New ADODB.Recordset
Dim Cmd As New ADODB.Command
Dim Data As Worksheet
Dim Column_Count As Integer
Dim X As Long


'This sets up the temporary database file to run the SQL code
    Dim file_path_name As String
    file_path_name = ThisWorkbook.FullName
    'Application.Calculation = xlCalculationManual
    conn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & file_path_name & ";Extended Properties=""Excel 8.0;HDR=Yes"";"
    Cmd.ActiveConnection = conn
    Cmd.CommandType = adCmdText
    
'This takes the input sheet and creates a table within the database
    rs.Open "SELECT * FROM [" & Input_Sheet & "$]", conn, adOpenStatic, adLockReadOnly
    
'Start with clear ouput sheet before continuing
    Worksheets(Output_Sheet).Cells.Clear

'Determine the number of columns on the sheet
    Column_Count = Worksheets(Input_Sheet).UsedRange.Columns.Count
 
'Puts titles above each column, this allows for SQL code to reference the column name
    For X = 0 To Column_Count - 1 'Change the 4 to the number of columns you are selecting MINUS 1
        Sheets(Input_Sheet).Cells(1, X + 1) = rs.Fields(X).Name
        Sheets(Output_Sheet).Cells(1, X + 1) = Sheets(Input_Sheet).Cells(1, X + 1)
    Next
    
'This creates the SQL command to run on input sheet data
    SQL_Text = "SELECT * FROM [" & Input_Sheet & "$]" & SQL_Text
    Cmd.CommandText = SQL_Text
    Set rs = Cmd.Execute
        
'This pastes SQL results onto the output sheet
    Worksheets(Output_Sheet).Range("A2").CopyFromRecordset rs
    
'Not clear what this code does.....
    'Application.Calculation = xlCalculationAutomatic
    'Application.Calculate
    
End Sub
QUESTION:
Is the "application.calulate" lines of code needed? What is it for?

Thanks
x2B7H.jpg
 
Last edited:
Upvote 0
Next on the todo list:
1) A template that creates a local recordset that stays open until file is closed. To be used when one set of data is expected to be filtered and sorted multiple times and want to avoid having to create a recordset every time....

2) A template that uses a network .mdb file as a permeate database that can be used to create recordsets and run SQL on.

Hopefuly wont get distracted today..... my job blows sometimes...... :rolleyes:
 
Upvote 0
You are correct, Application.calculate is not needed after application.calculation = xlcalculationautomatic is set.
 
Upvote 0
OK, lots of progress!!!! Finally was left alone for most of the day yesterday!!! :biggrin:

I need to define the best method to pull data out of a ADO database..... Does this method seem like the best approach??

1) Execute SQL code from ADO connection
2) Create Record set
3) VBA Loop Code to convert Record Set into an Array
4) Use Array in VBA

Can't wait to show off this tool. Here is a list of the sub routine tools, please suggest other tools I've missed:

- Create mdb database file
- Delete mdb database file
- Create table in database and fill in with defined range
- User provided SQL code to add column to db table
- Delete table in database
- User provided SQL code on db table to create table in databse
- User provided SQL code on db table to create Array ( in progress.... )
- User provided SQL code on db table to paste onto worksheet.range

I've kept it simple yet seem to have all the basic tools needed to give excel some serious power!! :cool:

Hopefully have it ready to post up soon!!

-Griff

MtTCU.jpg
 
Upvote 0
I've got this code for every ADO sub routine:

Code:
'Opens a connection to the database File
Dim ADO_Connection As ADODB.connection
Set ADO_Connection = New ADODB.connection
Connection_String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & DB_location_name & ";"
ADO_Connection.Open (Connection_String)
How can I consolidate this into one line of code I can call on every time I need a connection?

I'm anticipating the user needing to modify this connection code, it would be alot easier if the code was only in one place...... The connection does not work if I put it in a function or another subroutine I "call".... thoughts?
 
Last edited:
Upvote 0
So I have a SUB that creates the desired recordset.....

How do I use this recordset in another SUB? After I exit the sub the recordset disapears.....

Code:
Sub SQL_to_Table(DB_location_name As String, SQL_Text As String)
' This code will run SQL on an existing table and results will be outputed to a new db table

'Opens a connection to the database File
Dim ADO_Connection As ADODB.connection
Set ADO_Connection = New ADODB.connection
Connection_String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & DB_location_name & ";"
ADO_Connection.Open (Connection_String)

Dim CMD As New ADODB.Command
Dim RS As New ADODB.Recordset

CMD.ActiveConnection = ADO_Connection
CMD.CommandType = adCmdText
CMD.CommandText = SQL_Text
Set RS = CMD.Execute


'Close the connection so that computer resources are not used
ADO_Connection.Close
Set ADO_Connection = Nothing

End Sub
 
Last edited:
Upvote 0

Forum statistics

Threads
1,226,837
Messages
6,193,257
Members
453,786
Latest member
ALMALV

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top