2015-02-26 1 views
0

Je rencontre un problème frustrant avec liaison tardive à MS Access à partir de Excel VBA pour exécuter une instruction DML comme insertion ou mise à jour. Toutes les données que j'utilise dans vba proviennent de classes définies par l'utilisateur. Je peux très bien interroger, mais écrire à la base de données obtient des erreurs différentes chaque fois que j'essaie de faire la même chose. Vous trouverez ci-dessous quelques liens vers les mêmes problèmes, mais chacun est légèrement hors contexte et je n'ai donc pas réussi à résoudre mon problème.Excel VBA Late Bind à accès et SQL Insert

Mon objectif final est d'exécuter simplement une DML chaîne de caractères et il doit utiliser une liaison tardive. Principalement je reçois l'erreur 3251 disant que ma connexion est 'Read Only' ou un ISAM manquant quand j'ajoute ReadOnly = 0 à la chaîne de connexion. Fyi, getProjectFile retourne juste un chemin vers un fichier à partir du dossier parent de mon projet. Je suis assez sûr que je peux juste utiliser le connDB.Execute donc j'ai seulement besoin de SQL Insert, je ne veux pas interroger d'abord parce que les requêtes vont grossir rapidement. Je pense aussi que quelque chose ne va pas avec les params enum parce que les ExecuteOptions veulent des masques de bit au lieu de juste un long et je ne sais pas vraiment comment le faire. De la plupart de mes recherches, j'ai continué à me référer au LockType et/ou au curseur qui n'était pas correct. Pour mon environnement Windows 8.1 64 bits, MS Office 2010 32 bits (requis). Est-ce que quelqu'un voit ce qui ne va pas ici?

Sub ADO_Tester() 

Dim strSQL, strFile, strConnection As String 
Dim connDB As Object 

'late bind to the ADODB library and get a connection object 
Set connDB = CreateObject("ADODB.Connection") 

'Connect to the DB 
strFile = Application.ActiveWorkbook.Path & "\" & "PortfolioDB.accdb" 
strConnection = "Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";" 
connDB.Open strConnection 

'insert statement for a test record 
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')" 

'execute the 
connDB.Execute strSQL, , 2, 1 + 128 

'clear the object 
connDB.Close 
Set connDB = Nothing 

End Sub 

Edit:

liaison anticipée:

connDB.Execute strSQL, , adCmdText + adExecuteNoRecords 

liaison tardive: Comment entrer la valeur pour adExecuteNoRecords? Sur msdn, il est 0x80 et un autre message dit & H0001, de toute façon il donne une erreur de syntaxe. Il dit entrer un masque de bits pour cette valeur enum.

connDB.Execute strSQL, , 1 + 0x80 

Edit: Maintenant, la bonne façon - adExecuteNoRecords (la valeur enum ADO) = 0x80 (valeur binaire) = 128 (valeur décimale)

connDB.Execute strSQL, , 1 + 128 

Edit: maintenant le problème devient encore plus profond. Lorsque j'exécute le code dans une feuille de calcul de test dans une base de données de test, cela fonctionne. Lorsque je copie et colle dans la feuille de calcul du projet réel et que je pointe vers le projet réel db, j'obtiens l'erreur: l'opération doit utiliser une requête pouvant être mise à jour. . . encore. Même nom db, même dml, même nom de table. La seule différence est la DB réelle est un produit d'une scission pour le séparer des formes et du code dans Access. Est-ce que cela a pu changer un réglage pour le faire uniquement lire?

Editer: Il devient juste de plus en plus profond. Le problème qui l'empêche de fonctionner dans le projet db est que certaines tables Excel interrogent la base de données. J'ai fait ceux-ci à travers l'interface utilisateur Excel, ruban -> données externes -> accès -> etc. . Il est maintenant devenu évident que cela m'empêche d'insérer du DML car ils sont probablement configurés en lecture seule. Comment puis-je modifier les permissions de connexion des tables?Y a-t-il une autre façon de faire ces tableaux pour que je puisse fournir la connexion? Comment rendre les tables compatibles avec DML dans VBA?

+0

J'ai oublié de mentionner que j'ai également regardé dans l'instruction 'IN' pour un insert; 'INSÉRER DANS DANS () VALEURS (). Cependant je ne l'ai pas encore essayé. Serait-ce une bonne solution? Des mots de sagesse pour l'utiliser? –

+0

C'est une façon de le faire, mais cela ne devrait pas être nécessaire. J'utilise généralement ces instructions lorsque je ne veux pas ouvrir des connexions séparées à chaque base de données d'accès. Quelle erreur se produit lorsque vous changez 'connDB.Execute strSQL,, 2, & H1' en' connDB.Execute strSQL'? –

+0

Lorsque j'utilise simplement connDB.Execute strSQL, j'obtiens une erreur qui indique qu'il est en lecture seule et que le type de verrouillage est incorrect ou que le fournisseur ne peut pas le faire. Sur msdn, la méthode Execute est définie par défaut sur ForwardReadOnly. Mon fournisseur est le ACE.OLEDB, qui est le même fournisseur que tout le monde utilisé dans les exemples. J'ai essayé certains des autres lockTypes mais ils ont retourné la même erreur. –

Répondre

0

Cela a fonctionné pour moi:

Option Explicit 

Private Const acCmdText As Integer = 1 

Sub ADO_Tester() 
On Error GoTo ErrorHandler 

    Dim strSQL As String 
    Dim strFile As String 
    'Dim adoRecSet As Object 
    Dim connDB As Object 

    'late bind to the ADODB library and get a connection object 
    Set connDB = CreateObject("ADODB.Connection") 

    'Connect to the DB 
    strFile = getProjectFile("core", "PortfolioDB.accdb") 
    connDB.Open connectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";" 

    'If State = 1, db connection is okay. 
    MsgBox "ADO Connection State is " & connDB.State & "." 

    'SQL to get the whole [underlying_symbol] table 
    'strSQL = "underlying_symbol" 'if options 2 
    'strSQL = "SELECT * FROM underlying_symbol" 'if options 1 
    strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')" 

    'late bind to adodb and get recordset object 
    'Set adoRecSet = CreateObject("ADODB.Recordset") 

    '&H0001 = bitmask for aCmdText 
    connDB.Execute strSQL, , acCmdText 

    'With adoRecSet 
    ' .Open Source:=strSQL, _ 
     '  ActiveConnection:=connDB, _ 
     '  CursorType:=1, _ 
     ' LockType:=3, _ 
     ' Options:=&H1 
     '.AddNew 
     '.fields("symbol") = "XYZ" 
     '.Update 
    'End With 

    '------------------ 

    'close the objects 
    'adoRecSet.Close 
    connDB.Close 

    'destroy the variables 
    'Set adoRecSet = Nothing 
    Set connDB = Nothing 

ExitMe: 
    Exit Sub 
ErrorHandler: 
    MsgBox Err.Number & ": " & Err.Description 
    GoTo ExitMe 

End Sub 

Ajout une gestion des erreurs, une constante qui définit acCmdText (Pourquoi tout simplement pas ajouter une référence à la bibliothèque ADO jusqu'à vous, bien?.) Et une boîte de message à Vérifiez l'état de la connexion à la base de données, car je ne peux pas tester votre fonction getProjectFile. La liaison tardive ne semble pas être la question ici, je pense que la ligne clé est:

connDB.Execute strSQL, , 2, &H1 

peut vraiment dire ce qui se passe ici comme je l'ai jamais fait comme ça (le code ne compile même pas) , mais le changement à

connDB.Execute strSQL, , acCmdText 

travaillé pour moi.

+0

Si j'utilise simplement adCmdText, j'obtiendrai une erreur. Pour moi cela fonctionne avec une liaison anticipée: 'connDB.Execute strSQL,, adCmdText + adExecuteNoRecords' La liaison anticipée ne fonctionne pas du tout pour ma situation, j'ai déjà essayé d'écrire un tas de code de référence dynamique et c'était une très mauvaise idée. La liaison anticipée n'est utile que si le code ne fonctionne que sur les ordinateurs auxquels vous avez accès. Alors savez-vous comment entrer adExecuteNoRecords comme un masque de bits? 'connDB.Execute strSQL,, 1 +?' –

+0

Ha ha ne importe pas, je l'ai compris. 'connDB.Execute strSQL,, 1 + 128' où (adCmdText = 1) Et (+) (adExecuteNoRecords = 0x80 = 128). Ce n'était pas presque évident. –

+0

Eh bien ce genre de travail. Maintenant, il s'avère que si vous avez des tables, aka ListObjects, avec une requête provenant de la même DB, ils vont interférer avec le DML. –