>Thank you very much for your quick response. I’ll try to do a better job of explaining my current situation.
>
>I started with a VFP 6.0 database on one computer being merged to several different Word 97 documents either through MSQuery or Excel through MSQuery (if there were a lot of fields being merged). I found it to be very slow merging through Excel and then into Word in order to accommodate the restriction of the 255 SQL character limitation using MSQuery. However, I was able to deal with that as I was the only one using the computer.
>
>Now, I have a VFP 6.0 database that is shared over two computers in a client/server network (really a peer to peer network, but the database is only on the host computer which I was working on). I was unable to figure out how to merge a document over the network (ie the client has the Word document, and the Server has the VFP database). I contacted Microsoft, and they talked me through one solution. They said I could have the same copy of the database on both computers. When, in a form, someone clicks the save button in order to add values to a table, the save button updates both the table on the server, and the table on the client. The client copy of the database and the server copy of the database will therefore always be identical, and the merged documents will merge to the database on the local computer. As you can imagine, making changes and saving to two computers can become slow, but at the time, it did accomplish my objective.
>
>Now, the speed is starting to become an issue. In order to do a workaround, I created a program that selects the data to be merged into a free table. Foxpro is able to merge into a free table without needing MSQuery, and there are no limits (as far as I know) on the number of characters in the SQL statement. In order to have the free table updated whenever changes are made to the original database, I run the program every time a change is made to the dababase information (I issue a “do program” statement in the “save” button of a form). Therefore, the free table is always up to date. The only problem with this solution is that once one person (say the client) updates the free table, the other person (the server) cannot update the free table since utilizing the “select into table” command causes the other computer to get a “file in use” error.
>
>I am not sure if this is clear, but I am not a “great” programmer. As of three years ago, I did not even know what a database is! However, I have learned a lot and enjoy learning and fixing problems with my programs. This is a problem that I have had for over a year and have not been able to solve. Unfortunately, I am not sure what you are referring to with your "Sys" command to change the name of the free table. I am not sure if it applies based on my current situation which I hope I clarified a bit better above. The 255 character limit is the SQL limit, and I have never been able to figure out how to utilize the SQL and SQL1 statements (ie how to combine them into one statement - do you use the first SQL statement to select into a cursor and then use the SQL1 statement to select * from the cursor along with additional fields from the database?)
>
>I would really appreciate either a solution to the “file in use” problem (ie being able to run the “select into table” program on different computers concurrently without getting this error), or an alternative to MSQuery. Thank you very much for your help.
>
>Paul
Paul,
I'm not sure about the solution MS provided. Sounds a bit strange way of doing it but anyways if it's working as you want no problem.
For merge source there are 2 SQL strings. With 2 strings actually all you do is to split and put first 255 chars into first and rest into second. ie:
lcOriginalSQL = 'select .... from ...' && Assume would be over 255 in length
lcSQL1 = left( lcOriginalSQL, 255 ) && First 255 chars
lcSQL2 = substr( lcOriginalSQL, 256 ) && Rest
However what I do is to create the free table with my SQL in VFP therefore free from the limits (limits exist in VFP too but at least I couldn't hit those limits yet). Then for word source I simply use an SQL like :
select * from MyAlreadyVFPSQLedTable
IOW I do real SQL on VFP with all joins, fields, filters etc. and then on word select all from that free table. VFP being much faster on SQL then word with ODBC the result is fast (or even faster than doing only with ODBC).
Check downloads for a 'Mail merge with word' class. I wrote that years ago, before MDAC 2.1 came out. With MDAC 2.1 release drivers needed were dropped but it should still be working (or you might change DSN setting there with the one below).
The solution with sys(2015) creates unique free tables per user. ie:
lcFreeTableName = "F"+Sys(2015)
Select * From employee ;
where Title = 'Sales' ;
into Table (lcFreeTableName)
cDataSource = Dbf(Alias())
cDSN = "DSN=Visual Foxpro Tables;DBQ="+Sys(5)+Curdir()+;
";DefaultDir="+Sys(5)+Curdir()+";"+;
"SourceDB="+lcDefDir+";SourceType=DBF;"
cSQLStatement = "SELECT * FROM "+lcFreeTableName+".dbf"
USE
#Define wdSendToEmail 2
#Define wdSendToFax 3
#Define wdSendToNewDocument 0
#Define wdSendToPrinter 1
#Define wdDoNotSaveChanges 0
#Define wdSaveChanges -1
nlLocaleId=Sys(3004)
=Sys(3006,1033)
Wait Window Nowait "Creating Word Document..."
Local llToPrinter
oWordDocument=Createobject("word.application")
With oWordDocument
.Documents.Add(Sys(5)+Curdir()+'mytemplate.dot')
With .ActiveDocument.MailMerge
.OpenDataSource(,,,,,,,,,,,cDSN, cSQLStatement)
If llToPrinter
.Application.Options.PrintBackGround = .T.
.Destination = wdSendToPrinter
Else
.Destination = wdSendToNewDocument
Endif
.Execute
Endwith
Wait Clear
.Visible = !llToPrinter
Endwith
If llToPrinter
oWatcher = Createobject('myTimer')
Else
oWatcher = Createobject('myTimer2')
Endif
Read Events
Messagebox('Word finished')
? cDataSource
Erase (cDataSource)
=Sys(3006,Val(nlLocaleId))
Define Class myTimer As Timer
Interval = 1000
Procedure Timer
With oWordDocument
If .BackgroundPrintingStatus > 0
Return
Endif
For Each oDoc In .Documents
oDoc.Close(wdDoNotSaveChanges)
Endfor
oDoc = .Null.
.Quit(wdDoNotSaveChanges)
Endwith
This.Enabled = .F.
Clear Events
Endproc
Enddefine
Define Class myTimer2 As Timer
Interval = 1000
Procedure Timer
If Type('oWordDocument.Documents') = 'O' And ;
oWordDocument.Documents.Count > 0
Return
Endif
This.Enabled = .F.
Clear Events
Endproc
Enddefine
PS: Actually in a multiuser environment sys(2015) value might be duplicated. But chances are very low with a task like this and additionally using local directory (sys(5)+curdir()) to create the table the chance is eliminated. I assume exe file is on each user's local folder (which should be for performance reasons if nothing else).
Cetin