Concurrent access to data

C

count

Hi,
I have a working Excel 2000 app, where users see and manipulate data through
forms rather than worksheets.

Can you recommend a method of making this app available to more then 1 user
simultaneously?

I was thinking of making my app an add-in and storing all data in some
workbook aside - not sure however how to do it.

Thanks in advance
Paul
 
D

Dave Peterson

I'm not an Access user, but from the posts I've read, it sounds like you should
use a real database that support simultaneous users.

Excel does have a method to share a workbook, Tools|share, but there are lots of
things you can't do with a shared workbook.
 
C

count

Hi Dave,
You are right with real database solution - I'm trying to avoid introducing
Access because it requires Pro version of Office ($$$ :)
So my thought went along the lines of using ODBC mechanism or maybe
"home-made" record locking - maybe someone already been there and explored
all the traps awaiting...
Thanks for input
Paul
 
J

Jamie Collins

count said:
I'm trying to avoid introducing
Access because it requires Pro version of Office ($$$ :)

MS Access isn't a database. Rather, it is a database management
system. If money is an issue and you know what you are doing you can
create and maintain Jet databases, .mdb files using ADO. I'm told that
the .mdb format can be freely distributed too.

Here's some sample code to try in a new/blank workbook. It creates a
Jet database and some sample data, then queries it, all using ADO in
Excel. Try in on a machine without MS Access <g>

Sub Test()

Dim Cat As Object
Dim Con As Object
Dim rs As Object
Dim strConJet As String
Dim strSql1 As String
Dim strSql2 As String
Dim strSql3 As String
Dim oTarget As Excel.Range
Dim lngCounter As Long

' Amend the following constants to suit
Const FILENAME_JET As String = "" & _
"New_Jet_DB99.mdb"

Const CONN_STRING_JET As String = "" & _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=<PATH><FILENAME>"

' Build connection string
strConJet = CONN_STRING_JET
strConJet = Replace(strConJet, "<PATH>", _
ThisWorkbook.PATH & Excel.Application.PathSeparator)
strConJet = Replace(strConJet, "<FILENAME>", FILENAME_JET)

' Build sql statements
strSql1 = ""
strSql1 = strSql1 & "CREATE TABLE CommsUsers ("
strSql1 = strSql1 & " ID INTEGER NOT NULL PRIMARY KEY,"
strSql1 = strSql1 & " lname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " fname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " mname VARCHAR(35) NOT NULL"
strSql1 = strSql1 & " DEFAULT '{{NA}}'"
strSql1 = strSql1 & ");"

strSql2 = ""
strSql2 = strSql2 & "CREATE TABLE Phones ("
strSql2 = strSql2 & " ID INTEGER NOT NULL"
strSql2 = strSql2 & " REFERENCES CommsUsers (ID),"
strSql2 = strSql2 & " Phone VARCHAR(15) NOT NULL"
strSql2 = strSql2 & ");"

strSql3 = ""
strSql3 = strSql3 & "SELECT cm.ID, cm.lname,"
strSql3 = strSql3 & " cm.fname, ph.Phone"
strSql3 = strSql3 & " FROM CommsUsers cm"
strSql3 = strSql3 & " LEFT JOIN Phones ph"
strSql3 = strSql3 & " ON cm.ID=ph.ID;"

' Create new Jet database
Set Cat = CreateObject("ADOX.Catalog")
Cat.CREATE strConJet

' 'inherit' the connection
Set Con = Cat.ActiveConnection
Set Cat = Nothing

With Con

' Create tables
.Execute strSql1
.Execute strSql2

' Create some sample data
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (1, 'Livehulas', 'A')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (2, 'Katewudes', 'B')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (3, 'Hevitoxic', 'C')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (4, 'Norarules', 'D')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '123')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '456')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '555')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '444')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (4, '789')"
End With

' Open recordset
Set rs = Con.Execute(strSql3)

' Copy data to ThisWorkbook
Set oTarget = ThisWorkbook.Worksheets(1) _
.Range("A1")

With rs
For lngCounter = 1 To .fields.Count
oTarget(1, lngCounter).Value = _
.fields(lngCounter - 1).Name
Next
End With

oTarget(2, 1).CopyFromRecordset rs

Con.Close

End Sub


Jamie.

--
 
A

Amedee Van Gasse

count schreef in said:
Hi Dave,
You are right with real database solution - I'm trying to avoid
introducing Access because it requires Pro version of Office ($$$ :)
So my thought went along the lines of using ODBC mechanism or maybe
"home-made" record locking - maybe someone already been there and
explored all the traps awaiting...

You could also explore some of the "Open Source" databases like MySQL. This
has /a lot/ of support in the Linux world, but good news for you: MySQL
also runs on Windows (I know, I have done so for more than a year).
And another good all these databases speak "SQL" (Structured Query
Language), a common database language they all understand.
It should be possible, using ODBC/DAO/ADO (I always forget the right name),
to tell Excel to get data from a MySQL data source.

--
Amedee Van Gasse
http://www.amedee.be

To top-post is human, to bottom-post and snip is sublime.

Dit bericht is geplaatst in een nieuwsgroep. Post je evt antwoord of
vervolgvraag graag in dezelfde thread in de nieuwsgroep a.u.b.
 
C

count

Jamie - you're a champ!
And you will become A Hero of the Year if you tell me these three more
things...:)
1. True/False: MS Access can be used to meticulously construct MyBase.mdb
initially
2. You have a sample code to demonstrate syntax for Updating and Deleting
records...
3. How to ask for help with Jet and concurrent access - is there an issue at
all?

Can't wait to see your answer!
Regards, Paul
 
J

Jamie Collins

...
1. True/False: MS Access can be used to meticulously construct MyBase.mdb
initially

True. That is one of its key features. However, I thought the point
was you don't have MS Access. The same is true for ADO. The code I
posted creates an .mdb file i.e.

' Create new Jet database
Set Cat = CreateObject("ADOX.Catalog")
Cat.CREATE strConJet

But what you mean by 'myBase'? Just change the name in the sample
connection string. And what do you mean by meticulously in this
context? You can use DDL in ADO to create and maintain tables,
constraints, indexes, user accounts, etc. There are some things that
can be achieved using ADO that can't be done in the MS Access UI e.g.
specifying DEFAULT in a CREATE TABLE statement, the CHECK..SELECT
style of constraint, etc. For further details see the following
articles:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnacc2k/html/acintsql.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnacc2k/html/acadvsql.asp
2. You have a sample code to demonstrate syntax for Updating and Deleting
records

Here's some very similar code that includes UPDATE and DELETE syntax:

Option Explicit

Sub Test2()

Dim Cat As Object
Dim Con As Object
Dim rs As Object
Dim strConJet As String
Dim strSql1 As String
Dim strSql2 As String
Dim strSql3 As String
Dim oTarget As Excel.Range
Dim lngCounter As Long

' Amend the following constants to suit
Const FILENAME_JET As String = "" & _
"New_Jet_DB88.mdb"

Const CONN_STRING_JET As String = "" & _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=<PATH><FILENAME>"

' Build connection string
strConJet = CONN_STRING_JET
strConJet = Replace(strConJet, "<PATH>", _
ThisWorkbook.Path & Excel.Application.PathSeparator)
strConJet = Replace(strConJet, "<FILENAME>", FILENAME_JET)

' Build sql statements
strSql1 = ""
strSql1 = strSql1 & "CREATE TABLE CommsUsers ("
strSql1 = strSql1 & " ID INTEGER NOT NULL PRIMARY KEY,"
strSql1 = strSql1 & " lname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " fname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " mname VARCHAR(35) NOT NULL"
strSql1 = strSql1 & " DEFAULT '{{NA}}'"
strSql1 = strSql1 & ");"

strSql2 = ""
strSql2 = strSql2 & "CREATE TABLE Phones ("
strSql2 = strSql2 & " ID INTEGER NOT NULL"
strSql2 = strSql2 & " REFERENCES CommsUsers (ID),"
strSql2 = strSql2 & " Phone VARCHAR(15) NOT NULL"
strSql2 = strSql2 & ");"

strSql3 = ""
strSql3 = strSql3 & "SELECT cm.ID, cm.lname,"
strSql3 = strSql3 & " cm.fname, ph.Phone"
strSql3 = strSql3 & " FROM CommsUsers cm"
strSql3 = strSql3 & " LEFT JOIN Phones ph"
strSql3 = strSql3 & " ON cm.ID=ph.ID;"

' Create new Jet database
Set Cat = CreateObject("ADOX.Catalog")
Cat.CREATE strConJet

' 'inherit' the connection
Set Con = Cat.ActiveConnection
Set Cat = Nothing

With Con

' Create tables
.Execute strSql1
.Execute strSql2

' Create some sample data
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (1, 'Livehulas', 'A')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (2, 'Katewudes', 'B')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (3, 'Hevitoxic', 'C')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (4, 'Norarules', 'D')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '123')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '456')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '555')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '444')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (4, '789')"


' Update syntax
.Execute "UPDATE CommsUsers SET lname = 'Luxasonic'" & _
" WHERE ID=1"


' UPDATE syntax
.Execute "DELETE FROM Phones WHERE ID=4"


End With

' Open recordset
Set rs = Con.Execute(strSql3)

' Copy data to ThisWorkbook
Set oTarget = ThisWorkbook.Worksheets(1) _
.Range("A1")

With rs
For lngCounter = 1 To .fields.Count
oTarget(1, lngCounter).Value = _
.fields(lngCounter - 1).Name
Next
End With

oTarget(2, 1).CopyFromRecordset rs

Con.Close

End Sub
3. How to ask for help with Jet and concurrent access - is there an issue at
all?

In this ng, of course! Perhaps there is a more appropriately titled
one (e.g. microsoft.public.data.ado) but this one is better
subscribed. For example, see this recent thread:

http://groups.google.com/[email protected]

You may have some luck in the MS Access newsgroups but IMO the
regulars there have trouble differentiating between MS Access and Jet
i.e. it's difficult to get a pure Jet perspective there.

Jamie.

--
 
C

count

Jamie,
Thanks for your excellent, high quality answers - you have cut my
development time by factor of 10!

Uzytkownik "Jamie Collins said:
...


True. That is one of its key features. However, I thought the point
was you don't have MS Access. The same is true for ADO. The code I
posted creates an .mdb file i.e.

' Create new Jet database
Set Cat = CreateObject("ADOX.Catalog")
Cat.CREATE strConJet

MS Access: I have it but didn't want to impose it on users
But what you mean by 'myBase'? Just change the name in the sample
connection string. And what do you mean by meticulously in this
context? You can use DDL in ADO to create and maintain tables,
constraints, indexes, user accounts, etc. There are some things that
can be achieved using ADO that can't be done in the MS Access UI e.g.
specifying DEFAULT in a CREATE TABLE statement, the CHECK..SELECT
style of constraint, etc. For further details see the following
articles:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnacc2k/html/acintsql.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnacc2k/html/acadvsql.asp

I am familiar with Access and I thought I could use it to carefully design
tables, their fields and links with the help of its graphical presentation.
Command line creation appeared crude at first but thanks to you I will
probably start using and liking it.

Just as a piece of my contribution: I saw a thread in
microsoft.public.data.odbc where Claude Schneegans asks and Dmitri Ivanov
questions an issue with DEFAULT. Sorry I don't know how to paste posting
reference here (and if this info really applies - but I urgently need to
reciprocate :)
Here's some very similar code that includes UPDATE and DELETE syntax:

Option Explicit

Sub Test2()

Dim Cat As Object
Dim Con As Object
Dim rs As Object
Dim strConJet As String
Dim strSql1 As String
Dim strSql2 As String
Dim strSql3 As String
Dim oTarget As Excel.Range
Dim lngCounter As Long

' Amend the following constants to suit
Const FILENAME_JET As String = "" & _
"New_Jet_DB88.mdb"

Const CONN_STRING_JET As String = "" & _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=<PATH><FILENAME>"

' Build connection string
strConJet = CONN_STRING_JET
strConJet = Replace(strConJet, "<PATH>", _
ThisWorkbook.Path & Excel.Application.PathSeparator)
strConJet = Replace(strConJet, "<FILENAME>", FILENAME_JET)

' Build sql statements
strSql1 = ""
strSql1 = strSql1 & "CREATE TABLE CommsUsers ("
strSql1 = strSql1 & " ID INTEGER NOT NULL PRIMARY KEY,"
strSql1 = strSql1 & " lname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " fname VARCHAR(35) NOT NULL,"
strSql1 = strSql1 & " mname VARCHAR(35) NOT NULL"
strSql1 = strSql1 & " DEFAULT '{{NA}}'"
strSql1 = strSql1 & ");"

strSql2 = ""
strSql2 = strSql2 & "CREATE TABLE Phones ("
strSql2 = strSql2 & " ID INTEGER NOT NULL"
strSql2 = strSql2 & " REFERENCES CommsUsers (ID),"
strSql2 = strSql2 & " Phone VARCHAR(15) NOT NULL"
strSql2 = strSql2 & ");"

strSql3 = ""
strSql3 = strSql3 & "SELECT cm.ID, cm.lname,"
strSql3 = strSql3 & " cm.fname, ph.Phone"
strSql3 = strSql3 & " FROM CommsUsers cm"
strSql3 = strSql3 & " LEFT JOIN Phones ph"
strSql3 = strSql3 & " ON cm.ID=ph.ID;"

' Create new Jet database
Set Cat = CreateObject("ADOX.Catalog")
Cat.CREATE strConJet

' 'inherit' the connection
Set Con = Cat.ActiveConnection
Set Cat = Nothing

With Con

' Create tables
.Execute strSql1
.Execute strSql2

' Create some sample data
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (1, 'Livehulas', 'A')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (2, 'Katewudes', 'B')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (3, 'Hevitoxic', 'C')"
.Execute "INSERT INTO CommsUsers (ID, lname, fname)" & _
" VALUES (4, 'Norarules', 'D')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '123')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (1, '456')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '555')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (2, '444')"
.Execute "INSERT INTO Phones (ID, Phone)" & _
" VALUES (4, '789')"


' Update syntax
.Execute "UPDATE CommsUsers SET lname = 'Luxasonic'" & _
" WHERE ID=1"


' UPDATE syntax
.Execute "DELETE FROM Phones WHERE ID=4"


End With

' Open recordset
Set rs = Con.Execute(strSql3)

' Copy data to ThisWorkbook
Set oTarget = ThisWorkbook.Worksheets(1) _
.Range("A1")

With rs
For lngCounter = 1 To .fields.Count
oTarget(1, lngCounter).Value = _
.fields(lngCounter - 1).Name
Next
End With

oTarget(2, 1).CopyFromRecordset rs

Con.Close

End Sub


In this ng, of course! Perhaps there is a more appropriately titled
one (e.g. microsoft.public.data.ado) but this one is better
subscribed. For example, see this recent thread:

http://groups.google.com/[email protected]

You may have some luck in the MS Access newsgroups but IMO the
regulars there have trouble differentiating between MS Access and Jet
i.e. it's difficult to get a pure Jet perspective there.

Jamie.

--

Jamie, thanks again for your help - you are a Hero! - as promised :)
Regards, Paul
 
Top