VBA-SQL UPDATE/INSERT/SELECT to/from Excel worksheet

CheeseMo picture CheeseMo · Dec 14, 2015 · Viewed 12.6k times · Source

In a nutshell: I'm making a scheduler for my client and, due to constraints, it needs to be in a single excel file (as small as possible). So one worksheet works as the UI and any others will be tables or settings.

I'm trying to use SQL (to which I'm new) to work with the schedule data on a single worksheet (named "TblEmpDays"). So I need to add/update and retrieve records to/from this worksheet. I was able to get a SELECT query to work with some arbitrary data (and paste to a Range). However, I'm not able to get INSERT or UPDATE to work. I've seen it structured as INSERT INTO [<table name>$] (<field names>) VALUES (<data>);. However this gives me a run-time error "'-2147217900 (80040e14)' Syntax error in INSERT INTO statement."

I'm using VBA to write all of this and I made an SQL helper class to make the query execution easier.

To clarify, my question is: How do I need to construct the INSERT and UPDATE queries? What am I missing? I'm trying to post as much related info as possible, so let me know if I missed anything.

Class SQL:

Private pCn ' As Database
Private pResult 'As Recordset
Private pSqlStr As String

Public Property Get Result()
    Result = pResult
End Property

Public Function Init()
    Set pCn = CreateObject("ADODB.Connection")

    With pCn
        .ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                            "Data Source=" & ThisWorkbook.FullName & ";" & _
                            "Extended Properties=""Excel 12.0 Macro;HDR=YES;ReadOnly=False"";"
        .Open
    End With

End Function

Public Function Cleanup()
    If Not (pCn Is Nothing) Then
        pCn.Close
        Set pCn = Nothing
    End If

    If Not pResult Is Nothing Then
        Set pResult = Nothing
    End If

End Function

Public Function CopyResultToRange(rg As Range)
    If Not rg Is Nothing And Not pResult Is Nothing Then
        rg.CopyFromRecordset pResult
    End If
End Function

Public Property Get query() As String
    query = pSqlStr
End Property
Public Property Let query(value As String)
    pSqlStr = value
End Property

Public Function Execute(Optional sqlQuery As String)
    If sqlQuery = "" Then
        sqlQuery = query
    End If

    If Not pCn Is Nothing Then
        Set pResult = pCn.Execute(sqlQuery, , CommandTypeEnum.adCmdText Or ExecuteOptionEnum.adExecuteNoRecords)
    Else
        MsgBox "SQL connection not established"
    End If

End Function

Executing function:

Dim s As SQL ' this is the SQL class '
Dim tbl As String
' rcDay=date string, rcIn & rcOut = time strings, rcVac=boolean string, rcSls=number string'
Dim rcName As String, rcDay As String, rcIn As String, rcOut As String, rcVac As String, rcSls As String
Dim qry As String

tbl = "[TblEmpDays$]"
qry = "INSERT INTO <tbl> (name, date, in, out, vac, sales)" & vbNewLine & _
        "VALUES ('<name>', '<date>', '<in>', '<out>', '<vac>', <sales>);"

' Set rc* vars '

s.Init
s.query = Replace(Replace(Replace(Replace(Replace(Replace(Replace(qry, _
                                    "<tbl>", tbl), _
                                    "<sales>", rcSls), _
                                    "<vac>", rcVac), _
                                    "<out>", rcOut), _
                                    "<in>", rcIn), _
                                    "<date>", rcDay), _
                                    "<name>", rcName)
MsgBox s.query
s.Execute
s.Cleanup

I've looked all over an can't find a solution. I'm sure I just haven't searched the right phrase or something simple.

Answer

CheeseMo picture CheeseMo · Dec 15, 2015

I'm posting the solution here since I can't mark his comment as the answer.


Thanks to @Jeeped in the comments, I now feel like an idiot. It turns out three of my field names were using reserved words ("name", "date", and "in"). It always seems to be a subtle detail that does me in...

I renamed these fields in my worksheet (table) and altered the appropriate code. I also had to Cast the input strings into the proper data types. I'm still working the rest of the details out, but here's the new query:

qry = "INSERT INTO <tbl> (empName, empDay, inTime, outTime, vac, sales)" & vbNewLine & _
                  "VALUES (CStr('<name>'), CDate('<date>'), CDate('<in>'), CDate('<out>'), " & _
                      "CBool('<vac>'), CDbl(<sales>));"

I needed the CDate() (instead of the #*#) so I could pass in a string. So CDate('<date>') instead of #<date>#