I have read every question on this site having to do with SaveAsText (and other version-control-with-Access related questions).
The most helpful one so far was this one. I am using a slightly modified version of the VBScript code posted in Oliver's answer to save my objects as text files. My application is an .adp, and the database (which obviously includes the Stored Procedures) is SQL Server 2005.
I have attempted to add this code to my VBScript, but I consistently get an error that says "You have cancelled the previous operation" when the SaveAsText line is hit.
For Each myObj In oApplication.CurrentData.AllStoredProcedures
WScript.Echo " " & myObj.fullname
oApplication.SaveAsText acQuery, _
myObj.fullname, _
sExportpath & "\" & myObj.fullname & ".sql"
dctDelete.Add "RE" & myObj.fullname, acQuery
Next
Based on the response in this question, I made sure to add
Const acQuery = 1
to the top of the file.
Also, this code
For i = 0 To oApplication.CurrentDatabase.QueryDefs.Count - 1
oApplication.SaveAsText acQuery, _
oApplication.CurrentDatabase.QueryDefs(i).Name, _
sExportpath & "\" & db.QueryDefs(i).Name & ".sql"
Next i
did not work, but I believe that was intended for a .mdb anyway, not an .adp. Is there any solution for exporting StoredProcedures (and Views or Table definitions, while we're at it) to text files?
It probably doesn't have anything to do with mdb vs adp. When I try the following in an mdb, I get the same error message.
MsgBox Application.CurrentData.AllStoredProcedures.Count
I suspect that it is doing that because MS Access doesn't know the underlying structure of the SQL database is. And really, why should it care, and why would the DB tell your app what it looks like under the covers? The stored procedures run entirely on the DB side and knows nothing about the MS Access app, and the views are just that a view (or presentation of) the data. As far as I know, you can't manipulate either from within MS Access.
What I think you are trying to do is automate an export of the sql scripts necessary to recreate your database, and store them in some sort of version control system. The folks on Serverfault might have a convenient solution for that.
As for SaveAsText, unfortunately it is an undocumented method. I've used the following for exporting Queries
''...
Dim db As Database
Set db = CurrentDb()
Dim Qry As QueryDef
For Each Qry In db.QueryDefs
strObjectName = Qry.Name
If Not (strObjectName Like "~sq_*") Then
Debug.Print " - " & strObjectName
Application.SaveAsText acQuery, strObjectName, _
MY_PATH & "queries_" & strObjectName & ".txt"
End If
Next
''...
TableDef's were a little different (couldn't get SaveAsText/LoadAsText to work properly)
For Each Tbl In db.TableDefs
If Tbl.Attributes = 0 Then 'Ignores System Tables
strObjectName = Tbl.Name
Debug.Print " - " & strObjectName
Application.ExportXML acExportTable, strObjectName, , _
MY_PATH & "tables_" & strObjectName & ".xsd"
End If
Next
Related
I'm trying to get some information from a mysql database to a report in access. But I can't figure out how to get the information there since I'm using DAO connections in vba and cant use linked tables.
I've tried storing the information into a string from the form that I already have the information at through a DAO connection directly to mysql db with no luck.
Private Sub Command67_Click()
DoCmd.Save
DoCmd.GoToRecord , , acNewRec
Me.Label39.Visible = True
Dim strWhere As String
strWhere = "[ID] = " & Me.[Id]
DoCmd.OpenReport "MyReport", acViewPreview, , strWhere
End Sub
I use preview in that code to see some result but what I would like to do is print directly to the printer since this is a client turn receipt i need those to print fast.
Again I can't use linked tables.
After investigating on your former questions (some should be linked to that question), I see the problem. You don't link the MySQL-Tables what would make things easier for you.
But you can still use queries! Just put your connection string (maybeGlobales.ConnStringin former questions) in the queriesODBC Connection Stringin query design->properties. That makes the query a passthrough-query that is passed to MySQL-Server directly, not using MDAC.
Just set the reportsRecordSourceto the name of the query.
You can also build the query in VBA, but you can't use a temporary QueryDef("") as you can't set the Reports-Recordset, so use a non temp one.
Example (assumes there is a QueryDef named QueryForReport):
Sub EditQueryDefPassthrough()
With CurrentDb.QueryDefs("QueryForReport")
.Connect = "ODBC;Driver={MySQL ODBC 5.3 ANSI Driver};" _
& "Server=YourServerName;" _
& "Database=YourDatabaseName;" _
& "User=YourMysqlUserName;" _
& "Password=MysqlPwdForUser;" _
& "Option=3;" ' adapt this to your MySQL ODBC Driver Version and server settings
.SQL = "SELECT `Field` FROM `TABLE` LIMIT 1,1;" 'put SQL here (MySQL SQL Dialect, not MS-Access!). You can't use Access functions here (like Replace(), ..., but those of MySQL like Concat().
End With
End Sub
The QueryDef needs to be set before the Report_Load Event, but in Report_Open should be sufficent (e.g. if you want to use OpenArgs for building the SQL-String)
I'm running MS Access 2007, connecting to a MS SQL 2008 R2 server. I have a form with a multiselect box that I use to update status for several fields for the servers selected. Currently I'm using the ServerName field in the multiselect box. The problem is that there can be multiple records with the same server name. So to get around this I want to change it from ServerName to record number (ID). When I do this though VB gives the error "Error 3622 - You must use the dbSeeChanges option with OpenRecordset when accessing a SQL Server table that has an IDENTITY column". I've looked at many different posts on different websites, but can't figure out how to implement this into my code. The script works perfectly when I use ServerName, it also works perfectly if I go to the SQL server and change the field to Identity = False. The problem with that is that I can't create new records with the autonumber. It also works perfectly if I hard code the line numbers in an Update query. The problem with that is I can't hardcode the line numbers for everyone that uses the database. The issue only appears to be related to VB.
Below is what I have currently. As you can see I tried adding the dbSeeChanges to the Execute line.
Private Sub btnRoarsStatus_Click()
Dim strSQL As String
Dim Criteria As String
Dim Itm As Variant
With Me.lstServerNames
If .ItemsSelected.Count > 0 Then
For Each Itm In .ItemsSelected
Criteria = Criteria & "," & .ItemData(Itm)
Next Itm
' remove leading comma
Criteria = Mid(Criteria, 2)
' execute the SQL statement
strSQL = "UPDATE buildsheet SET [Roars Status] = " & Chr(34) & _
Me.cboRoarsStatus & Chr(34) & " WHERE ID IN(" & Criteria & ")"
Debug.Print strSQL
CurrentDb().Execute strSQL, dbSeeChanges
Else
MsgBox "You must select one or more items in the list box!", _
vbExclamation, "No Selection Made"
Exit Sub
End If
End With
MsgBox "Completed", vbExclamation, "Completed"
End Sub
I had a similar Problem with a Delete Statement that I wanted to execute and solved it by:
CurrentDb.Execute SqlStr, dbSeeChanges
note the missing () after CurrentDb
For me worked this:
CurrentDb.Execute strSQL, **dbFailOnError +** dbSeeChanges
dbFailOnError was the key...
CurrentDb().Execute strSQL, someotherConstant, dbSeeChanges
I think, someotherConstant maybe missing.
I have a form that contains multiple partners that share a "pool". The partners are listed on a subform. After I'm done entering the information, I want a button to run a report for each of the partners with their specific information. But since it's multiple partners and I need one report for each (which I then want to email), I want to use a Loop to go through each of the partners.
EDIT1: Added entire code for review. I do have Option Explicit in and I have compiled it as well.
Private Sub btn_Run_Click()
Dim db As DAO.Database
Dim rs As DAO.Recordset
Dim strSQL As String
strSQL = "Select * FROM Cobind_qryReport WHERE PartPoolName = """ & Me.TopLvlPoolName & """"
Debug.Print "strSQL: " & strSQL
Set db = CurrentDb
Set rs = db.OpenRecordset(strSQL)
On Error GoTo Err_PO_Click
If MsgBox("Do you wish to issue the cobind invites?", vbYesNo + vbQuestion, "Confirmation Required") = vbYes Then
rs.MoveFirst
Do While rs.EOF = False
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" _
& rs!CatCode & "_" & rs!PartPoolName "Cobind Invite_" & _
Format(Now(), "mmddyy") & ".pdf"
DoCmd.SendObject acSendReport, "Cobind_rptMain", acFormatPDF, ,_
, , " Cobind Invite", "Please find the cobind invite attached._
Response is needed by " & [RSVP] & ". Thank you.", True
rs.MoveNext
Loop
End If
Exit_PO_Click:
MsgBox ("It didn't work")
rs.Close
Set rs = Nothing
Set db = Nothing
Exit Sub
Err_PO_Click:
MsgBox Err.Description
Resume Exit_PO_Click
End Sub
This should allow me to create a report for each record in my query, save it to my server, then open an email to send it out. Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression." If I take out the [PartPoolName], it'll create a PDF with four pages (each page showing a partner), where I want to end up with four separate PDFs.
The first thing you should do is add Option Explicit to the Declarations section of your module.
Then, from the Visual Basic editor's main menu, select Debug->Compile [your project name here]
Fix all the problems the compiler complains about. I suspect one of the compiler's first complaints may be triggered by this section of your code:
rs.MoveFirst
Do While Recordset.EOF = False
Do you have two recordset objects open, or one?
After you fix everything the compiler complains about, try your revised code.
If you get runtime errors, show us the exact error message and which code line is highlighted.
If the part of your code you haven't shown us includes an error hander, you can disable that error handler like so:
'On Error GoTo Err_PO_Click
Error handlers are great for production to shield users from errors. However, during development you really need to be able to identify which code line causes the error.
Alternatively, you can leave your error handler active and select Tools->Options from the editor's main menu. In the Options dialog, select the General tab, then select the "Break on All Errors" radio button and click OK. You can switch that option back to "Break on Unhandled Errors" after you finish your testing.
Update: You wrote: Right now, it appears that the [PartPoolName] is hanging up the code because I'm getting a "Microsoft Office Access can't find the field "|" referred to in your expression."
What is [PartPoolName]? If it's a field in the recordset, you can reference its value as rs!PartPoolName If it's something else, perhaps a global variable, give us more information about it.
Update2: Whenever your current code completes without error, you will hit this:
Exit_PO_Click:
MsgBox ("It didn't work")
Can that be right?
Update3: This OutputTo statement is your issue now, right?
DoCmd.OutputTo acOutputReport, "Cobind_rptMain", acFormatPDF,_
"K:\OB MS Admin\Postage\CoBind Opportunities\Sent Invites\" & _
"Cobind Invite_" & Format(Now(), "mmddyy") & ".pdf"
Cobind_rptMain is a report. It has a RowSource for its data. You're calling OutputTo with that report 4 times (once for each of the 4 rows in the recordset). Yet you expect 4 different versions of that report ... a separate report for each PartPoolName value?
To finish off the fine work by HansUp visit a page on how to print a report for a single record and how to generate reports to attach to emails. See the Emailing reports as attachments from Microsoft Access page.
I have two different MDB files [with the same structure]. Is there an existing tool that can report the difference between the two files [row by row]?
I found a program called "MDBDiff" on SF, however the program is no longer available for download.
I've made an AccdbMerge utility that is able to compare data and programming objects as well. In scope of "row by row" comparison - it will show what records were added/modified/removed, for modified records it will highlight fields with updated values.
See the following page and go down a bit for a list of utilities to compare Access databases
http://www.granite.ab.ca/access/thirdparty.htm One of those might be what you're looking for.
I wanted to do the same (basically use DIFF to see differences row by row) so
1) I exported all the tables:
Option Explicit
Option Compare Database
Private Sub ExportAllTables()
Dim myDatabase As Database
Dim myTableDef As TableDef
Dim strTableName As String
Set myDatabase = CurrentDb
For Each myTableDef In myDatabase.TableDefs
DoEvents
strTableName = myTableDef.Name
DoCmd.TransferText _
acExportDelim, _
, _
strTableName, _
Environ("USERPROFILE") & "\DeskTop\dump\" & strTableName & ".CSV", _
True
Next myTableDef
MsgBox "Done"
End Sub
2) concatenated them into one file
type *.csv > all.txt
CAT will do as well if you have it
3) diff'ed them
diff all.txt all2.txt
Try using SQL Data Compare from Redgate, http://www.red-gate.com/products/SQL_Data_Compare/index.htm
and then use this trick,
http://www.red-gate.com/messageboard/viewtopic.php?p=15296#15296
I haven't tried it yet but this tool looks like it would do the job http://www.datanamic.com/download/download-datadiff-for-msaccess.html
During my work on this database application, I've apparently managed to corrupt a form in the application - attempting to save any edit to any field on the form will cause Access to crash, and for the database file to report corrupted when Access attempts to re-open it.
I've tried exporting the entire form + controls as text, then re-importing them using VB code (from Allen Browne's website) but it will not re-import without either crashing Access or telling me the form isn't import-able due to an error (no error number or description given).
The form is rather complex, hence I am hesitant to just remake it from scratch, so is there a way to save it? If I do manage to recover it, does this mean I should transfer everything to a new MDB file (in case it's a cascading failure effect)?
To be honest, I've never managed to corrupt an Access database object before, so I don't know if this is something that signals the end of that MDB file, or just something I can correct and continue as before.
Decompile is a good thing to try once you've made a copy of the database. Have you tried saving the form under a different name using File >> Save As? Also try copying and pasting the form with a different name from the database window.
Also it's been my experience that one corrupt form/report does not spread to the rest of the database. That said it doesn't hurt to clean things up. Compact and repair only fixes up tables and related data such as indexes and relationships. To clean up corrupted other objects such as forms and reports you must import them into a new MDB/ACCDB. Tip: Close the database container window if you have a lot of objects. Access wastes a lot of time during the import refreshing the database container window.
What I ended up having to do was re-create the form, and copy element by element until I discovered that the strSupplierID combo box itself was the cause of the crashing. I re-created it from scratch, manually giving it the same properties, and replacing the VB from stored copies I cut and pasted to the clipboard. The form now works, and I removed the corrupted form, and compacted the database. Thanks for the help, everyone! :)
Others have supplied you with various approaches to possibly recover your corrupted form. Sometimes an code-bearing Access object will become irretrievably corrupt and none of these methods will work. In that case, you'll have to look= at backups to find a non-corrupt version as a starting point and import that and then revise it back to the current state of the object.
I'm posting an answer to suggest that you probably need to change your coding practices if you're encountering corruption in code-bearing objects.
First, you need to make sure you keep regular backups and do not overwrite them. Rolling back to an earlier version is always a last resort.
Always turn off COMPILE ON DEMAND in the VBE options. Read Michael Kaplan's article on The Real Deal on the Decompile Switch for the explanation of why.
In the VBE, add the compile button (and the call stack button) to your regular VBE toolbar, and hit that compile button after every few lines of code, and save your code.
Decide on a reasonable interval to backup and decompile your app. If you're doing heavy-duty code pounding, you might want to do this every day. If you've experienced an Access crash during coding, you likely want to make your backup and decompile/recompile. Certainly before distributing to users, you should decompile and recompile your app.
If you follow these practices, the causes of corruption in code-bearing Access objects will be minimized as much as possible, while you will also have plenty of backups (multiple levels of redundant backups are a must, because when backup failures happen, they almost always cascade through multiple levels -- have several types of backup and don't depend on an automatic backup).
But the key point:
Compile often, decompile reasonably often and icky stuff will never have a chance to accumulate in the p-code of your application.
Have you looked at the full set of methods for dealing with corruption from Allen Browne: http://allenbrowne.com/ser-47.html ? In particular, decompile.
It may be worth try a copy and paste of the controls into a new form and gradually add back in the code.
I have had that happen to me many times. Here are a couple things that have saved my bacon. I am assuming you are using Access 2003 or higher. Try converting the database to Access 2002 or 2000 format. Then convert that database back to your current version.
Here is some code that I created to combat bloat in previous versions. It also solved this issue for me 95% of the time.
Option Compare Database
Option Explicit
Private Sub cmdCreateDuplicate_Click()
'********************************************************
' Author Daniel Tweddell
' Revision Date 10/27/05
'
' To Combat bloat, we are recreating the a new database
'********************************************************
On Error GoTo Err_Function
Dim strNewdb As String
Dim AppNewDb As New Access.Application 'the new database we're creating to manage the updates
strNewdb = CurrentProject.Path & "\db1.mdb"
SysCmd acSysCmdSetStatus, "Creating Database. . ."
With AppNewDb
DeleteFile strNewdb 'make sure it's not already there
.Visible = False 'hear no database see no database
.NewCurrentDatabase strNewdb 'open it
ChangeRemoteProperty "StartupShowDbWindow", AppNewDb, , dbBoolean, False
ChangeRemoteProperty "Auto compact", AppNewDb, , dbBoolean, True
ImportReferences AppNewDb, Application
.CloseCurrentDatabase
End With
Set AppNewDb = Nothing
Dim ao As AccessObject
For Each ao In CurrentData.AllTables
If Left(ao.Name, 4) <> "msys" Then
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acTable, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
End If
Next
For Each ao In CurrentData.AllQueries
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acQuery, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllForms
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acForm, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllReports
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acReport, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllMacros
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acMacro, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
For Each ao In CurrentProject.AllModules
DoCmd.TransferDatabase acExport, "Microsoft Access", strNewdb, acModule, ao.Name, ao.Name
SysCmd acSysCmdSetStatus, "Exporting " & ao.Name & ". . ."
Next
MsgBox "Creation Complete!" & vbCrLf & "Reset Password", vbExclamation, "New Database"
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, Me.Name & " cmdCreateDuplicate_Click()"
End Sub
Function DeleteFile(ByVal strPathAndFile As String) As Boolean
'***********************************************************************************
' Author Daniel Tweddell
' Revision Date 04/14/03
'
' Deletes a file
'***********************************************************************************
On Error GoTo Err_Function
DeleteFile = True 'default to true
If UncDir(strPathAndFile) <> "" Then 'make sure the file is there
Kill strPathAndFile 'delete a file
End If
Exit Function
Err_Function:
ErrHandler Err.Number, Err.Description, "DeleteFile()", bSilent
DeleteFile = False 'if there is a problem, false
End Function
Public Sub ChangeRemoteProperty(strPropName As String, _
appToDB As Access.Application, Optional appFromDB As Access.Application, _
Optional vPropType As Variant, Optional vPropValue As Variant)
'********************************************************************************
' Author Daniel Tweddell
' Revision Date 01/13/04
'
' Changes/adds a database property in one db to match another
'********************************************************************************
On Error GoTo Err_Function
Dim ToDB As DAO.Database
Dim FromDB As DAO.Database
Dim prpTest As DAO.Property
Dim bPropertyExists As Boolean
Set ToDB = appToDB.CurrentDb
If Not appFromDB Is Nothing Then Set FromDB = appFromDB.CurrentDb
bPropertyExists = False 'flag to see if we found the property
For Each prpTest In ToDB.Properties 'first see if the property exists so we don't error
If prpTest.Name = strPropName Then
If IsMissing(vPropValue) Then vPropValue = FromDB.Properties(strPropName) 'in case we want to assign it a specific value
ToDB.Properties(strPropName) = vPropValue 'if it does set it and get out or the loop
bPropertyExists = True
Exit For
End If
Next
If Not bPropertyExists Then ' Property not found.
Dim prpChange As DAO.Property
If IsMissing(vPropValue) Then
With FromDB.Properties(strPropName)
vPropValue = .Value 'in case we want to assign it a specific value
vPropType = .Type
End With
End If
Set prpChange = ToDB.CreateProperty(strPropName, vPropType, vPropValue) 'add it
ToDB.Properties.Append prpChange
End If
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, "ChangeRemoteProperty()", bSilent
End Sub
Public Sub ImportReferences(AppNewDb As Access.Application, appUpdateDB As Access.Application, Optional iStatus As Integer)
'********************************************************************************
' Author Daniel Tweddell
' Revision Date 01/13/04
'
' Copies the current references from the one database to another we're building
'********************************************************************************
On Error GoTo Err_Function
Dim rNewRef As Reference
Dim rUpdateRef As Reference
Dim bReferenceExists As Boolean
Dim rToAdd As Reference
Dim sReference As String
If iStatus <> 0 Then ProgressBarUpdate iStatus, "Referencing Visual Basic Libraries. . ."
For Each rUpdateRef In appUpdateDB.References
bReferenceExists = False
For Each rNewRef In AppNewDb.References
sReference = rNewRef.Name
If rUpdateRef.Name = sReference Then
bReferenceExists = True
Exit For
End If
Next
If Not bReferenceExists Then
With rUpdateRef
Set rToAdd = AppNewDb.References.AddFromGuid(.Guid, .Major, .Minor)
End With
End If
Next
Exit Sub
Err_Function:
ErrHandler Err.Number, Err.Description, "ImportReferences(" & sReference & ")", bSilent
Resume Next
End Sub
I have found that combo boxes with 10 or more columns can cause an Access form to corrupt. Try reducing the number of the columns or removing that combo box to see if the form saves properly. This problem is was related to working in Win 7 64 bit operating system with Access 2003 databases. There was no problem when developing in XP in other words the forms save fine with large column counts in combo boxes. Hope this information helps since it caused a lot of wasted time thinking the database was corrupted.