2015-12-14 145 views
5

一言で言えば、私はクライアント用のスケジューラを作成していますが、制約のために、1つのExcelファイル可能)。したがって、ワークシートの1つはUIとして機能し、他のワークシートはテーブルまたは設定になります。ExcelワークシートとのVBA-SQLの更新/挿入/選択

1つのワークシート(「TblEmpDays」という名前)でスケジュールデータを処理するためにSQLを使用しようとしています。したがって、このワークシートとの間でレコードを追加/更新して取得する必要があります。私はSELECTクエリをいくつかの任意のデータ(および範囲に貼り付ける)で動作させることができました。しかし、私はINSERTまたはUPDATEを動作させることができません。私はそれがINSERT INTO [<table name>$] (<field names>) VALUES (<data>);として構造化されているのを見ました。しかし、これは私に「『-2147217900(80040E14)』 INSERT INTOステートメントの構文エラーを。」実行時エラーを与える

を、私はこのすべてを書くためにVBAを使用していると私は作るためにSQLヘルパークラスを作りましたクエリの実行が容易になります。

私の質問は、INSERTUPDATEのクエリをどのように構築する必要があるのですか?私は何が欠けていますか?私はできるだけ多くの関連情報を投稿しようとしていますので、私が何かを見逃していれば教えてください。

クラス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 

実行機能は:

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 

私は解決策を見つけることができない以上、すべてを見てきました。私はちょうど正しいフレーズや何かをシンプルに検索していないと確信しています。

+0

Excelでデータベースを再作成するのは難しい作業です。 Jet/ACEデータベースを作成するためにMS Accessを使用しますか?注意:ユーザーはAccessを使用する必要はありませんが、UIブックを.accdb/.mdbファイルに接続してデータを格納し、使用可能なSQLをすべて使用できます。 Jet/ACE SQLエンジンは、Windowsユーザーが使用できる.dllファイルです(また、Accessにのみ限定されません)。 – Parfait

+0

@パルフェット私はそれを掘り下げなければならないでしょう(矛盾する回答を得る...).dllは何ですか、そしてそれはどこにありますか?たぶん私は彼らがアクセスを持っていない場合はそれを見つけることができます。 (私はこのプロジェクト全体を考えて、Accessを使用することができればどれくらい簡単になるでしょうか) – CheeseMo

+0

通常、Windows自体にインストールされているJet/ACEエンジンを使用するには、MS Accessはインストールされていません。 Notepad.exeのようなものです。 Registry、HKEY CLASSES ROOT: 'Microsoft.ACE.OLEDB.12.0'と' Microsoft.JET.OLEDB.4.0'を参照してください。また、ユーザーは.accdbファイルを使用するには**無料** [Access runtime](https://www.microsoft.com/en-US/download/details.aspx?id=39358)をダウンロードできます(ただし、開発者はフルプログラム)。 – Parfait

答えて

1

私は答えとしての彼のコメントをマークすることはできませんので、私はここで解決策を掲載しています。コメント欄で@Jeepedから


おかげで、私は今、馬鹿のように感じます。私のフィールド名のうち3つは予約語( "name"、 "date"、 "in")を使用していました。 それはいつも私をしている微妙な細部のようです...

ワークシート(表)でこれらのフィールドの名前を変更し、適切なコードを変更しました。私はまた、入力文字列を適切なデータ型にキャストしなければなりませんでした。私はまだ出て細部の残りを働いているが、ここで新しいクエリです:

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

は私が CDate()(代わりに#*の#を)必要なので、私は、文字列で渡すことができます。 so #<date>#の代わりに CDate('<date>')

0

プロジェクトのワークシートではなく、リレーショナルデータベースをバックエンドとして使用することを検討してください。 UIスプレッドシートをフロントエンドとして引き続き使用できます。 Windows製品として、Jet/ACE SQLエンジンは実用的なソリューションとなり、複数のユーザーが同時アクセス(レコードレベルのロックを使用)できるようになります。さらに、Jet/ACEには、Database Definition Language (DDL)Database Maniupulation Language (DML)プロシージャの独自のSQLダイアレクトが装備されています。また、ExcelはADO/DAOオブジェクト経由でJet/ACEに接続できます。 Jet/ACEと他のRDMSとの唯一の違いは、ファイルレベルのデータベース(サーバーではない)であり、SQLを使用してデータベースを作成できないことです。まず、VBAまたは他のCOM定義言語を使用してデータベースファイルを作成する必要があります。

以下は、DAOを使用してデータベースを作成し、ADOを使用してテーブルを作成し、アクションクエリを実行し、レコードセットをワークシートにコピーするVBAスクリプト(クライアントテーブルと受注テーブル)の実例です。これらのマクロをプロジェクトに統合します。エラー処理とdebug.Printを使用してアプリケーションを開発してください。 MS Accessがインストールされていない場合、.accdbファイルはディレクトリに表示されますが、空白のアイコンが表示されます。コード経由以外でファイルを管理するユーザーインターフェイスはありません。

Sub CreateDatabase() 
On Error GoTo ErrHandle 
    Dim fso As Object 
    Dim olDb As Object, db As Object 
    Dim strpath As String 
    Const dbLangGeneral = ";LANGID=0x0409;CP=1252;COUNTRY=0" 

    strpath = "C:\Path\To\Database\File.accdb" 

    ' CREATE DATABASE ' 
    Set fso = CreateObject("Scripting.FileSystemObject") 
    Set olDb = CreateObject("DAO.DBEngine.120") 

    If Not fso.FileExists(strpath) Then 
     Set db = olDb.CreateDatabase(strpath, dbLangGeneral) 
    End If 

    Set db = Nothing 
    Set olDb = Nothing 
    Set fso = Nothing 

    MsgBox "Successfully created database!", vbInformation 
    Exit Sub 

ErrHandle: 
    MsgBox Err.Number & " - " & Err.Description, vbCritical 
    Exit Sub 
End Sub 

Sub CreateTables() 
On Error GoTo ErrHandle 
    Dim strpath As String, constr As String 
    Dim objAccess As Object 
    Dim conn As Object 

    strpath = "C:\Path\To\Database\File.accdb" 

    ' CONNECT TO DATABASE ' 
    constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strpath & ";" 
    Set conn = CreateObject("ADODB.Connection") 
    conn.Open constr 

    ' CREATE TABLES (RUN ONLY ONCE) ' 
    conn.Execute "CREATE TABLE Clients (" _ 
        & " ClientID AUTOINCREMENT," _ 
        & " ClientName TEXT(255)," _ 
        & " Address TEXT(255)," _ 
        & " Notes TEXT(255)," _ 
        & " DateCreated DATETIME" _ 
        & ");" 

    conn.Execute "CREATE TABLE Orders (" _ 
        & " OrderID AUTOINCREMENT," _ 
        & " ClientID INTEGER," _ 
        & " Item TEXT(255)," _ 
        & " Price DOUBLE," _ 
        & " OrderDate DATETIME," _ 
        & " Notes TEXT(255)" _ 
        & ");" 

    ' CLOSE CONNECTION ' 
    conn.Close 
    Set conn = Nothing 

    MsgBox "Successfully created Clients and Orders tables!", vbInformation 
    Exit Sub 

ErrHandle: 
    MsgBox Err.Number & " - " & Err.Description, vbCritical 
    Exit Sub 

End Sub 

Sub RetrieveDataToWorksheet() 
On Error GoTo ErrHandle 
    Dim strpath As String, constr As String 
    Dim conn As Object, rs As Object 
    Dim fld As Variant 

    strpath = "C:\Path\To\Database\File.accdb" 

    ' OPEN CONNECTION ' 
    constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strpath & ";" 
    Set conn = CreateObject("ADODB.Connection") 
    Set rs = CreateObject("ADODB.Recordset") 

    conn.Open constr 
    rs.Open "SELECT * FROM Clients" _ 
      & " INNER JOIN Orders ON Clients.ClientID = Orders.ClientID;", conn 

    ' COPY FROM RECORDSET TO WORKSHEET ' 
    Worksheets(1).Activate 
    Worksheets(1).Range("A4").Select 

    ' COLUMN NAMES ' 
    For Each fld In rs.Fields 
     ActiveCell = fld.Name 
     ActiveCell.Offset(0, 1).Select 
    Next 

    ' ROW VALUES ' 
    Worksheets(1).Range("A5").CopyFromRecordset rs 

    ' CLOSE RECORDSET AND CONNECTION ' 
    rs.Close 
    conn.Close 

    Set conn = Nothing 
    Set rs = Nothing 
    Exit Sub 

ErrHandle: 
    MsgBox Err.Number & " - " & Err.Description, vbCritical 
    Exit Sub 
End Sub 

Sub ActionQueries() 
On Error GoTo ErrHandle 
    Dim strpath As String, constr As String 
    Dim conn As Object 

    strpath = "C:\Path\To\Database\File.accdb" 

    ' OPEN CONNECTION ' 
    constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strpath & ";" 
    Set conn = CreateObject("ADODB.Connection") 
    conn.Open constr 

    ' APPEND QUERY ' 
    conn.Execute "INSERT INTO Clients (ClientID, ClientName)" _ 
        & " VALUES (" & Worksheets(1).Range("A2") & ", '" & Worksheets(1).Range("B2") & "');" 

    conn.Execute "INSERT INTO Orders (ClientID, Item, Price)" _ 
        & " VALUES (" & Worksheets(1).Range("A2") & ", " _ 
        & "'" & Worksheets(1).Range("C2") & "', " _ 
        & Worksheets(1).Range("D2") & ");" 

    ' UPDATE QUERY ' 
    conn.Execute "UPDATE Clients " _ 
        & " SET Address = '" & Worksheets(1).Range("E2") & "'" _ 
        & " WHERE ClientID = " & Worksheets(1).Range("A2") & ";" 

    ' DELETE QUERY ' 
    conn.Execute "DELETE FROM Orders " _ 
        & " WHERE ClientID = " & Worksheets(1).Range("A2") & ";" 

    ' CLOSE CONNECTION ' 
    conn.Close 
    Set conn = Nothing 

    MsgBox "Successfully updated database!", vbInformation 
    Exit Sub 

ErrHandle: 
    MsgBox Err.Number & " - " & Err.Description, vbCritical 
    Exit Sub 
End Sub 
+0

うわー。私は後のプロジェクトでこれを覚えておく必要があります。悲しいことに、私の質問で述べたように、私はすべてのものが1つのExcelファイルに含まれている必要があります。私はあなたがExcelファイル内にデータベースを埋め込むことと一緒に示唆しているものの実行可能性を調べました。 Excelが保存されるたびにその保存ファイルを完全に書き換えるので、この場合、あまりにも多くの作業が必要になると私は判断しました。再度、感謝します! – CheeseMo