Remove indexes programmatically by field name

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

Situation: application under development, being tested by two separate
clients; have had to create/delete/modify relationships & indexes
occasionally.

Current project: need to standardize indexes between these clients as I
prepare to distribute the application to others.

What I need to do: remove all indexes & relations, and replace them with a
standard index/relation set.

Complication: I am not certian that I have the exact same index/relation
names on both copies of the BE.

I know how to add/remove indexes & relationships programmatically by
index/relation name. I also know that I can simply loop through the queries &
relations collections and delete them all, then recreate them all. However, I
do not necessarily want to clear all of them, but just the particular one
involved in an update I am applying.

Is there a way to reference indexes and/or relations by table/field name
for deletion?
 
Brian said:
Situation: application under development, being tested by two separate
clients; have had to create/delete/modify relationships & indexes
occasionally.

Current project: need to standardize indexes between these clients as I
prepare to distribute the application to others.

What I need to do: remove all indexes & relations, and replace them with a
standard index/relation set.

Complication: I am not certian that I have the exact same index/relation
names on both copies of the BE.

I know how to add/remove indexes & relationships programmatically by
index/relation name. I also know that I can simply loop through the queries &
relations collections and delete them all, then recreate them all. However, I
do not necessarily want to clear all of them, but just the particular one
involved in an update I am applying.

Is there a way to reference indexes and/or relations by table/field name
for deletion?


You can certainly refer to a TableDef's Indexes collection,
but not by field name. You need to use the index's name:

Set db = CurrentDb()
Set tdf = db.TableDefs!tableanme
tdf.Indexes.Delete "indexname"

An index has a Fields collection that you can use to see if
a field is used in the index.

Similarly, you have to refer to a relation using the
relation's name, not a table name.

db.Relations.Delete "Relationname"

If necessary, you can check a relation's Table and
ForeignTable properties to check if a table is involved in
the relation.
 
The index & relation names are the way I am doing it now, but that assumes
that when I simply did a manual (drag-and-drop) relationship to the same
fields in two different BE's at different times, that it gave it the same
name to both.

Let me give you a simple example: I have a PK/FK relation between fields in
two tables. At some point early in development, I needed to change the field
size on one side. This, of course, required deleting the relation, changing
the field size on both sides, then re-creating the relation.

I did this manually on each of the two client BE's, because it wasn't worth
writing a patch at the time. Now I need to change that relation from
CascadeUpdate to CascadeDelete, but I am working towards issuing these
changes as patches instead of doing the work manually (I hope the reason is
obvious - this is a work in progress, and as I get more clients using this
application while it is still under development, I will constantly be needing
access to their BE's to update them manually).

I know that Access uses a standard naming convention for manually-created
(i.e. not programmatically-created) indexes & relations, but I don't want to
leave anything to inference when modifying table/relation/index structures
for my clients. Furthermore, I very often have to remove & re-create
relations within my development environment, and that is the one I would
likely use as a model for the index name & relation name when creating
patches.

If, for any reason, the relation got named differently in either live BE or
my development BE when I re-created it after the field size change, then I
will not be able to refer to the relation by name.

I am assuming, from what you said, that I can search through the relations
collection until I find one whose Table & ForeignTable properties match the
one I want, and then delete it so that I can re-create it with a standard
name.

Of course, much of the above also applies to the Indexes collection. I can
look through the list of properties to find the answer to this question, but
perhaps you already know: is there a FieldName property for an element of the
Indexes collection so that I can identify the Index if I know the field but
cannot guarantee the Index name?

Would it just be better to send out one massive patch now that loops through
the Relations and Indexes collections, deleting each one until there are no
more, and then creates them all with the names I have put into the patch?

My concern here is that as I distribute BE's to future clients while my
applications are still under development, the name of some index or relation
may end up different from the cognate one in another client's BE, and then
how do I programmatically modify a property of an index or relation via a
common patch sent to all clients?

Or, what if I indexed a field manually for one client but forgot to do it
for the other one? If I don't realize that I did it for the first one and
send out a patch to create te index, it will generate an error for the first
client because the index already exists.

I never gave a thought to all this version control stuff when I started
working with Access... sorry about the length of the post - perhaps I just
need some instruction on best practices in managing the underlying structures
in an envirnoment where I am distributing patches to multiple clients.
 
The "Fields" property of a DAO index object is actually a string.
You have to parse the string to get the individual fields.

I don't know what you get in ADOX.

(david)
 
Thanks, David.

So, I now have tried this (I left out all the Dim's to shorten the example):

tblName = "TableName"
fldName = "FieldName"
dbPath = "C:\Database.mdb"
Set dbName = DBEngine.Workspaces(0).OpenDatabase(dbPath, True)
Set tdf = dbName .TableDefs(tblName)
idxCount = tdf.Indexes.Count
For idxCurr = 0 To idxCount - 1
idxName = tdf.Indexes(idxCurr).Name
fldName2 = tdf.Indexes(idxCurr).Fields
MsgBox idxName & ": " & fldName2
Next idxCurr

I will just change the MsgBox to an If InStr to see if fldName is found in
fldName2.

The one thing I discovered is that when I loop through this way, the Fields
property always includes the index name preceded by a "+". Will this be
absolutely consistent?

Also - any comments on the initial concern? Is Access absolutely consistent
in its index-naming and relation-naming scheme? That is, can I always infer
the relation name from the table names and the index name from the field
name. (I'm sure some testing would show this one way or the other, but I'm
just trying to save some time by posting here.)

How might others approach the issue of BE-side patch distribution during
beta testing where table/index/relation structures may need to be altered for
multiple BE's?
 
You can ***not*** rely on any consistency in automatically
created names!

Be careful of the Fields property. If used by itself, it is
a somewhat unusual string. If used as a collection, it
behaves as you would expect.

I agree that it may be cumbersome, but to do what you want
for a table's Indexes, search through the Fields collection
of each Index for the specific field names. Once you've
identified the proper index, you can do other things with it
(e.g. delete method, name property, etc).

The same kind of approach can be used for relations, except
for the serious complication that when you create a
relation, Access automatically creates a hidden index for
the foreign key in the many side table (even if it
duplicates a manually created index). You can not delete
these internally created indexes unless you delete the
relation. These internal indexes are members of the table's
Indexes collection and you will stumble over them while
iterating through the indexes collection even though they do
not appear in the table's design view index window.
Although I have no proof, I think the internally created
indexes can be identified because their Foreign property is
is set to True.

Obviously, after all this discussion, it behooves you to
never again fiddle with a deployed back end database's
structure. It requires very deliberate thought and a
deployment strategy before a change should be made.
 
Thanks, Marshall. My assumption that I could not rely on auto-naming
consistency is what got this whole thread started.

I tihnk the method I described in my reply to David is more-or-less what you
are suggesting.

The thought behind your last comment has been well-etched into my mind in
this process. This is my first excursion into a multi-client application, and
it ended up being developed live for both. Now I have others asking for it,
and the thought of ensuring consistency of the invisible elements of the BE
are coming sharply into focus for me. It is one thing to ensure that all
clients get the same field names; it is quite another to ensure the same
index/relation names if I am manually (drag-and-drop) creating relations.

Would it make sense to you that I should proceed as follows?

1. Ensure that the two existing clients' BE's and my development BE are
identical in index/relation naming (I have ensured at each step that the
table structures are functionally identical, but not the relation/index
names). To do so, the safest thing might be to write a patch that removes all
indexes/relations and re-creates them by name.

2. Do any future BE changes via a distributed patch instead of manually. For
example if I add a new table to the BE (it is, after all, still under
development) that requires relations to existing tables, create a patch that
copies the new table and creates the relation programmaticlly.

As I noted before, I never really anticipated having to deal with version
control issues.. Am I missing anything fundamental here?

Marshall Barton said:
You can ***not*** rely on any consistency in automatically
created names!

Be careful of the Fields property. If used by itself, it is
a somewhat unusual string. If used as a collection, it
behaves as you would expect.

I agree that it may be cumbersome, but to do what you want
for a table's Indexes, search through the Fields collection
of each Index for the specific field names. Once you've
identified the proper index, you can do other things with it
(e.g. delete method, name property, etc).

The same kind of approach can be used for relations, except
for the serious complication that when you create a
relation, Access automatically creates a hidden index for
the foreign key in the many side table (even if it
duplicates a manually created index). You can not delete
these internally created indexes unless you delete the
relation. These internal indexes are members of the table's
Indexes collection and you will stumble over them while
iterating through the indexes collection even though they do
not appear in the table's design view index window.
Although I have no proof, I think the internally created
indexes can be identified because their Foreign property is
is set to True.

Obviously, after all this discussion, it behooves you to
never again fiddle with a deployed back end database's
structure. It requires very deliberate thought and a
deployment strategy before a change should be made.
--
Marsh
MVP [MS Access]



The index & relation names are the way I am doing it now, but that assumes
that when I simply did a manual (drag-and-drop) relationship to the same
fields in two different BE's at different times, that it gave it the same
name to both.

Let me give you a simple example: I have a PK/FK relation between fields in
two tables. At some point early in development, I needed to change the field
size on one side. This, of course, required deleting the relation, changing
the field size on both sides, then re-creating the relation.

I did this manually on each of the two client BE's, because it wasn't worth
writing a patch at the time. Now I need to change that relation from
CascadeUpdate to CascadeDelete, but I am working towards issuing these
changes as patches instead of doing the work manually (I hope the reason is
obvious - this is a work in progress, and as I get more clients using this
application while it is still under development, I will constantly be needing
access to their BE's to update them manually).

I know that Access uses a standard naming convention for manually-created
(i.e. not programmatically-created) indexes & relations, but I don't want to
leave anything to inference when modifying table/relation/index structures
for my clients. Furthermore, I very often have to remove & re-create
relations within my development environment, and that is the one I would
likely use as a model for the index name & relation name when creating
patches.

If, for any reason, the relation got named differently in either live BE or
my development BE when I re-created it after the field size change, then I
will not be able to refer to the relation by name.

I am assuming, from what you said, that I can search through the relations
collection until I find one whose Table & ForeignTable properties match the
one I want, and then delete it so that I can re-create it with a standard
name.

Of course, much of the above also applies to the Indexes collection. I can
look through the list of properties to find the answer to this question, but
perhaps you already know: is there a FieldName property for an element of the
Indexes collection so that I can identify the Index if I know the field but
cannot guarantee the Index name?

Would it just be better to send out one massive patch now that loops through
the Relations and Indexes collections, deleting each one until there are no
more, and then creates them all with the names I have put into the patch?

My concern here is that as I distribute BE's to future clients while my
applications are still under development, the name of some index or relation
may end up different from the cognate one in another client's BE, and then
how do I programmatically modify a property of an index or relation via a
common patch sent to all clients?

Or, what if I indexed a field manually for one client but forgot to do it
for the other one? If I don't realize that I did it for the first one and
send out a patch to create te index, it will generate an error for the first
client because the index already exists.

I never gave a thought to all this version control stuff when I started
working with Access... sorry about the length of the post - perhaps I just
need some instruction on best practices in managing the underlying structures
in an envirnoment where I am distributing patches to multiple clients.
 
Indexes can be named anything. In particular, if
you change the name of a field, the name of any attached
index does NOT change. You may find that idxRecord has
an index called idxType, while the index on idxType is
called idxRecord...

Relationships can be named anything. In particular,
if you import a relationship, as someone might do
because they are a manager with pretensions to technical
knowledge and "it is a good idea to import everything
into a new database", then all of your relationships
are renamed with GUID's.

Index fields are + if they are ascending, - for descending.
AFIAK, undocumented, and I would be careful in case there
are any other special cases.

(david)
 
Be careful of the Fields property. If used by itself, it is
a somewhat unusual string. If used as a collection, it

Everything I've said here is based only on my personal
experience with Jet 3.51 in year 2000. At that time
I couldn't get a fields collection - the indexfields
type was a string, not a collection.

I would use a fields collection by preference.

(david)
 
David,

I think there was something funny going on with your A2K
experience. There was enough funny things in A2K so this
may have been just one more in a long list.

Give this kind of thing a try:

For Each idx In tdf.Indexes
Debug.Print idx.Name
Debug.PrintSpc(3); idx.Fields
For Each fld In idx.Fields
Debug.Print Spc(6); fld.Name
Next fld
For k = 0 To idx.Fields.Count - 1
Debug.Print Spc(9); idx.Fields(k).Name
Next k
Next idx

and you should see that, at least in my experience with A97,
AXP and A03, the Fields property behaves as both a string
and a collection.
 
Brian said:
Thanks, Marshall. My assumption that I could not rely on auto-naming
consistency is what got this whole thread started.

I tihnk the method I described in my reply to David is more-or-less what you
are suggesting.

The thought behind your last comment has been well-etched into my mind in
this process. This is my first excursion into a multi-client application, and
it ended up being developed live for both. Now I have others asking for it,
and the thought of ensuring consistency of the invisible elements of the BE
are coming sharply into focus for me. It is one thing to ensure that all
clients get the same field names; it is quite another to ensure the same
index/relation names if I am manually (drag-and-drop) creating relations.

Would it make sense to you that I should proceed as follows?

1. Ensure that the two existing clients' BE's and my development BE are
identical in index/relation naming (I have ensured at each step that the
table structures are functionally identical, but not the relation/index
names). To do so, the safest thing might be to write a patch that removes all
indexes/relations and re-creates them by name.

2. Do any future BE changes via a distributed patch instead of manually. For
example if I add a new table to the BE (it is, after all, still under
development) that requires relations to existing tables, create a patch that
copies the new table and creates the relation programmaticlly.

As I noted before, I never really anticipated having to deal with version
control issues.. Am I missing anything fundamental here?


I would create a "template" backend mdb that is used for all
new clients. Then I would try to find a way to import the
two existing client's data into copies of that new backend
and send that back to them. This way you are sure that
initially, everyone has the same table/index/relation
structure.

For the future, make ***all*** changes to the backend design
using a version update program. I mean that you can only
make design changes programatically, you are not allowed to
open the backend for design changes - period. If you also
do this for your test data backend, you should be testing
the effects of the update program pretty thoroughly as you
perform normal testing.

You probably can export a new table to the clients data mdb,
but I generally use SQL DDL statements in VBA (or in an SQL
scripts table) to create new tables, fields, indexes, and
relations and then copy a table's data using an append
query.

Once you have tested the updated template mdb, you can
distribute the update program to existing customers,
probably as part of a front end version change.
 
Marshal, you haven't shown your declarations, which
was part of my problem.

The other part of my problem was that I wanted to
pass the object to a subroutine. I had trouble there
as well:

http://groups.google.com.au/group/m...ead/thread/f94deae1749653f5/63909979fdf8f194?


Reviewing the code (which is no longer in use) I see
in the end I was reducing everything to string values
for string comparison anyway, and I only needed to
parse the string if the index had changed.

(david)


Marshall Barton said:
David,

I think there was something funny going on with your A2K
experience. There was enough funny things in A2K so this
may have been just one more in a long list.

Give this kind of thing a try:

For Each idx In tdf.Indexes
Debug.Print idx.Name
Debug.PrintSpc(3); idx.Fields
For Each fld In idx.Fields
Debug.Print Spc(6); fld.Name
Next fld
For k = 0 To idx.Fields.Count - 1
Debug.Print Spc(9); idx.Fields(k).Name
Next k
Next idx

and you should see that, at least in my experience with A97,
AXP and A03, the Fields property behaves as both a string
and a collection.
--
Marsh
MVP [MS Access]

Everything I've said here is based only on my personal
experience with Jet 3.51 in year 2000. At that time
I couldn't get a fields collection - the indexfields
type was a string, not a collection.

I would use a fields collection by preference.
 
Ahh Yes, that thread is enlightening. I see that you did
sort out the misunderstanding in the end.

Regardless of that, Brian should not have to parse the
string returned by Fields, so I think he's OK too.
--
Marsh
MVP [MS Access]


Marshal, you haven't shown your declarations, which
was part of my problem.

The other part of my problem was that I wanted to
pass the object to a subroutine. I had trouble there
as well:

http://groups.google.com.au/group/m...ead/thread/f94deae1749653f5/63909979fdf8f194?


Reviewing the code (which is no longer in use) I see
in the end I was reducing everything to string values
for string comparison anyway, and I only needed to
parse the string if the index had changed.

(david)


Marshall Barton said:
David,

I think there was something funny going on with your A2K
experience. There was enough funny things in A2K so this
may have been just one more in a long list.

Give this kind of thing a try:

For Each idx In tdf.Indexes
Debug.Print idx.Name
Debug.PrintSpc(3); idx.Fields
For Each fld In idx.Fields
Debug.Print Spc(6); fld.Name
Next fld
For k = 0 To idx.Fields.Count - 1
Debug.Print Spc(9); idx.Fields(k).Name
Next k
Next idx

and you should see that, at least in my experience with A97,
AXP and A03, the Fields property behaves as both a string
and a collection.
--
Marsh
MVP [MS Access]

Be careful of the Fields property. If used by itself, it is
a somewhat unusual string. If used as a collection, it

Everything I've said here is based only on my personal
experience with Jet 3.51 in year 2000. At that time
I couldn't get a fields collection - the indexfields
type was a string, not a collection.

I would use a fields collection by preference.


You can ***not*** rely on any consistency in automatically
created names!

Be careful of the Fields property. If used by itself, it is
a somewhat unusual string. If used as a collection, it
behaves as you would expect.

I agree that it may be cumbersome, but to do what you want
for a table's Indexes, search through the Fields collection
of each Index for the specific field names. Once you've
identified the proper index, you can do other things with it
(e.g. delete method, name property, etc).

The same kind of approach can be used for relations, except
for the serious complication that when you create a
relation, Access automatically creates a hidden index for
the foreign key in the many side table (even if it
duplicates a manually created index). You can not delete
these internally created indexes unless you delete the
relation. These internal indexes are members of the table's
Indexes collection and you will stumble over them while
iterating through the indexes collection even though they do
not appear in the table's design view index window.
Although I have no proof, I think the internally created
indexes can be identified because their Foreign property is
is set to True.

Obviously, after all this discussion, it behooves you to
never again fiddle with a deployed back end database's
structure. It requires very deliberate thought and a
deployment strategy before a change should be made.
 
Back
Top